Merge pull request #21943 from tetektoza/fix/21927_change_enter_ovp_accepting_dim

Sketcher: Change enter behavior on OVP to put OVP in lock state only
This commit is contained in:
Benjamin Nauck
2025-06-23 21:18:41 +02:00
committed by GitHub
15 changed files with 200 additions and 29 deletions

View File

@@ -33,8 +33,13 @@
#include <QEvent>
#include <QKeyEvent>
#include <QPixmap>
#include <QLabel>
#include <QHBoxLayout>
#include <QString>
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
@@ -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 = " ";
@@ -206,14 +215,43 @@ bool EditableDatumLabel::eventFilter(QObject* watched, QEvent* event)
{
if (event->type() == QEvent::KeyPress) {
auto* keyEvent = static_cast<QKeyEvent*>(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<QAbstractSpinBox*>(watched)) {
this->hasFinishedEditing = true;
Q_EMIT this->valueChanged(this->value);
return false;
// 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;
}
// 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 +271,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 +352,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 +495,64 @@ 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);
// 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);
}
lockIconLabel->show();
}
} 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;

View File

@@ -26,6 +26,7 @@
#include <QObject>
#include <QPointer>
#include <QLabel>
#include <Gui/QuantitySpinBox.h>
#include "SoDatumLabel.h"
@@ -72,6 +73,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 +81,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 +99,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 +114,7 @@ private:
SoTransform* transform;
QPointer<View3DInventorViewer> viewer;
QuantitySpinBox* spinBox;
QLabel* lockIconLabel; ///< Label to display lock icon next to spinbox
SoNodeSensor* cameraSensor;
SbVec3f midpos;

View File

@@ -365,8 +365,56 @@ 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<int>(i))) {
onViewParameters[i]->isSet = true;
onViewParameters[i]->hasFinishedEditing = true;
double currentValue = onViewParameters[i]->getValue();
onViewValueChanged(static_cast<int>(i), currentValue);
}
}
}
void tryViewValueChanged(int onviewparameterindex, double value)
{
// 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<int>(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.
// -> A machine does not forward to a next state when adapting the parameter (though it
// may forward to
@@ -628,6 +676,11 @@ 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();
});
}
}

View File

@@ -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;
@@ -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);
}
}

View File

@@ -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;
@@ -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;

View File

@@ -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());

View File

@@ -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;
@@ -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;

View File

@@ -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;
@@ -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);
}
}

View File

@@ -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;
@@ -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;

View File

@@ -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
}

View File

@@ -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;
@@ -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;

View File

@@ -2346,14 +2346,14 @@ 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);
}
} 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);
}

View File

@@ -702,7 +702,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;

View File

@@ -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;
@@ -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;

View File

@@ -756,7 +756,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;
@@ -764,7 +764,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);
}
@@ -777,7 +777,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;