From cf4357ed386e42384eb858aa1b8118a36823857f Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sun, 6 Apr 2025 19:31:59 +0200 Subject: [PATCH] Gui: Fix handling - character in OVP --- src/Gui/EditableDatumLabel.cpp | 22 ++++++++--- src/Gui/QuantitySpinBox.cpp | 37 +++++++++++++++++-- src/Gui/QuantitySpinBox.h | 11 ++++++ .../AttachmentEditor/TaskAttachmentEditor.py | 1 - 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/Gui/EditableDatumLabel.cpp b/src/Gui/EditableDatumLabel.cpp index 723a16ab5f..cfc8d3902b 100644 --- a/src/Gui/EditableDatumLabel.cpp +++ b/src/Gui/EditableDatumLabel.cpp @@ -156,8 +156,10 @@ void EditableDatumLabel::startEdit(double val, QObject* eventFilteringObj, bool spinBox->setMinimum(-std::numeric_limits::max()); spinBox->setMaximum(std::numeric_limits::max()); spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); - spinBox->setKeyboardTracking(false); spinBox->setFocusPolicy(Qt::ClickFocus); // prevent passing focus with tab. + spinBox->setAutoNormalize(false); + spinBox->setKeyboardTracking(false); + if (eventFilteringObj) { spinBox->installEventFilter(eventFilteringObj); } @@ -172,12 +174,20 @@ void EditableDatumLabel::startEdit(double val, QObject* eventFilteringObj, bool spinBox->adjustSize(); setFocusToSpinbox(); - connect(spinBox, qOverload(&QuantitySpinBox::valueChanged), - this, [this](double value) { - this->isSet = true; - this->value = value; + const auto validateAndFinish = [this]() { + // this event can be fired after spinBox was already disposed + // in such case we need to skip processing that event + if (!spinBox) { + return; + } + + isSet = true; + value = spinBox->rawValue(); + Q_EMIT this->valueChanged(value); - }); + }; + + connect(spinBox, qOverload(&QuantitySpinBox::valueChanged), this, validateAndFinish); } void EditableDatumLabel::stopEdit() diff --git a/src/Gui/QuantitySpinBox.cpp b/src/Gui/QuantitySpinBox.cpp index 2a1d79f885..59f88073bc 100644 --- a/src/Gui/QuantitySpinBox.cpp +++ b/src/Gui/QuantitySpinBox.cpp @@ -66,6 +66,7 @@ public: QuantitySpinBoxPrivate(QuantitySpinBox *q) : validInput(true), pendingEmit(false), + normalize(true), checkRangeInExpression(false), unitValue(0), maximum(std::numeric_limits::max()), @@ -255,6 +256,7 @@ public: QLocale locale; bool validInput; bool pendingEmit; + bool normalize; bool checkRangeInExpression; QString validStr; Base::Quantity quantity; @@ -401,9 +403,11 @@ void QuantitySpinBox::resizeEvent(QResizeEvent * event) void Gui::QuantitySpinBox::keyPressEvent(QKeyEvent* event) { + Q_D(QuantitySpinBox); + const auto isEnter = event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return; - if (isEnter && !isNormalized()) { + if (d->normalize && isEnter && !isNormalized()) { normalize(); return; } @@ -411,6 +415,10 @@ void Gui::QuantitySpinBox::keyPressEvent(QKeyEvent* event) if (!handleKeyEvent(event->text())) { QAbstractSpinBox::keyPressEvent(event); } + + if (isEnter) { + returnPressed(); + } } void Gui::QuantitySpinBox::paintEvent(QPaintEvent*) @@ -494,7 +502,13 @@ bool QuantitySpinBox::isNormalized() QRegularExpression::CaseInsensitiveOption); Q_D(const QuantitySpinBox); - return !d->validStr.contains(operators); + + // this check is two level + // 1. We consider every string that does not contain operators as normalized + // 2. If it does contain operators we check if it differs from normalized input - as some + // operators like - can be allowed even in normalized case. + return !d->validStr.contains(operators) + || d->validStr.toStdString() == d->quantity.getUserString(); } void QuantitySpinBox::setValue(const Base::Quantity& value) @@ -523,6 +537,18 @@ void QuantitySpinBox::setValue(double value) setValue(quantity); } +bool QuantitySpinBox::autoNormalize() const +{ + Q_D(const QuantitySpinBox); + return d->normalize; +} + +void QuantitySpinBox::setAutoNormalize(bool normalize) +{ + Q_D(QuantitySpinBox); + d->normalize = normalize; +} + bool QuantitySpinBox::hasValidInput() const { Q_D(const QuantitySpinBox); @@ -903,8 +929,13 @@ void QuantitySpinBox::focusInEvent(QFocusEvent * event) void QuantitySpinBox::focusOutEvent(QFocusEvent * event) { + Q_D(const QuantitySpinBox); + validateInput(); - normalize(); + + if (d->normalize) { + normalize(); + } QToolTip::hideText(); QAbstractSpinBox::focusOutEvent(event); diff --git a/src/Gui/QuantitySpinBox.h b/src/Gui/QuantitySpinBox.h index 7c17216436..e2bd498920 100644 --- a/src/Gui/QuantitySpinBox.h +++ b/src/Gui/QuantitySpinBox.h @@ -46,6 +46,7 @@ class GuiExport QuantitySpinBox : public QAbstractSpinBox, public ExpressionSpin Q_PROPERTY(Base::Quantity value READ value WRITE setValue NOTIFY valueChanged USER true) Q_PROPERTY(QString binding READ boundToName WRITE setBoundToByName) // clazy:exclude=qproperty-without-notify Q_PROPERTY(QString expression READ expressionText) // clazy:exclude=qproperty-without-notify + Q_PROPERTY(bool autoNormalize READ autoNormalize WRITE setAutoNormalize) // clazy:exclude=qproperty-without-notify public: explicit QuantitySpinBox(QWidget *parent = nullptr); @@ -96,6 +97,11 @@ public: /// Sets the number of decimals void setDecimals(int v); + /// Checks if auto normalization is enabled + bool autoNormalize() const; + /// Enables or disables automatic normalization on enter + void setAutoNormalize(bool normalize); + /// Sets a specific unit schema to handle quantities. /// The system-wide schema won't be used any more. void setSchema(int s); @@ -189,6 +195,11 @@ Q_SIGNALS: * or finished (false). */ void showFormulaDialog(bool); + /** Gets emitted if user confirms the value with return. This + * is very similar to editingFinished() but does not fire on + * focus out. + */ + void returnPressed(); private: QScopedPointer d_ptr; diff --git a/src/Mod/Part/AttachmentEditor/TaskAttachmentEditor.py b/src/Mod/Part/AttachmentEditor/TaskAttachmentEditor.py index fbcb6f4fd8..2ee48895dd 100644 --- a/src/Mod/Part/AttachmentEditor/TaskAttachmentEditor.py +++ b/src/Mod/Part/AttachmentEditor/TaskAttachmentEditor.py @@ -387,7 +387,6 @@ class AttachmentEditorTaskPanel(FrozenClass): pos.z = Q(self.form.attachmentOffsetZ.text()).getValueAs(mm) if index >= 0 and index <= 2: plm.Base = pos - if index >= 3 and index <= 5: yaw = Q(self.form.attachmentOffsetYaw.text()).getValueAs(deg) pitch = Q(self.form.attachmentOffsetPitch.text()).getValueAs(deg)