diff --git a/src/Gui/FreeCADGuiInit.py b/src/Gui/FreeCADGuiInit.py index 5f176d78ac..3831335cbd 100644 --- a/src/Gui/FreeCADGuiInit.py +++ b/src/Gui/FreeCADGuiInit.py @@ -38,8 +38,7 @@ Gui = FreeCADGui Gui.listCommands = Gui.Command.listAll Gui.isCommandActive = lambda cmd: Gui.Command.get(cmd).isActive() -# The values must match with that of the -# C++ enum class ResolveMode +# The values must match with that of the C++ enum class ResolveMode class ResolveMode(IntEnum): NoResolve = 0 OldStyleElement = 1 @@ -48,6 +47,13 @@ class ResolveMode(IntEnum): Gui.Selection.ResolveMode = ResolveMode +# The values must match with that of the C++ enum class SelectionStyle +class SelectionStyle(IntEnum): + NormalSelection = 0 + GreedySelection = 1 + +Gui.Selection.SelectionStyle = SelectionStyle + # Important definitions class Workbench: """The workbench base class.""" diff --git a/src/Gui/Selection.cpp b/src/Gui/Selection.cpp index e08538ef45..654614526a 100644 --- a/src/Gui/Selection.cpp +++ b/src/Gui/Selection.cpp @@ -1599,6 +1599,15 @@ void SelectionSingleton::slotDeletedObject(const App::DocumentObject& Obj) } } +void SelectionSingleton::setSelectionStyle(SelectionStyle selStyle) +{ + selectionStyle = selStyle; +} + +SelectionSingleton::SelectionStyle SelectionSingleton::getSelectionStyle() +{ + return selectionStyle; +} //************************************************************************** // Construction/Destruction @@ -1607,8 +1616,9 @@ void SelectionSingleton::slotDeletedObject(const App::DocumentObject& Obj) * A constructor. * A more elaborate description of the constructor. */ -SelectionSingleton::SelectionSingleton() - :CurrentPreselection(SelectionChanges::ClrSelection) +SelectionSingleton::SelectionSingleton() : + CurrentPreselection(SelectionChanges::ClrSelection), + selectionStyle(SelectionStyle::NormalSelection) { hx = 0; hy = 0; @@ -1778,6 +1788,12 @@ PyMethodDef SelectionSingleton::Methods[] = { "objName : str\n Name of the `App.DocumentObject` to select.\n" "subName : str\n Subelement name.\n" "point : tuple\n Coordinates of the point to pick."}, + {"setSelectionStyle", (PyCFunction) SelectionSingleton::sSetSelectionStyle, METH_VARARGS, + "setSelectionStyle(selectionStyle) -> None\n" + "\n" + "Change the selection style. 0 for normal selection, 1 for greedy selection\n" + "\n" + "selectionStyle : int"}, {"addObserver", (PyCFunction) SelectionSingleton::sAddSelObserver, METH_VARARGS, "addObserver(object, resolve=ResolveMode.OldStyleElement) -> None\n" "\n" @@ -2259,6 +2275,19 @@ PyObject *SelectionSingleton::sGetSelectionObject(PyObject * /*self*/, PyObject } } +PyObject *SelectionSingleton::sSetSelectionStyle(PyObject * /*self*/, PyObject *args) +{ + int selStyle = 0; + if (!PyArg_ParseTuple(args, "i", &selStyle)) + return nullptr; + + PY_TRY { + Selection().setSelectionStyle(selStyle == 0 ? SelectionStyle::NormalSelection : SelectionStyle::GreedySelection); + Py_Return; + } + PY_CATCH; +} + PyObject *SelectionSingleton::sAddSelObserver(PyObject * /*self*/, PyObject *args) { PyObject* o; diff --git a/src/Gui/Selection.h b/src/Gui/Selection.h index 736ff69149..7d31e89a12 100644 --- a/src/Gui/Selection.h +++ b/src/Gui/Selection.h @@ -601,6 +601,22 @@ public: const char* pDocName=nullptr, Base::Type typeId=App::DocumentObject::getClassTypeId()) const; //@} + /** @name Selection style functions + * + * The selection style changes the way selection works. In Greedy selection + * it is as if you were pressing Ctrl. + */ + //@{ + enum class SelectionStyle { + NormalSelection, + GreedySelection + }; + /// Changes the style of selection between greedy and normal. + void setSelectionStyle(SelectionStyle selStyle); + /// Get the style of selection. + SelectionStyle getSelectionStyle(); + //@} + static SelectionSingleton& instance(); static void destruct (); friend class SelectionFilter; @@ -622,6 +638,7 @@ protected: static PyObject *sGetCompleteSelection(PyObject *self,PyObject *args); static PyObject *sGetSelectionEx (PyObject *self,PyObject *args); static PyObject *sGetSelectionObject (PyObject *self,PyObject *args); + static PyObject *sSetSelectionStyle (PyObject *self,PyObject *args); static PyObject *sAddSelObserver (PyObject *self,PyObject *args); static PyObject *sRemSelObserver (PyObject *self,PyObject *args); static PyObject *sAddSelectionGate (PyObject *self,PyObject *args); @@ -703,6 +720,8 @@ protected: int logDisabled = 0; bool logHasSelection = false; + + SelectionStyle selectionStyle; }; /** diff --git a/src/Gui/SoFCUnifiedSelection.cpp b/src/Gui/SoFCUnifiedSelection.cpp index 95924f3bf5..6ce2e11597 100644 --- a/src/Gui/SoFCUnifiedSelection.cpp +++ b/src/Gui/SoFCUnifiedSelection.cpp @@ -743,7 +743,8 @@ SoFCUnifiedSelection::handleEvent(SoHandleEventAction * action) if (SoMouseButtonEvent::isButtonReleaseEvent(e,SoMouseButtonEvent::BUTTON1)) { // check to see if the mouse is over a geometry... auto infos = this->getPickedList(action,!Selection().needPickedList()); - if(setSelection(infos,event->wasCtrlDown())) + bool greedySel = Gui::Selection().getSelectionStyle() == Gui::SelectionSingleton::SelectionStyle::GreedySelection; + if(setSelection(infos, event->wasCtrlDown() || greedySel)) action->setHandled(); } // mouse release }