diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.cpp index c140941bd0..e012a10ef0 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -38,7 +39,7 @@ VectorElement::VectorElement(QWidget* parent) VectorElement::layout(this, m_spinBox, m_label, false); connect(m_spinBox, QOverload::of(&AzQtComponents::DoubleSpinBox::valueChanged), this, &VectorElement::onValueChanged); - connect(m_spinBox, &AzQtComponents::DoubleSpinBox::editingFinished, this, &VectorElement::editingFinished); + connect(m_spinBox, &AzQtComponents::DoubleSpinBox::editingFinished, this, &VectorElement::onSpinBoxEditingFinished); } void VectorElement::SetLabel(const char* label) @@ -60,6 +61,22 @@ const QString& VectorElement::label() const void VectorElement::setValue(double newValue) { + // Nothing to do if the value is not actually changed + if (AZ::IsCloseMag(m_value, newValue, AZStd::numeric_limits::epsilon())) + { + return; + } + + // If the spin box currently has focus, the user is editing it, so we should not + // change the value from non-user input while they're in the middle of editing + if (m_spinBox->hasFocus()) + { + auto& deferredValue = m_deferredExternalValue.emplace(); + deferredValue.value = newValue; + deferredValue.prevValue = m_value; + return; + } + m_value = newValue; const QSignalBlocker blocker(m_spinBox); m_spinBox->setValue(newValue); @@ -67,6 +84,23 @@ void VectorElement::setValue(double newValue) emit valueChanged(newValue); } +void VectorElement::onSpinBoxEditingFinished() +{ + if (m_deferredExternalValue) + { + DeferredSetValue deferredValue = *m_deferredExternalValue; + m_deferredExternalValue.reset(); + + if (m_value == deferredValue.prevValue) + { + AZ_Assert(!m_spinBox->hasFocus(), "Editing finished but the spinbox still has focus"); + setValue(deferredValue.value); + } + } + + emit editingFinished(); +} + void VectorElement::setCoordinate(VectorElement::Coordinate coordinate) { setProperty(g_CoordinatePropertyName, QVariant::fromValue(coordinate)); @@ -249,7 +283,7 @@ VectorInput::VectorInput(QWidget* parent, int elementCount, int elementsPerRow, { OnValueChangedInElement(value, elementIndex); }); - connect(m_elements[elementIndex]->GetSpinBox(), &AzQtComponents::DoubleSpinBox::editingFinished, this, &VectorInput::editingFinished); + connect(m_elements[elementIndex], &VectorElement::editingFinished, this, &VectorInput::editingFinished); numberOfElementsRemaining--; } diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.h index 44caa59e49..17eacea8dd 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.h @@ -9,6 +9,7 @@ #if !defined(Q_MOC_RUN) #include #include +#include #endif class QLabel; @@ -18,6 +19,10 @@ namespace AzQtComponents class Style; + // 'AzQtComponents::VectorElement::m_deferredExternalValue': class 'AZStd::optional' needs to + // have dll-interface to be used by clients of class 'AzQtComponents::VectorElement' + AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING + /*! * \class VectorElement * \brief All flexible vector GUI's are constructed using a number vector elements. Each Vector @@ -98,7 +103,15 @@ namespace AzQtComponents void resizeLabel(); + void onSpinBoxEditingFinished(); + private: + struct DeferredSetValue + { + double prevValue; + double value; + }; + // m_labelText must be initialised before m_spinBox. It is used by editFieldRect, which gets // called by the spin box constructor. QString m_labelText = {}; @@ -108,8 +121,13 @@ namespace AzQtComponents double m_value = 0.0; //! Indicates whether the value in the spin box has been edited by the user or not bool m_wasValueEditedByUser = false; + //! If a value is editing, but not by the user, and the user is currently editing the value, + //! avoid overwriting their work, until they finish editing + AZStd::optional m_deferredExternalValue; }; + AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING + ////////////////////////////////////////////////////////////////////////// /*!