From ef0b2590973e31a38d01a7e225a8f8b87185d9f2 Mon Sep 17 00:00:00 2001 From: tetektoza Date: Wed, 11 Jun 2025 23:59:07 +0200 Subject: [PATCH 1/7] 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; From bcbf8d88a96f06babad948cdb48207acd9f3c187 Mon Sep 17 00:00:00 2001 From: tetektoza Date: Mon, 16 Jun 2025 23:09:38 +0200 Subject: [PATCH 2/7] Sketcher: Adjust P&D mode to new enter behavior --- src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h | 2 +- src/Mod/Sketcher/Gui/DrawSketchHandlerArcSlot.h | 2 +- src/Mod/Sketcher/Gui/DrawSketchHandlerCircle.h | 2 +- src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h | 2 +- src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h | 2 +- src/Mod/Sketcher/Gui/DrawSketchHandlerPolygon.h | 2 +- src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h | 2 +- src/Mod/Sketcher/Gui/DrawSketchHandlerRotate.h | 2 +- src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h | 2 +- src/Mod/Sketcher/Gui/DrawSketchHandlerTranslate.h | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h index 062c864d79..81c7faa2ea 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerArc.h @@ -721,7 +721,7 @@ void DSHArcController::doChangeDrawSketchHandlerMode() auto& firstParam = onViewParameters[OnViewParameter::First]; auto& secondParam = onViewParameters[OnViewParameter::Second]; - if (firstParam->hasFinishedEditing || secondParam->hasFinishedEditing) { + if (firstParam->hasFinishedEditing && secondParam->hasFinishedEditing) { handler->setState(SelectMode::SeekSecond); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerArcSlot.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerArcSlot.h index 305ef517a0..382cf17c04 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerArcSlot.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerArcSlot.h @@ -784,7 +784,7 @@ void DSHArcSlotController::doChangeDrawSketchHandlerMode() auto& firstParam = onViewParameters[OnViewParameter::First]; auto& secondParam = onViewParameters[OnViewParameter::Second]; - if (firstParam->hasFinishedEditing || secondParam->hasFinishedEditing) { + if (firstParam->hasFinishedEditing && secondParam->hasFinishedEditing) { handler->setState(SelectMode::SeekSecond); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerCircle.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerCircle.h index 055a079b88..7ebb975b04 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerCircle.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerCircle.h @@ -603,7 +603,7 @@ void DSHCircleController::doChangeDrawSketchHandlerMode() auto& firstParam = onViewParameters[OnViewParameter::First]; auto& secondParam = onViewParameters[OnViewParameter::Second]; - if (firstParam->hasFinishedEditing || secondParam->hasFinishedEditing) { + if (firstParam->hasFinishedEditing && secondParam->hasFinishedEditing) { handler->setState(SelectMode::SeekSecond); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h index 2a478c64bf..90413ffd07 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h @@ -697,7 +697,7 @@ void DSHEllipseController::doChangeDrawSketchHandlerMode() auto& firstParam = onViewParameters[OnViewParameter::First]; auto& secondParam = onViewParameters[OnViewParameter::Second]; - if (firstParam->hasFinishedEditing || secondParam->hasFinishedEditing) { + if (firstParam->hasFinishedEditing && secondParam->hasFinishedEditing) { handler->setState(SelectMode::SeekSecond); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h index 186a741c2f..a31a3f7e65 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h @@ -563,7 +563,7 @@ void DSHLineController::doChangeDrawSketchHandlerMode() auto& firstParam = onViewParameters[OnViewParameter::First]; auto& secondParam = onViewParameters[OnViewParameter::Second]; - if (firstParam->hasFinishedEditing || secondParam->hasFinishedEditing) { + if (firstParam->hasFinishedEditing && secondParam->hasFinishedEditing) { handler->setState(SelectMode::SeekSecond); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerPolygon.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerPolygon.h index 4bc170f68a..b58a1fb7b6 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerPolygon.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerPolygon.h @@ -455,7 +455,7 @@ void DSHPolygonController::doChangeDrawSketchHandlerMode() auto& firstParam = onViewParameters[OnViewParameter::First]; auto& secondParam = onViewParameters[OnViewParameter::Second]; - if (firstParam->hasFinishedEditing || secondParam->hasFinishedEditing) { + if (firstParam->hasFinishedEditing && secondParam->hasFinishedEditing) { handler->setState(SelectMode::SeekSecond); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h index 23302559d7..a9002a30f0 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h @@ -2346,7 +2346,7 @@ void DSHRectangleController::doChangeDrawSketchHandlerMode() switch (handler->state()) { case SelectMode::SeekFirst: { if (onViewParameters[OnViewParameter::First]->hasFinishedEditing - || onViewParameters[OnViewParameter::Second]->hasFinishedEditing) { + && onViewParameters[OnViewParameter::Second]->hasFinishedEditing) { handler->setState(SelectMode::SeekSecond); } diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerRotate.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerRotate.h index 4baf4773b1..cf9f8f9342 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerRotate.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerRotate.h @@ -661,7 +661,7 @@ void DSHRotateController::doChangeDrawSketchHandlerMode() auto& firstParam = onViewParameters[OnViewParameter::First]; auto& secondParam = onViewParameters[OnViewParameter::Second]; - if (firstParam->hasFinishedEditing || secondParam->hasFinishedEditing) { + if (firstParam->hasFinishedEditing && secondParam->hasFinishedEditing) { handler->setState(SelectMode::SeekSecond); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h index 51ac5ca808..9ffe972cba 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h @@ -542,7 +542,7 @@ void DSHSlotController::doChangeDrawSketchHandlerMode() auto& firstParam = onViewParameters[OnViewParameter::First]; auto& secondParam = onViewParameters[OnViewParameter::Second]; - if (firstParam->hasFinishedEditing || secondParam->hasFinishedEditing) { + if (firstParam->hasFinishedEditing && secondParam->hasFinishedEditing) { handler->setState(SelectMode::SeekSecond); } } break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerTranslate.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerTranslate.h index 846097ff57..833eccc623 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerTranslate.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerTranslate.h @@ -713,7 +713,7 @@ void DSHTranslateController::doChangeDrawSketchHandlerMode() auto& firstParam = onViewParameters[OnViewParameter::First]; auto& secondParam = onViewParameters[OnViewParameter::Second]; - if (firstParam->hasFinishedEditing || secondParam->hasFinishedEditing) { + if (firstParam->hasFinishedEditing && secondParam->hasFinishedEditing) { handler->setState(SelectMode::SeekSecond); } } break; From 1f250fab320cfebb33e07fedb9d866885df5970d Mon Sep 17 00:00:00 2001 From: tetektoza Date: Mon, 16 Jun 2025 23:14:30 +0200 Subject: [PATCH 3/7] Sketcher: Initialize lock icon only once --- src/Gui/EditableDatumLabel.cpp | 52 +++++++++++++++------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/src/Gui/EditableDatumLabel.cpp b/src/Gui/EditableDatumLabel.cpp index c31562a6a1..f3ead76e29 100644 --- a/src/Gui/EditableDatumLabel.cpp +++ b/src/Gui/EditableDatumLabel.cpp @@ -496,37 +496,31 @@ void EditableDatumLabel::setLockedAppearance(bool locked) lockIconLabel = new QLabel(spinBox); lockIconLabel->setAttribute(Qt::WA_TransparentForMouseEvents, true); lockIconLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + + // 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); + // style spinbox and add padding for lock + QString styleSheet = QString::fromLatin1("QSpinBox { " + "padding-right: %1px; " + "}") + .arg(iconSize + padding + 2); + + spinBox->setStyleSheet(styleSheet); } - 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; From 78a754e6204aec5ca43caab6a453d1f276bd85f8 Mon Sep 17 00:00:00 2001 From: tetektoza Date: Mon, 16 Jun 2025 23:36:31 +0200 Subject: [PATCH 4/7] Sketcher: Force cycling back to first labels on OVP if they are not set --- src/Mod/Sketcher/Gui/DrawSketchController.h | 30 ++++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Mod/Sketcher/Gui/DrawSketchController.h b/src/Mod/Sketcher/Gui/DrawSketchController.h index bc75dee386..ac124199e8 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchController.h +++ b/src/Mod/Sketcher/Gui/DrawSketchController.h @@ -386,10 +386,32 @@ public: 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); + // go to next label in circular manner if user has currently pressed enter on current one + if (onViewParameters[onviewparameterindex]->hasFinishedEditing) { + // find the first parameter of the current mode that is not locked to start the cycle + auto findNextUnlockedParameter = [this](size_t startIndex) -> int { + for (size_t i = startIndex; i < onViewParameters.size(); i++) { + if (isOnViewParameterOfCurrentMode(i) + && !onViewParameters[i]->hasFinishedEditing) { + return static_cast(i); + } + } + return -1; + }; + + // find first unlocked parameter (for cycling back) + int firstOfCurrentMode = findNextUnlockedParameter(0); + + // find next unlocked parameter after current one + int nextUnlockedIndex = findNextUnlockedParameter(onviewparameterindex + 1); + + // if no next parameter found, cycle back to first of current mode + if (nextUnlockedIndex != -1) { + setFocusToOnViewParameter(nextUnlockedIndex); + } + else if (firstOfCurrentMode != -1) { + setFocusToOnViewParameter(firstOfCurrentMode); + } } /* That is not supported with on-view parameters. From 9912c029dcd8f427830d94d487d90ccb710ccc7c Mon Sep 17 00:00:00 2001 From: tetektoza Date: Mon, 16 Jun 2025 23:55:19 +0200 Subject: [PATCH 5/7] Sketcher: Add QLabel header for newly added locked icon --- src/Gui/EditableDatumLabel.h | 1 + src/Mod/Sketcher/Gui/DrawSketchController.h | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Gui/EditableDatumLabel.h b/src/Gui/EditableDatumLabel.h index 6f6b1bb05c..6b3aad0b78 100644 --- a/src/Gui/EditableDatumLabel.h +++ b/src/Gui/EditableDatumLabel.h @@ -26,6 +26,7 @@ #include #include +#include #include #include "SoDatumLabel.h" diff --git a/src/Mod/Sketcher/Gui/DrawSketchController.h b/src/Mod/Sketcher/Gui/DrawSketchController.h index ac124199e8..3feed1dd3a 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchController.h +++ b/src/Mod/Sketcher/Gui/DrawSketchController.h @@ -374,7 +374,8 @@ public: // 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))) { + if (isOnViewParameterOfCurrentMode(i) && isOnViewParameterVisible(i) + && initialState == getState(static_cast(i))) { onViewParameters[i]->isSet = true; onViewParameters[i]->hasFinishedEditing = true; @@ -677,11 +678,9 @@ protected: }); // Connect Ctrl+Enter signal to apply values to all visible OVPs in current stage - QObject::connect(parameter, - &Gui::EditableDatumLabel::finishEditingOnAllOVPs, - [this]() { - finishEditingOnAllOVPs(); - }); + QObject::connect(parameter, &Gui::EditableDatumLabel::finishEditingOnAllOVPs, [this]() { + finishEditingOnAllOVPs(); + }); } } From 7515c70b677ada75e40328a714d5e592a9552e08 Mon Sep 17 00:00:00 2001 From: tetektoza Date: Sat, 21 Jun 2025 13:48:12 +0200 Subject: [PATCH 6/7] Sketcher: Make TAB lock the label if user has typed previously --- src/Gui/EditableDatumLabel.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Gui/EditableDatumLabel.cpp b/src/Gui/EditableDatumLabel.cpp index f3ead76e29..a0fc8f91bc 100644 --- a/src/Gui/EditableDatumLabel.cpp +++ b/src/Gui/EditableDatumLabel.cpp @@ -215,9 +215,15 @@ bool EditableDatumLabel::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::KeyPress) { auto* keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { + if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Tab) { if (auto* spinBox = qobject_cast(watched)) { + // if tab has been pressed and user did not type anything previously, + // then just cycle but don't lock anything, otherwise we lock the label + if (keyEvent->key() == Qt::Key_Tab && !this->isSet) { + return false; + } + // for ctrl + enter we accept values as they are if (keyEvent->modifiers() & Qt::ControlModifier) { Q_EMIT this->finishEditingOnAllOVPs(); From 75017b2dd25c9c66c03e7e898684c58f57e59a53 Mon Sep 17 00:00:00 2001 From: tetektoza Date: Mon, 23 Jun 2025 19:24:30 +0200 Subject: [PATCH 7/7] Sketcher: Make TAB clear the field if user hasn't valid input --- src/Gui/EditableDatumLabel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Gui/EditableDatumLabel.cpp b/src/Gui/EditableDatumLabel.cpp index a0fc8f91bc..d0d36d1182 100644 --- a/src/Gui/EditableDatumLabel.cpp +++ b/src/Gui/EditableDatumLabel.cpp @@ -221,6 +221,10 @@ bool EditableDatumLabel::eventFilter(QObject* watched, QEvent* event) // if tab has been pressed and user did not type anything previously, // then just cycle but don't lock anything, otherwise we lock the label if (keyEvent->key() == Qt::Key_Tab && !this->isSet) { + if (!this->spinBox->hasValidInput()) { + Q_EMIT this->spinBox->valueChanged(this->value); + return true; + } return false; }