From ef0b2590973e31a38d01a7e225a8f8b87185d9f2 Mon Sep 17 00:00:00 2001 From: tetektoza Date: Wed, 11 Jun 2025 23:59:07 +0200 Subject: [PATCH] Sketcher: Change enter behavior on OVP to put OVP in lock state only This patch adds/changes a couple of things: * if you press enter on a label now, it moves you to another label and adds the label and lock on the previous label, instead of previous behavior where it was accepting whole dimension * if you press enter and have lock state on both labels then you move to next stage * if you press ctrl+enter it's as is if you'd press enter on both labels (the object becomes constrained with whatever dimensions that were in both labels) * tab still works the same way * you can remove "Lock" state from the label by typing something additional or removing the dimension at all --- src/Gui/EditableDatumLabel.cpp | 114 +++++++++++++++++- src/Gui/EditableDatumLabel.h | 5 + src/Mod/Sketcher/Gui/DrawSketchController.h | 32 +++++ src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h | 4 +- .../Sketcher/Gui/DrawSketchHandlerArcSlot.h | 2 +- .../Sketcher/Gui/DrawSketchHandlerBSpline.h | 2 +- .../Sketcher/Gui/DrawSketchHandlerCircle.h | 2 +- .../Sketcher/Gui/DrawSketchHandlerEllipse.h | 4 +- src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h | 2 +- src/Mod/Sketcher/Gui/DrawSketchHandlerPoint.h | 2 +- .../Sketcher/Gui/DrawSketchHandlerPolygon.h | 2 +- .../Sketcher/Gui/DrawSketchHandlerRectangle.h | 4 +- src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h | 2 +- .../Sketcher/Gui/DrawSketchHandlerTranslate.h | 4 +- 14 files changed, 163 insertions(+), 18 deletions(-) diff --git a/src/Gui/EditableDatumLabel.cpp b/src/Gui/EditableDatumLabel.cpp index f863b76ab0..c31562a6a1 100644 --- a/src/Gui/EditableDatumLabel.cpp +++ b/src/Gui/EditableDatumLabel.cpp @@ -33,8 +33,13 @@ #include #include +#include +#include +#include +#include #include +#include #include #include @@ -62,6 +67,7 @@ EditableDatumLabel::EditableDatumLabel(View3DInventorViewer* view, , value(0.0) , viewer(view) , spinBox(nullptr) + , lockIconLabel(nullptr) , cameraSensor(nullptr) , function(Function::Positioning) { @@ -151,6 +157,9 @@ void EditableDatumLabel::startEdit(double val, QObject* eventFilteringObj, bool return; } + // Reset locked state when starting to edit + this->resetLockedState(); + QWidget* mdi = viewer->parentWidget(); label->string = " "; @@ -209,11 +218,30 @@ bool EditableDatumLabel::eventFilter(QObject* watched, QEvent* event) if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { if (auto* spinBox = qobject_cast(watched)) { - this->hasFinishedEditing = true; - Q_EMIT this->valueChanged(this->value); - return false; + // for ctrl + enter we accept values as they are + if (keyEvent->modifiers() & Qt::ControlModifier) { + Q_EMIT this->finishEditingOnAllOVPs(); + return true; + } + else { + // regular enter + this->hasFinishedEditing = true; + Q_EMIT this->spinBox->valueChanged(this->value); + + // only set lock state if it passed validation + // (validation can unset isSet if value didn't pass + // confusion point for example) + if (this->isSet) + this->setLockedAppearance(true); + return true; + } } } + else if (this->hasFinishedEditing && keyEvent->key() != Qt::Key_Tab) + { + this->setLockedAppearance(false); + return false; + } } return QObject::eventFilter(watched, event); @@ -233,6 +261,9 @@ void EditableDatumLabel::stopEdit() spinBox->deleteLater(); spinBox = nullptr; + + // Lock icon will be automatically destroyed as it's a child of spinbox + lockIconLabel = nullptr; } } @@ -311,6 +342,19 @@ void EditableDatumLabel::positionSpinbox() pxCoord.setX(posX); pxCoord.setY(posY); spinBox->move(pxCoord); + + // Update lock icon position inside the spinbox if it exists and is visible + if (lockIconLabel && lockIconLabel->isVisible()) { + int iconSize = 14; + int padding = 4; + QSize spinboxSize = spinBox->size(); + lockIconLabel->setGeometry( + spinboxSize.width() - iconSize - padding, + (spinboxSize.height() - iconSize) / 2, + iconSize, + iconSize + ); + } } SbVec3f EditableDatumLabel::getTextCenterPoint() const @@ -441,6 +485,70 @@ void EditableDatumLabel::setSpinboxVisibleToMouse(bool val) spinBox->setAttribute(Qt::WA_TransparentForMouseEvents, !val); } +void EditableDatumLabel::setLockedAppearance(bool locked) +{ + if (locked) { + if (spinBox) { + QWidget* mdi = viewer->parentWidget(); + + // create lock icon label it it doesn't exist, if it does - show it + if (!lockIconLabel) { + lockIconLabel = new QLabel(spinBox); + lockIconLabel->setAttribute(Qt::WA_TransparentForMouseEvents, true); + lockIconLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + } + else + { + lockIconLabel->show(); + } + + // load icon and scale it to fit in spinbox + QPixmap lockIcon = Gui::BitmapFactory().pixmap("Constraint_Lock"); + QPixmap scaledIcon = lockIcon.scaled(14, 14, Qt::KeepAspectRatio, Qt::SmoothTransformation); + lockIconLabel->setPixmap(scaledIcon); + + // position lock icon inside the spinbox + int iconSize = 14; + int padding = 4; + QSize spinboxSize = spinBox->size(); + lockIconLabel->setGeometry( + spinboxSize.width() - iconSize - padding, + (spinboxSize.height() - iconSize) / 2, + iconSize, + iconSize + ); + lockIconLabel->show(); + + // style spinbox and add padding for lock + QString styleSheet = QString::fromLatin1( + "QSpinBox { " + "padding-right: %1px; " + "}" + ).arg(iconSize + padding + 2); + + spinBox->setStyleSheet(styleSheet); + } + } else { + this->hasFinishedEditing = false; + + // if spinbox exists, reset its appearance + if (spinBox) { + spinBox->setStyleSheet(QString()); + + // hide lock icon if it exists for later reuse + if (lockIconLabel) { + lockIconLabel->hide(); + } + } + } +} + +void EditableDatumLabel::resetLockedState() +{ + hasFinishedEditing = false; + setLockedAppearance(false); +} + EditableDatumLabel::Function EditableDatumLabel::getFunction() { return function; diff --git a/src/Gui/EditableDatumLabel.h b/src/Gui/EditableDatumLabel.h index 380532a681..6f6b1bb05c 100644 --- a/src/Gui/EditableDatumLabel.h +++ b/src/Gui/EditableDatumLabel.h @@ -72,6 +72,7 @@ public: void setPoints(SbVec3f p1, SbVec3f p2); void setPoints(Base::Vector3d p1, Base::Vector3d p2); void setFocusToSpinbox(); + void clearSelection(); ///< Clears text selection in the spinbox void setLabelType(SoDatumLabel::Type type, Function function = Function::Positioning); void setLabelDistance(double val); void setLabelStartAngle(double val); @@ -79,6 +80,8 @@ public: void setLabelRecommendedDistance(); void setLabelAutoDistanceReverse(bool val); void setSpinboxVisibleToMouse(bool val); + void setLockedAppearance(bool locked); ///< Sets visual appearance to indicate locked state (finished editing) + void resetLockedState(); ///< Resets both hasFinishedEditing flag and locked appearance Function getFunction(); @@ -95,6 +98,7 @@ public: Q_SIGNALS: void valueChanged(double val); void parameterUnset(); + void finishEditingOnAllOVPs(); ///< Emitted when Ctrl+Enter is pressed to finish editing on all visible OVPs protected: bool eventFilter(QObject* watched, QEvent* event) override; @@ -109,6 +113,7 @@ private: SoTransform* transform; QPointer viewer; QuantitySpinBox* spinBox; + QLabel* lockIconLabel; ///< Label to display lock icon next to spinbox SoNodeSensor* cameraSensor; SbVec3f midpos; diff --git a/src/Mod/Sketcher/Gui/DrawSketchController.h b/src/Mod/Sketcher/Gui/DrawSketchController.h index cf59ba0efb..bc75dee386 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchController.h +++ b/src/Mod/Sketcher/Gui/DrawSketchController.h @@ -365,8 +365,33 @@ public: } } + void finishEditingOnAllOVPs() + { + // we call this on a current OnViewParameter when pressed CTRL+ENTER to accept + // input on all visible ovps of current mode + + // we check for initial state, since `onViewValueChanged` can process to next mode + // if we set hasFinishedEditing on current mode + auto initialState = handler->state(); + for (size_t i = 0; i < onViewParameters.size(); i++) { + if (isOnViewParameterOfCurrentMode(i) && isOnViewParameterVisible(i) && initialState == getState(static_cast(i))) { + onViewParameters[i]->isSet = true; + onViewParameters[i]->hasFinishedEditing = true; + + double currentValue = onViewParameters[i]->getValue(); + onViewValueChanged(static_cast(i), currentValue); + } + } + } + void tryViewValueChanged(int onviewparameterindex, double value) { + // go only to next label if user has currently pressed enter on current one + int nextindex = onviewparameterindex + 1; + if (onViewParameters[onviewparameterindex]->hasFinishedEditing && isOnViewParameterOfCurrentMode(nextindex)) { + setFocusToOnViewParameter(nextindex); + } + /* That is not supported with on-view parameters. // -> A machine does not forward to a next state when adapting the parameter (though it // may forward to @@ -628,6 +653,13 @@ protected: unsetOnViewParameter(parameter); finishControlsChanged(); }); + + // Connect Ctrl+Enter signal to apply values to all visible OVPs in current stage + QObject::connect(parameter, + &Gui::EditableDatumLabel::finishEditingOnAllOVPs, + [this]() { + finishEditingOnAllOVPs(); + }); } } diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h index f33f3106e1..062c864d79 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h @@ -729,7 +729,7 @@ void DSHArcController::doChangeDrawSketchHandlerMode() auto& thirdParam = onViewParameters[OnViewParameter::Third]; auto& fourthParam = onViewParameters[OnViewParameter::Fourth]; - if (thirdParam->hasFinishedEditing || fourthParam->hasFinishedEditing) { + if (thirdParam->hasFinishedEditing && fourthParam->hasFinishedEditing) { handler->setState(SelectMode::SeekThird); } } break; @@ -743,7 +743,7 @@ void DSHArcController::doChangeDrawSketchHandlerMode() else { auto& sixthParam = onViewParameters[OnViewParameter::Sixth]; - if (fifthParam->hasFinishedEditing || sixthParam->hasFinishedEditing) { + if (fifthParam->hasFinishedEditing && sixthParam->hasFinishedEditing) { handler->setState(SelectMode::End); } } diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerArcSlot.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerArcSlot.h index b5a1e74391..305ef517a0 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerArcSlot.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerArcSlot.h @@ -792,7 +792,7 @@ void DSHArcSlotController::doChangeDrawSketchHandlerMode() auto& thirdParam = onViewParameters[OnViewParameter::Third]; auto& fourthParam = onViewParameters[OnViewParameter::Fourth]; - if (thirdParam->hasFinishedEditing || fourthParam->hasFinishedEditing) { + if (thirdParam->hasFinishedEditing && fourthParam->hasFinishedEditing) { handler->setState(SelectMode::SeekThird); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerBSpline.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerBSpline.h index 46903efbe6..0d12a1f76e 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerBSpline.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerBSpline.h @@ -1096,7 +1096,7 @@ void DSHBSplineController::doChangeDrawSketchHandlerMode() auto& thirdParam = onViewParameters[OnViewParameter::Third]; auto& fourthParam = onViewParameters[OnViewParameter::Fourth]; - if (thirdParam->hasFinishedEditing || fourthParam->hasFinishedEditing) { + if (thirdParam->hasFinishedEditing && fourthParam->hasFinishedEditing) { handler->canGoToNextMode(); // its not going to next mode unsetOnViewParameter(thirdParam.get()); diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerCircle.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerCircle.h index 5e93a86cf7..055a079b88 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerCircle.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerCircle.h @@ -630,7 +630,7 @@ void DSHCircleController::doChangeDrawSketchHandlerMode() auto& fifthParam = onViewParameters[OnViewParameter::Fifth]; auto& sixthParam = onViewParameters[OnViewParameter::Sixth]; - if (fifthParam->hasFinishedEditing || sixthParam->hasFinishedEditing) { + if (fifthParam->hasFinishedEditing && sixthParam->hasFinishedEditing) { handler->setState(SelectMode::End); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h index 033d2597c2..2a478c64bf 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h @@ -705,7 +705,7 @@ void DSHEllipseController::doChangeDrawSketchHandlerMode() auto& thirdParam = onViewParameters[OnViewParameter::Third]; auto& fourthParam = onViewParameters[OnViewParameter::Fourth]; - if (thirdParam->hasFinishedEditing || fourthParam->hasFinishedEditing) { + if (thirdParam->hasFinishedEditing && fourthParam->hasFinishedEditing) { handler->setState(SelectMode::SeekThird); } } break; @@ -720,7 +720,7 @@ void DSHEllipseController::doChangeDrawSketchHandlerMode() } else { auto& sixthParam = onViewParameters[OnViewParameter::Sixth]; - if (fifthParam->hasFinishedEditing || sixthParam->hasFinishedEditing) { + if (fifthParam->hasFinishedEditing && sixthParam->hasFinishedEditing) { handler->setState(SelectMode::End); } } diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h index 96e61a22b9..186a741c2f 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h @@ -571,7 +571,7 @@ void DSHLineController::doChangeDrawSketchHandlerMode() auto& thirdParam = onViewParameters[OnViewParameter::Third]; auto& fourthParam = onViewParameters[OnViewParameter::Fourth]; - if (thirdParam->hasFinishedEditing || fourthParam->hasFinishedEditing) { + if (thirdParam->hasFinishedEditing && fourthParam->hasFinishedEditing) { handler->setState(SelectMode::End); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerPoint.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerPoint.h index cef45cac34..e28abfb2f8 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerPoint.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerPoint.h @@ -234,7 +234,7 @@ void DSHPointController::doChangeDrawSketchHandlerMode() auto& firstParam = onViewParameters[OnViewParameter::First]; auto& secondParam = onViewParameters[OnViewParameter::Second]; - if (firstParam->hasFinishedEditing || secondParam->hasFinishedEditing) { + if (firstParam->hasFinishedEditing && secondParam->hasFinishedEditing) { handler->setState(SelectMode::End); // handler->finish(); // Called by the change of mode } diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerPolygon.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerPolygon.h index c20651acd6..4bc170f68a 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerPolygon.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerPolygon.h @@ -463,7 +463,7 @@ void DSHPolygonController::doChangeDrawSketchHandlerMode() auto& thirdParam = onViewParameters[OnViewParameter::Third]; auto& fourthParam = onViewParameters[OnViewParameter::Fourth]; - if (thirdParam->hasFinishedEditing || fourthParam->hasFinishedEditing) { + if (thirdParam->hasFinishedEditing && fourthParam->hasFinishedEditing) { handler->setState(SelectMode::End); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h index df16b3d043..23302559d7 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h @@ -2353,7 +2353,7 @@ void DSHRectangleController::doChangeDrawSketchHandlerMode() } break; case SelectMode::SeekSecond: { if (onViewParameters[OnViewParameter::Third]->hasFinishedEditing - || onViewParameters[OnViewParameter::Fourth]->hasFinishedEditing) { + && onViewParameters[OnViewParameter::Fourth]->hasFinishedEditing) { if (handler->roundCorners || handler->makeFrame || handler->constructionMethod() == ConstructionMethod::ThreePoints @@ -2387,7 +2387,7 @@ void DSHRectangleController::doChangeDrawSketchHandlerMode() } else { if (onViewParameters[OnViewParameter::Fifth]->hasFinishedEditing - || onViewParameters[OnViewParameter::Sixth]->hasFinishedEditing) { + && onViewParameters[OnViewParameter::Sixth]->hasFinishedEditing) { if (handler->roundCorners || handler->makeFrame) { handler->setState(SelectMode::SeekFourth); } diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h index 67c1b7381f..51ac5ca808 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h @@ -550,7 +550,7 @@ void DSHSlotController::doChangeDrawSketchHandlerMode() auto& thirdParam = onViewParameters[OnViewParameter::Third]; auto& fourthParam = onViewParameters[OnViewParameter::Fourth]; - if (thirdParam->hasFinishedEditing || fourthParam->hasFinishedEditing) { + if (thirdParam->hasFinishedEditing && fourthParam->hasFinishedEditing) { handler->setState(SelectMode::SeekThird); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerTranslate.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerTranslate.h index 9e19d89b57..846097ff57 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerTranslate.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerTranslate.h @@ -721,7 +721,7 @@ void DSHTranslateController::doChangeDrawSketchHandlerMode() auto& thirdParam = onViewParameters[OnViewParameter::Third]; auto& fourthParam = onViewParameters[OnViewParameter::Fourth]; - if (thirdParam->hasFinishedEditing || fourthParam->hasFinishedEditing) { + if (thirdParam->hasFinishedEditing && fourthParam->hasFinishedEditing) { if (handler->secondNumberOfCopies == 1) { handler->setState(SelectMode::End); } @@ -734,7 +734,7 @@ void DSHTranslateController::doChangeDrawSketchHandlerMode() auto& fifthParam = onViewParameters[OnViewParameter::Fifth]; auto& sixthParam = onViewParameters[OnViewParameter::Sixth]; - if (fifthParam->hasFinishedEditing || sixthParam->hasFinishedEditing) { + if (fifthParam->hasFinishedEditing && sixthParam->hasFinishedEditing) { handler->setState(SelectMode::End); } } break;