From 3237a215805297c6b97e6868c851b3e56a5de6b3 Mon Sep 17 00:00:00 2001 From: Captain <87000456+captain0xff@users.noreply.github.com> Date: Mon, 9 Feb 2026 02:06:04 +0530 Subject: [PATCH] PartDesign: add interactive gizmos for box, cylinder and sphere operations (#23700) --- src/Mod/Part/Gui/TaskAttacher.cpp | 11 +++ src/Mod/Part/Gui/TaskAttacher.h | 3 + .../Gui/TaskPrimitiveParameters.cpp | 80 +++++++++++++++++++ .../PartDesign/Gui/TaskPrimitiveParameters.h | 16 +++- 4 files changed, 109 insertions(+), 1 deletion(-) diff --git a/src/Mod/Part/Gui/TaskAttacher.cpp b/src/Mod/Part/Gui/TaskAttacher.cpp index a11ba5ffd6..3f538015ae 100644 --- a/src/Mod/Part/Gui/TaskAttacher.cpp +++ b/src/Mod/Part/Gui/TaskAttacher.cpp @@ -594,6 +594,8 @@ void TaskAttacher::onSelectionChanged(const Gui::SelectionChanges& msg) if (msg.Type == Gui::SelectionChanges::AddSelection) { SubAndObjName pair = {msg.pObjectName, msg.pSubName}; addToReference(pair); + + Q_EMIT placementUpdated(); } } @@ -736,6 +738,8 @@ void TaskAttacher::onAttachmentOffsetChanged(double /*val*/, int idx) pcAttach->AttachmentOffset.setValue(pl); updatePreview(); + + Q_EMIT placementUpdated(); } void TaskAttacher::onAttachmentOffsetXChanged(double val) @@ -778,6 +782,8 @@ void TaskAttacher::onCheckFlip(bool on) = ViewProvider->getObject()->getExtensionByType(); pcAttach->MapReversed.setValue(on); ViewProvider->getObject()->recomputeFeature(); + + Q_EMIT placementUpdated(); } void TaskAttacher::onButtonRef(const bool checked, unsigned idx) @@ -794,6 +800,8 @@ void TaskAttacher::onButtonRef(const bool checked, unsigned idx) updateRefButton(1); updateRefButton(2); updateRefButton(3); + + Q_EMIT placementUpdated(); } void TaskAttacher::onButtonRef1(const bool checked) @@ -873,6 +881,7 @@ void TaskAttacher::onRefName(const QString& text, unsigned idx) ui->lineRef4->setText(refstrings[3]); ui->lineRef4->setProperty("RefName", QByteArray(newrefnames[3].c_str())); updateReferencesUI(); + Q_EMIT placementUpdated(); return; } @@ -963,6 +972,8 @@ void TaskAttacher::onRefName(const QString& text, unsigned idx) selectMapMode(getActiveMapMode()); updateReferencesUI(); + + Q_EMIT placementUpdated(); } void TaskAttacher::updateRefButton(int idx) diff --git a/src/Mod/Part/Gui/TaskAttacher.h b/src/Mod/Part/Gui/TaskAttacher.h index e15914c303..dc70c3558e 100644 --- a/src/Mod/Part/Gui/TaskAttacher.h +++ b/src/Mod/Part/Gui/TaskAttacher.h @@ -90,6 +90,9 @@ public: return completed; } +Q_SIGNALS: + void placementUpdated(); + private Q_SLOTS: void onAttachmentOffsetChanged(double, int idx); void onAttachmentOffsetXChanged(double); diff --git a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp index cc5759ad73..def61aff1f 100644 --- a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp @@ -29,12 +29,15 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #include #include @@ -369,6 +372,8 @@ TaskBoxPrimitives::TaskBoxPrimitives(ViewProviderPrimitive* vp, QWidget* parent) this, &TaskBoxPrimitives::onWedgeZ2maxChanged); connect(ui->wedgeZ2min, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &TaskBoxPrimitives::onWedgeZ2minChanged); + + setupGizmos(); } // clang-format on @@ -810,6 +815,11 @@ void TaskBoxPrimitives::onWedgeZmaxChanged(double v) } } +void TaskBoxPrimitives::onPlacementChanged() +{ + setGizmoPositions(); +} + bool TaskBoxPrimitives::setPrimitive(App::DocumentObject* obj) { @@ -998,6 +1008,69 @@ bool TaskBoxPrimitives::setPrimitive(App::DocumentObject* obj) return true; } +void TaskBoxPrimitives::setupGizmos() +{ + if (!Gui::GizmoContainer::isEnabled()) { + return; + } + + switch (getObject()->getPrimitiveType()) { + case PartDesign::FeaturePrimitive::Box: + lengthGizmo = new Gui::LinearGizmo(ui->boxLength); + widthGizmo = new Gui::LinearGizmo(ui->boxWidth); + heightGizmo = new Gui::LinearGizmo(ui->boxHeight); + + gizmoContainer = Gui::GizmoContainer::create({widthGizmo, heightGizmo, lengthGizmo}, vp); + break; + case PartDesign::FeaturePrimitive::Cylinder: + heightGizmo = new Gui::LinearGizmo(ui->cylinderHeight); + radiusGizmo = new Gui::LinearGizmo(ui->cylinderRadius); + + gizmoContainer = Gui::GizmoContainer::create({heightGizmo, radiusGizmo}, vp); + break; + case PartDesign::FeaturePrimitive::Sphere: + radiusGizmo = new Gui::LinearGizmo(ui->sphereRadius); + + gizmoContainer = Gui::GizmoContainer::create({radiusGizmo}, vp); + break; + default: + return; + } + + setGizmoPositions(); +} + +void TaskBoxPrimitives::setGizmoPositions() +{ + if (!gizmoContainer) { + return; + } + + SbVec3f pos = Base::convertTo(vp->getObjectPlacement().getPosition()); + SbRotation rot = Base::convertTo(vp->getObjectPlacement().getRotation()); + auto getVec = [rot](SbVec3f vec) { + rot.multVec(vec, vec); + + return vec; + }; + switch (getObject()->getPrimitiveType()) { + case PartDesign::FeaturePrimitive::Box: + lengthGizmo->setDraggerPlacement(pos, getVec({1, 0, 0})); + widthGizmo->setDraggerPlacement(pos, getVec({0, 1, 0})); + heightGizmo->setDraggerPlacement(pos, getVec({0, 0, 1})); + break; + case PartDesign::FeaturePrimitive::Cylinder: + heightGizmo->setDraggerPlacement(pos, getVec({0, 0, 1})); + radiusGizmo->setDraggerPlacement(pos, getVec({1, 1, 0})); + break; + case PartDesign::FeaturePrimitive::Sphere: + radiusGizmo->setDraggerPlacement(pos, getVec({1, 1, 0})); + break; + default: + return; + } +} + TaskDlgPrimitiveParameters::TaskDlgPrimitiveParameters(ViewProviderPrimitive* PrimitiveView) : TaskDlgFeatureParameters(PrimitiveView) , vp_prm(PrimitiveView) @@ -1009,6 +1082,13 @@ TaskDlgPrimitiveParameters::TaskDlgPrimitiveParameters(ViewProviderPrimitive* Pr parameter = new PartGui::TaskAttacher(PrimitiveView, nullptr, QString(), tr("Attachment")); Content.push_back(parameter); Content.push_back(preview); + + connect( + parameter, + &PartGui::TaskAttacher::placementUpdated, + primitive, + &TaskBoxPrimitives::onPlacementChanged + ); } TaskDlgPrimitiveParameters::~TaskDlgPrimitiveParameters() = default; diff --git a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h index 5cf94a159c..592ca89f19 100644 --- a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h @@ -27,6 +27,8 @@ #define GUI_TASKVIEW_TaskPrimitiveParameters_H #include +#include + #include #include #include @@ -43,7 +45,9 @@ class Property; namespace Gui { class ViewProvider; -} +class GizmoContainer; +class LinearGizmo; +} // namespace Gui namespace PartDesignGui { @@ -102,6 +106,8 @@ public Q_SLOTS: void onWedgeZ2maxChanged(double); void onWedgeZ2minChanged(double); + void onPlacementChanged(); + private: /** Notifies when the object is about to be removed. */ void slotDeletedObject(const Gui::ViewProviderDocumentObject& Obj) override; @@ -121,6 +127,14 @@ private: QWidget* proxy; std::unique_ptr ui; ViewProviderPrimitive* vp; + + std::unique_ptr gizmoContainer; + Gui::LinearGizmo* lengthGizmo = nullptr; + Gui::LinearGizmo* heightGizmo = nullptr; + Gui::LinearGizmo* widthGizmo = nullptr; + Gui::LinearGizmo* radiusGizmo = nullptr; + void setupGizmos(); + void setGizmoPositions(); }; class TaskDlgPrimitiveParameters: public TaskDlgFeatureParameters