summaryrefslogtreecommitdiffstats
path: root/src/runtime
diff options
context:
space:
mode:
authorJere Tuliniemi <jere.tuliniemi@qt.io>2019-08-20 13:21:36 +0300
committerJere Tuliniemi <jere.tuliniemi@qt.io>2019-08-21 10:58:28 +0300
commit7ad7a0b0cf6731c0e0435ce0574219469890d568 (patch)
tree4e5d4ca09ddf2e972e661d3c37cccabbabd7ff2e /src/runtime
parent8927387cca9fd149c7cae7c93972f5b635d8350a (diff)
Fix component activation resetting user inputs
QT3DS-3778 is fixed by not rollbacking and executing the slide again when activated after deactivation. Thus, the component continues from the previous state. QT3DS-3767 is partly fixed by the same change, but attributes set prior to the first activation of the component are lost. This is fixed by storing the attribute changes and applying them after the first activation. Task-number: QT3DS-3778 Task-number: QT3DS-3767 Change-Id: I3917e66b56dd40a2804d6d74db38b2e21132187e Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/Qt3DSActivationManager.cpp7
-rw-r--r--src/runtime/Qt3DSComponentManager.cpp29
-rw-r--r--src/runtime/Qt3DSComponentManager.h5
-rw-r--r--src/runtime/Qt3DSIComponentManager.h3
-rw-r--r--src/runtime/Qt3DSQmlElementHelper.cpp147
-rw-r--r--src/runtime/Qt3DSQmlElementHelper.h9
-rw-r--r--src/runtime/Qt3DSQmlEngine.cpp43
7 files changed, 174 insertions, 69 deletions
diff --git a/src/runtime/Qt3DSActivationManager.cpp b/src/runtime/Qt3DSActivationManager.cpp
index 1449f6e..a976032 100644
--- a/src/runtime/Qt3DSActivationManager.cpp
+++ b/src/runtime/Qt3DSActivationManager.cpp
@@ -644,7 +644,12 @@ struct STimeContext
m_AllNodesDirty = true;
if (isActive) {
Mutex::ScopedLock __locker(m_ElementAccessMutex);
- inComponentManager.GotoSlideIndex(&theContextNode, 1, false);
+ // When the component is activated the first time go to the first slide
+ // Subsequent activations should continue from the deactivated slide
+ if (theContextNode.GetCurrentSlide() == 0) {
+ inComponentManager.GotoSlideIndex(&theContextNode, 1, false);
+ inComponentManager.applyQueuedChanges(&theContextNode);
+ }
} else
RemoveOverride();
}
diff --git a/src/runtime/Qt3DSComponentManager.cpp b/src/runtime/Qt3DSComponentManager.cpp
index d7ce0b6..184576f 100644
--- a/src/runtime/Qt3DSComponentManager.cpp
+++ b/src/runtime/Qt3DSComponentManager.cpp
@@ -41,6 +41,7 @@
#include "Qt3DSApplication.h"
#include "Qt3DSActivationManager.h"
#include "Qt3DSPresentation.h"
+#include "Qt3DSQmlElementHelper.h"
using qt3ds::runtime::SSlideKey;
//==============================================================================
@@ -311,6 +312,34 @@ void CComponentManager::PlaythroughToSlide(TElement *inComponent)
}
}
+void CComponentManager::applyQueuedChanges(TElement *component)
+{
+ const auto &targetQueue = m_queuedChanges[component];
+ for (auto itTarget = targetQueue.constBegin(); itTarget != targetQueue.constEnd();
+ ++itTarget) {
+ const auto &target = itTarget.key();
+ const auto &attributeQueue = itTarget.value();
+ for (auto itAttribute = attributeQueue.constBegin();
+ itAttribute != attributeQueue.constEnd(); ++itAttribute) {
+ const auto &attribute = itAttribute.key();
+ target->SetAttribute(attribute, itAttribute.value());
+ }
+ }
+ m_queuedChanges.remove(component);
+}
+
+void CComponentManager::queueChange(TElement *component, TElement *target, const char *attName,
+ const char *value)
+{
+ CQmlElementHelper::TypedAttributeAndValue attributeAndValue
+ = CQmlElementHelper::getTypedAttributeAndValue(target, attName, value);
+ if (attributeAndValue.attribute.m_Hash != 0) {
+ auto &targetQueue = m_queuedChanges[component];
+ auto &attQueue = targetQueue[target];
+ attQueue[attributeAndValue.attribute.m_Hash] = attributeAndValue.value;
+ }
+}
+
//==============================================================================
/**
* Performs a switch to the previous slide.
diff --git a/src/runtime/Qt3DSComponentManager.h b/src/runtime/Qt3DSComponentManager.h
index 865b8aa..108640b 100644
--- a/src/runtime/Qt3DSComponentManager.h
+++ b/src/runtime/Qt3DSComponentManager.h
@@ -91,6 +91,9 @@ public: // Slide
void GoToNextSlide(TElement *inComponent, const INT32 inDecrement = 1) override;
void GoToPreviousSlide(TElement *inComponent, const INT32 inDecrement = 1) override;
void PlaythroughToSlide(TElement *inComponent);
+ void applyQueuedChanges(TElement *component) override;
+ void queueChange(TElement *component, TElement *target, const char *attName,
+ const char *value) override;
UINT8 GetSlideCount(TElement *inComponent) override;
UINT8 GetCurrentSlide(TElement *inComponent) override;
@@ -134,6 +137,8 @@ private:
TComponentGotoSlideDataMap m_ComponentGotoSlideMap;
TComponentIntMap m_PlaythroughOverrideMap;
+ QHash<TElement *, QHash<TElement *, QHash<TAttributeHash, UVariant>>> m_queuedChanges;
+
//==============================================================================
// Friends
//==============================================================================
diff --git a/src/runtime/Qt3DSIComponentManager.h b/src/runtime/Qt3DSIComponentManager.h
index 8185da2..be94f7e 100644
--- a/src/runtime/Qt3DSIComponentManager.h
+++ b/src/runtime/Qt3DSIComponentManager.h
@@ -120,6 +120,9 @@ public: // Slides
virtual UINT8 GetSlideCount(TElement *inComponent) = 0;
virtual UINT8 GetCurrentSlide(TElement *inComponent) = 0;
virtual const CHAR *GetCurrentSlideName(TElement *inComponent) = 0;
+ virtual void applyQueuedChanges(TElement *component) = 0;
+ virtual void queueChange(TElement *component, TElement *target, const char *attName,
+ const char *value) = 0;
virtual void OnElementDeactivated(TElement *inElement) = 0;
diff --git a/src/runtime/Qt3DSQmlElementHelper.cpp b/src/runtime/Qt3DSQmlElementHelper.cpp
index 5518a38..bf414a0 100644
--- a/src/runtime/Qt3DSQmlElementHelper.cpp
+++ b/src/runtime/Qt3DSQmlElementHelper.cpp
@@ -151,58 +151,37 @@ TElement *CQmlElementHelper::GetElement(qt3ds::runtime::IApplication &inApplicat
return theElement;
}
-bool CQmlElementHelper::SetAttribute(TElement *theElement, const char *theAttName,
- const void *value)
+CQmlElementHelper::TypedAttributeAndValue CQmlElementHelper::getTypedAttributeAndValue(
+ TElement *theElement, const char *theAttName, const void *value)
{
+ TypedAttributeAndValue retVal = { SAttributeKey(), UVariant() };
+ retVal.attribute.m_Hash = 0;
+
SAttributeKey theAttributeKey;
theAttributeKey.m_Hash = CHash::HashAttribute(theAttName);
- bool force = false;
-
- // Fail if trying to change the activation state of an object in another slide
- if (theAttributeKey.m_Hash == Q3DStudio::ATTRIBUTE_EYEBALL) {
- CPresentation *presentation = static_cast<CPresentation *>(
- theElement->GetBelongedPresentation());
- ISlideSystem &slideSystem = presentation->GetSlideSystem();
- TElement *componentElement = theElement->GetActivityZone().GetItemTimeParent(*theElement);
- TComponent *component = presentation->GetComponentManager().GetComponent(componentElement);
- if (!slideSystem.isElementInSlide(*theElement, *componentElement,
- component->GetCurrentSlide())) {
- return false;
- }
- }
// Early out for our single 'read only' attribute
if (ATTRIBUTE_URI == theAttributeKey.m_Hash) {
- // we didn't push anything onto the stack
- return false;
+ // we didn't push anything onto the stack
+ return retVal;
}
// first search if it is a static property
- Option<qt3ds::runtime::element::TPropertyDescAndValuePtr> thePropertyInfo =
- theElement->FindProperty(theAttributeKey.m_Hash);
+ Option<qt3ds::runtime::element::TPropertyDescAndValuePtr> thePropertyInfo
+ = theElement->FindProperty(theAttributeKey.m_Hash);
- // Do not create property for eyeball, it uses the explicit activity flag
if (!thePropertyInfo.hasValue() && theAttributeKey.m_Hash != Q3DStudio::ATTRIBUTE_EYEBALL) {
// if not search in the dynamic properties
thePropertyInfo = theElement->FindDynamicProperty(theAttributeKey.m_Hash);
- if (!thePropertyInfo.hasValue()) {
- // create a new dynamic porperty
- qt3ds::runtime::IElementAllocator &theElemAllocator(
- theElement->GetBelongedPresentation()->GetApplication().GetElementAllocator());
- qt3ds::foundation::IStringTable &theStringTable(
- theElement->GetBelongedPresentation()->GetStringTable());
- IRuntimeMetaData &theMetaData =
- theElement->GetBelongedPresentation()->GetApplication().GetMetaData();
- thePropertyInfo = theElemAllocator.CreateDynamicProperty(
- theMetaData, *theElement, theStringTable.RegisterStr(theAttName));
- force = true;
- }
+ if (!thePropertyInfo.hasValue())
+ return retVal;
}
if (theAttributeKey.m_Hash == Q3DStudio::ATTRIBUTE_EYEBALL) {
UVariant theNewValue;
theNewValue.m_INT32 = *(INT32 *)value;
- theElement->SetAttribute(theAttributeKey.m_Hash, theNewValue);
+ retVal.attribute = theAttributeKey;
+ retVal.value = theNewValue;
} else if (thePropertyInfo.hasValue()) {
UVariant theNewValue;
QString name(thePropertyInfo->first.m_Name.c_str());
@@ -212,59 +191,115 @@ bool CQmlElementHelper::SetAttribute(TElement *theElement, const char *theAttNam
case ATTRIBUTETYPE_HASH:
theNewValue.m_INT32 = *(INT32 *)value;
break;
-
case ATTRIBUTETYPE_FLOAT:
theNewValue.m_FLOAT = *(FLOAT *)value;
if (name.startsWith(QLatin1String("rotation.")))
theNewValue.m_FLOAT = qDegreesToRadians(theNewValue.m_FLOAT);
break;
-
case ATTRIBUTETYPE_BOOL:
theNewValue.m_INT32 = *(INT32 *)value;
break;
-
case ATTRIBUTETYPE_STRING:
- theNewValue.m_StringHandle =
- theElement->GetBelongedPresentation()->GetStringTable().getDynamicHandle(
+ theNewValue.m_StringHandle
+ = theElement->GetBelongedPresentation()->GetStringTable().getDynamicHandle(
QByteArray(static_cast<const char *>(value)));
break;
-
case ATTRIBUTETYPE_POINTER:
- qCCritical(INVALID_OPERATION, "setAttribute: pointer attributes not handled.");
- return false;
- break;
-
+ qCCritical(INVALID_OPERATION, "getTypedAttributeAndValue: "
+ "pointer attributes not handled.");
+ return retVal;
case ATTRIBUTETYPE_ELEMENTREF:
- qCCritical(INVALID_OPERATION, "setAttribute: ElementRef attributes are read only.");
- return false;
- break;
-
+ qCCritical(INVALID_OPERATION, "getTypedAttributeAndValue: "
+ "ElementRef attributes are read only.");
+ return retVal;
case ATTRIBUTETYPE_FLOAT3: {
FLOAT *vec3 = (FLOAT *)value;
theNewValue.m_FLOAT3[0] = vec3[0];
theNewValue.m_FLOAT3[1] = vec3[1];
theNewValue.m_FLOAT3[2] = vec3[2];
if (name == QLatin1String("rotation")) {
- theNewValue.m_FLOAT3[0]= qDegreesToRadians(theNewValue.m_FLOAT3[0]);
- theNewValue.m_FLOAT3[1]= qDegreesToRadians(theNewValue.m_FLOAT3[1]);
- theNewValue.m_FLOAT3[2]= qDegreesToRadians(theNewValue.m_FLOAT3[2]);
+ theNewValue.m_FLOAT3[0] = qDegreesToRadians(theNewValue.m_FLOAT3[0]);
+ theNewValue.m_FLOAT3[1] = qDegreesToRadians(theNewValue.m_FLOAT3[1]);
+ theNewValue.m_FLOAT3[2] = qDegreesToRadians(theNewValue.m_FLOAT3[2]);
}
} break;
-
case ATTRIBUTETYPE_NONE:
case ATTRIBUTETYPE_DATADRIVEN_PARENT:
case ATTRIBUTETYPE_DATADRIVEN_CHILD:
case ATTRIBUTETYPECOUNT:
default:
- qCCritical(INVALID_OPERATION, "setAttribute: Attribute has no type!");
+ qCCritical(INVALID_OPERATION, "getTypedAttributeAndValue: Attribute has no type!");
+ return retVal;
+ }
+
+ retVal.attribute = theAttributeKey;
+ retVal.value = theNewValue;
+ }
+
+ return retVal;
+}
+
+bool CQmlElementHelper::SetAttribute(TElement *theElement, const char *theAttName,
+ const void *value)
+{
+ SAttributeKey theAttributeKey;
+ theAttributeKey.m_Hash = CHash::HashAttribute(theAttName);
+ bool force = false;
+
+ // Fail if trying to change the activation state of an object in another slide
+ if (theAttributeKey.m_Hash == Q3DStudio::ATTRIBUTE_EYEBALL) {
+ CPresentation *presentation = static_cast<CPresentation *>(
+ theElement->GetBelongedPresentation());
+ ISlideSystem &slideSystem = presentation->GetSlideSystem();
+ TElement *componentElement = theElement->GetActivityZone().GetItemTimeParent(*theElement);
+ TComponent *component = presentation->GetComponentManager().GetComponent(componentElement);
+ if (!slideSystem.isElementInSlide(*theElement, *componentElement,
+ component->GetCurrentSlide())) {
return false;
- break;
}
+ }
- theElement->SetAttribute(*thePropertyInfo, theNewValue, force);
- } else {
+ // Early out for our single 'read only' attribute
+ if (ATTRIBUTE_URI == theAttributeKey.m_Hash) {
+ // we didn't push anything onto the stack
return false;
}
+
+ // first search if it is a static property
+ Option<qt3ds::runtime::element::TPropertyDescAndValuePtr> thePropertyInfo =
+ theElement->FindProperty(theAttributeKey.m_Hash);
+
+ // Do not create property for eyeball, it uses the explicit activity flag
+ if (!thePropertyInfo.hasValue() && theAttributeKey.m_Hash != Q3DStudio::ATTRIBUTE_EYEBALL) {
+ // if not search in the dynamic properties
+ thePropertyInfo = theElement->FindDynamicProperty(theAttributeKey.m_Hash);
+ if (!thePropertyInfo.hasValue()) {
+ // create a new dynamic porperty
+ qt3ds::runtime::IElementAllocator &theElemAllocator(
+ theElement->GetBelongedPresentation()->GetApplication().GetElementAllocator());
+ qt3ds::foundation::IStringTable &theStringTable(
+ theElement->GetBelongedPresentation()->GetStringTable());
+ IRuntimeMetaData &theMetaData =
+ theElement->GetBelongedPresentation()->GetApplication().GetMetaData();
+ thePropertyInfo = theElemAllocator.CreateDynamicProperty(
+ theMetaData, *theElement, theStringTable.RegisterStr(theAttName));
+ force = true;
+ }
+ }
+
+ TypedAttributeAndValue attributeAndValue = getTypedAttributeAndValue(theElement, theAttName,
+ value);
+
+ if (attributeAndValue.attribute.m_Hash == 0)
+ return false;
+
+ if (attributeAndValue.attribute.m_Hash == Q3DStudio::ATTRIBUTE_EYEBALL)
+ theElement->SetAttribute(attributeAndValue.attribute.m_Hash, attributeAndValue.value);
+ else if (thePropertyInfo.hasValue())
+ theElement->SetAttribute(thePropertyInfo, attributeAndValue.value, force);
+ else
+ return false;
+
return true;
}
diff --git a/src/runtime/Qt3DSQmlElementHelper.h b/src/runtime/Qt3DSQmlElementHelper.h
index c7b2b08..f516571 100644
--- a/src/runtime/Qt3DSQmlElementHelper.h
+++ b/src/runtime/Qt3DSQmlElementHelper.h
@@ -50,6 +50,15 @@ public:
static bool SetAttribute(TElement *inElement, const char *inAttribute, const void *value);
static bool GetAttribute(TElement *inElement, const char *inAttribute, void *value);
+
+ struct TypedAttributeAndValue {
+ SAttributeKey attribute;
+ UVariant value;
+ };
+
+ static TypedAttributeAndValue getTypedAttributeAndValue(TElement *inElement,
+ const char *inAttribute,
+ const void *value);
};
}
diff --git a/src/runtime/Qt3DSQmlEngine.cpp b/src/runtime/Qt3DSQmlEngine.cpp
index 40a4af6..3ef4b11 100644
--- a/src/runtime/Qt3DSQmlEngine.cpp
+++ b/src/runtime/Qt3DSQmlEngine.cpp
@@ -604,16 +604,33 @@ void CQmlEngineImpl::Initialize()
}
}
+bool queueAttributeChange(TElement *target, const char *attName, const char *value)
+{
+ TElement *componentElement = target->GetActivityZone().GetItemTimeParent(*target);
+ TComponent *component = static_cast<TComponent *>(componentElement);
+ // Queue changes to elements inside components that have not been activated even once
+ if (component->GetCurrentSlide() == 0) {
+ IPresentation *presentation = target->GetBelongedPresentation();
+ presentation->GetComponentManager().queueChange(componentElement, target,
+ attName, value);
+ return true;
+ }
+ return false;
+}
+
void CQmlEngineImpl::SetAttribute(TElement *target, const char *attName, const char *value)
{
QML_ENGINE_MULTITHREAD_PROTECT_METHOD;
+
if (target) {
- bool success = CQmlElementHelper::SetAttribute(target, attName, value);
- if (!success) {
- qCCritical(qt3ds::INVALID_OPERATION)
- << "CQmlEngineImpl::SetAttribute: "
- << "failed to set attribute on element"
- << target << ":" << attName << ":" << value;
+ if (!queueAttributeChange(target, attName, value)) {
+ bool success = CQmlElementHelper::SetAttribute(target, attName, value);
+ if (!success) {
+ qCCritical(qt3ds::INVALID_OPERATION)
+ << "CQmlEngineImpl::SetAttribute: "
+ << "failed to set attribute on element"
+ << target->m_Path.c_str() << ":" << attName << ":" << value;
+ }
}
}
}
@@ -624,12 +641,14 @@ void CQmlEngineImpl::SetAttribute(const char *element, const char *attName, cons
TElement *theTarget = getTarget(element);
if (theTarget) {
- bool success = CQmlElementHelper::SetAttribute(theTarget, attName, value);
- if (!success) {
- qCCritical(qt3ds::INVALID_OPERATION)
- << "CQmlEngineImpl::SetAttribute: "
- << "failed to set attribute on element"
- << element << ":" << attName << ":" << value;
+ if (!queueAttributeChange(theTarget, attName, value)) {
+ bool success = CQmlElementHelper::SetAttribute(theTarget, attName, value);
+ if (!success) {
+ qCCritical(qt3ds::INVALID_OPERATION)
+ << "CQmlEngineImpl::SetAttribute: "
+ << "failed to set attribute on element"
+ << element << ":" << attName << ":" << value;
+ }
}
}
}