diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.cpp index 7552fb0b50..d7e6cb85cd 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.cpp @@ -43,7 +43,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) @@ -65,6 +65,22 @@ const QString& VectorElement::label() const void VectorElement::setValue(double newValue) { + // Nothing to do if the value is not actually changed + if (AZ::IsClose(m_value, newValue, std::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); @@ -72,6 +88,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_Warning("VectorElement", !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)); @@ -254,7 +287,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 8fb906a5cf..a9cd743830 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/VectorInput.h @@ -14,6 +14,7 @@ #if !defined(Q_MOC_RUN) #include #include +#include #endif class QLabel; @@ -23,6 +24,12 @@ namespace AzQtComponents class Style; + #pragma warning(push) + + // 'AzQtComponents::VectorElement::m_deferredExternalValue': class 'AZStd::optional' needs to + // have dll-interface to be used by clients of class 'AzQtComponents::VectorElement' + #pragma warning(disable:4251) + /*! * \class VectorElement * \brief All flexible vector GUI's are constructed using a number vector elements. Each Vector @@ -103,7 +110,14 @@ namespace AzQtComponents void resizeLabel(); + void onSpinBoxEditingFinished(); + private: + struct DeferredSetValue + { + double prevValue, 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 = {}; @@ -113,8 +127,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; }; + #pragma warning(pop) + ////////////////////////////////////////////////////////////////////////// /*!