From fcf54e031cdeaa37e469c8c62c686730e3690a6a Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Wed, 26 Jun 2024 15:25:41 +0200 Subject: [PATCH] Assembly: Enable moving objects while making joints. --- src/Mod/Assembly/App/AssemblyObject.cpp | 2 +- src/Mod/Assembly/App/AssemblyObject.h | 2 +- src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 61 +++++++++++-------- src/Mod/Assembly/Gui/ViewProviderAssembly.h | 18 ++++++ .../Assembly/Gui/ViewProviderAssemblyPy.xml | 12 ++++ .../Gui/ViewProviderAssemblyPyImp.cpp | 20 ++++++ src/Mod/Assembly/JointObject.py | 46 ++++++++------ 7 files changed, 113 insertions(+), 48 deletions(-) diff --git a/src/Mod/Assembly/App/AssemblyObject.cpp b/src/Mod/Assembly/App/AssemblyObject.cpp index 0dabd5b998..336538ca86 100644 --- a/src/Mod/Assembly/App/AssemblyObject.cpp +++ b/src/Mod/Assembly/App/AssemblyObject.cpp @@ -528,7 +528,7 @@ std::vector AssemblyObject::getJoints(bool updateJCS, bool // add sub assemblies joints. for (auto& assembly : getSubAssemblies()) { - auto subJoints = assembly->getJoints(updateJCS); + auto subJoints = assembly->getJoints(updateJCS, delBadJoints); joints.insert(joints.end(), subJoints.begin(), subJoints.end()); } diff --git a/src/Mod/Assembly/App/AssemblyObject.h b/src/Mod/Assembly/App/AssemblyObject.h index c15229515b..4a8753f7ec 100644 --- a/src/Mod/Assembly/App/AssemblyObject.h +++ b/src/Mod/Assembly/App/AssemblyObject.h @@ -184,7 +184,7 @@ public: void jointParts(std::vector joints); JointGroup* getJointGroup(); ViewGroup* getExplodedViewGroup(); - std::vector getJoints(bool updateJCS = true, bool delBadJoints = true); + std::vector getJoints(bool updateJCS = true, bool delBadJoints = false); std::vector getGroundedJoints(); std::vector getJointsOfObj(App::DocumentObject* obj); std::vector getJointsOfPart(App::DocumentObject* part); diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index a780ea3ccb..22e647b42f 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -92,6 +92,8 @@ ViewProviderAssembly::ViewProviderAssembly() , canStartDragging(false) , partMoving(false) , enableMovement(true) + , moveOnlyPreselected(false) + , moveInCommand(true) , jointVisibilityBackup(false) , ctrlPressed(false) , docsToMove({}) @@ -139,7 +141,6 @@ bool ViewProviderAssembly::canDragObject(App::DocumentObject* obj) const // else if a solid is removed, remove associated joints if any. bool prompted = false; auto* assemblyPart = static_cast(getObject()); - std::vector joints = assemblyPart->getJoints(); // Combine the joints and groundedJoints vectors into one for simplicity. std::vector allJoints = assemblyPart->getJoints(); @@ -505,30 +506,33 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection return false; } - for (auto& selObj : Gui::Selection().getSelectionEx("", - App::DocumentObject::getClassTypeId(), - Gui::ResolveMode::NoResolve)) { - // getSubNames() returns ["Body001.Pad.Face14", "Body002.Pad.Face7"] - // if you have several objects within the same assembly selected. + if (!moveOnlyPreselected) { + for (auto& selObj : Gui::Selection().getSelectionEx("", + App::DocumentObject::getClassTypeId(), + Gui::ResolveMode::NoResolve)) { + // getSubNames() returns ["Body001.Pad.Face14", "Body002.Pad.Face7"] + // if you have several objects within the same assembly selected. - std::vector objsSubNames = selObj.getSubNames(); - for (auto& subNamesStr : objsSubNames) { - std::vector subNames = parseSubNames(subNamesStr); - if (subNames.empty()) { - continue; + std::vector objsSubNames = selObj.getSubNames(); + for (auto& subNamesStr : objsSubNames) { + std::vector subNames = parseSubNames(subNamesStr); + if (subNames.empty()) { + continue; + } + if (onlySolids && subNames.back() != "") { + continue; + } + + App::DocumentObject* obj = getObjectFromSubNames(subNames); + + if (!canDragObjectIn3d(obj)) { + continue; + } + + auto* pPlc = + dynamic_cast(obj->getPropertyByName("Placement")); + docsToMove.emplace_back(obj, pPlc->getValue()); } - if (onlySolids && subNames.back() != "") { - continue; - } - - App::DocumentObject* obj = getObjectFromSubNames(subNames); - - if (!canDragObjectIn3d(obj)) { - continue; - } - - auto* pPlc = dynamic_cast(obj->getPropertyByName("Placement")); - docsToMove.emplace_back(obj, pPlc->getValue()); } } @@ -557,7 +561,7 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection if (!alreadyIn) { auto* pPlc = dynamic_cast(obj->getPropertyByName("Placement")); - if (!ctrlPressed) { + if (!ctrlPressed && !moveOnlyPreselected) { Gui::Selection().clearSelection(); docsToMove.clear(); } @@ -772,8 +776,9 @@ void ViewProviderAssembly::initMove(const SbVec2s& cursorPos, Gui::View3DInvento prevPosition = initialPosition; } - - Gui::Command::openCommand(tr("Move part").toStdString().c_str()); + if (moveInCommand) { + Gui::Command::openCommand(tr("Move part").toStdString().c_str()); + } partMoving = true; // prevent selection while moving @@ -825,7 +830,9 @@ void ViewProviderAssembly::endMove() assemblyPart->setObjMasses({}); } - Gui::Command::commitCommand(); + if (moveInCommand) { + Gui::Command::commitCommand(); + } } void ViewProviderAssembly::initMoveDragger() diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.h b/src/Mod/Assembly/Gui/ViewProviderAssembly.h index e952b1c91a..70d671d663 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.h +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.h @@ -114,6 +114,22 @@ public: { return enableMovement; } + virtual void setMoveOnlyPreselected(bool enable = true) + { + moveOnlyPreselected = enable; + } + virtual bool getMoveOnlyPreselected() const + { + return moveOnlyPreselected; + } + virtual void setMoveInCommand(bool enable = true) + { + moveInCommand = enable; + } + virtual bool getMoveInCommand() const + { + return moveInCommand; + } bool canDragObjectIn3d(App::DocumentObject* obj) const; @@ -150,6 +166,8 @@ public: bool canStartDragging; bool partMoving; bool enableMovement; + bool moveOnlyPreselected; + bool moveInCommand; bool jointVisibilityBackup; bool ctrlPressed; int numberOfSel; diff --git a/src/Mod/Assembly/Gui/ViewProviderAssemblyPy.xml b/src/Mod/Assembly/Gui/ViewProviderAssemblyPy.xml index 8d2fac8863..8d0f9dfad9 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssemblyPy.xml +++ b/src/Mod/Assembly/Gui/ViewProviderAssemblyPy.xml @@ -31,6 +31,18 @@ + + + If enabled, only the preselected object will move. + + + + + + If enabled, each move will be wrapped in a command. + + + Show or hide the assembly dragger. diff --git a/src/Mod/Assembly/Gui/ViewProviderAssemblyPyImp.cpp b/src/Mod/Assembly/Gui/ViewProviderAssemblyPyImp.cpp index 4e3bd156c2..c733b11c17 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssemblyPyImp.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssemblyPyImp.cpp @@ -52,6 +52,26 @@ void ViewProviderAssemblyPy::setEnableMovement(Py::Boolean arg) getViewProviderAssemblyPtr()->setEnableMovement(arg); } +Py::Boolean ViewProviderAssemblyPy::getMoveOnlyPreselected() const +{ + return {getViewProviderAssemblyPtr()->getMoveOnlyPreselected()}; +} + +void ViewProviderAssemblyPy::setMoveOnlyPreselected(Py::Boolean arg) +{ + getViewProviderAssemblyPtr()->setMoveOnlyPreselected(arg); +} + +Py::Boolean ViewProviderAssemblyPy::getMoveInCommand() const +{ + return {getViewProviderAssemblyPtr()->getMoveInCommand()}; +} + +void ViewProviderAssemblyPy::setMoveInCommand(Py::Boolean arg) +{ + getViewProviderAssemblyPtr()->setMoveInCommand(arg); +} + Py::Boolean ViewProviderAssemblyPy::getDraggerVisibility() const { return {getViewProviderAssemblyPtr()->getDraggerVisibility()}; diff --git a/src/Mod/Assembly/JointObject.py b/src/Mod/Assembly/JointObject.py index bcff1ca936..63f6d85e5b 100644 --- a/src/Mod/Assembly/JointObject.py +++ b/src/Mod/Assembly/JointObject.py @@ -1223,14 +1223,6 @@ class MakeJointSelGate: # Only objects within the assembly. return False - if Gui.Selection.isSelected(obj, sub, Gui.Selection.ResolveMode.NoResolve): - # If it's to deselect then it's ok - return True - - if len(self.taskbox.current_selection) >= 2: - # No more than 2 elements can be selected for basic joints. - return False - full_obj_name = ".".join(objs_names) full_element_name = full_obj_name + "." + element_name selected_object = UtilsAssembly.getObject(full_element_name) @@ -1247,15 +1239,6 @@ class MakeJointSelGate: else: return False - part_containing_selected_object = UtilsAssembly.getContainingPart( - full_element_name, selected_object, self.assembly - ) - - for selection_dict in self.taskbox.current_selection: - if selection_dict["part"] == part_containing_selected_object: - # Can't join a solid to itself. So the user need to select 2 different parts. - return False - return True @@ -1285,7 +1268,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject): return if self.activeType == "Assembly": - self.assembly.ViewObject.EnableMovement = False + self.assembly.ViewObject.MoveOnlyPreselected = True + self.assembly.ViewObject.MoveInCommand = False self.form = Gui.PySideUic.loadUi(":/panels/TaskAssemblyCreateJoint.ui") @@ -1358,6 +1342,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.form.featureList.installEventFilter(self) + self.addition_rejected = False + def accept(self): if len(self.current_selection) != 2: App.Console.PrintWarning( @@ -1389,7 +1375,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject): if self.activeType == "Assembly": self.assembly.clearUndo() - self.assembly.ViewObject.EnableMovement = True + self.assembly.ViewObject.MoveOnlyPreselected = False + self.assembly.ViewObject.MoveInCommand = True Gui.Selection.removeSelectionGate() Gui.Selection.removeObserver(self) @@ -1831,6 +1818,23 @@ class TaskAssemblyCreateJoint(QtCore.QObject): element_name = UtilsAssembly.getElementName(full_element_name) part_containing_selected_object = self.getContainingPart(full_element_name, selected_object) + # Check if the addition is acceptable (we are not doing this in selection gate to let user move objects) + acceptable = True + if len(self.current_selection) >= 2: + # No more than 2 elements can be selected for basic joints. + acceptable = False + + for selection_dict in self.current_selection: + if selection_dict["part"] == part_containing_selected_object: + # Can't join a solid to itself. So the user need to select 2 different parts. + acceptable = False + + if not acceptable: + self.addition_rejected = True + Gui.Selection.removeSelection(doc_name, obj_name, sub_name) + return + + # Selection is acceptable so add it selection_dict = { "object": selected_object, "part": part_containing_selected_object, @@ -1851,6 +1855,10 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.joint.ViewObject.Proxy.showPreviewJCS(False) def removeSelection(self, doc_name, obj_name, sub_name, mousePos=None): + if self.addition_rejected: + self.addition_rejected = False + return + full_element_name = UtilsAssembly.getFullElementName(obj_name, sub_name) selected_object = UtilsAssembly.getObject(full_element_name) element_name = UtilsAssembly.getElementName(full_element_name)