From f633fa476a49341ff1b709348a177a23ad35c0d8 Mon Sep 17 00:00:00 2001 From: Florian Foinant-Willig Date: Mon, 4 Mar 2024 17:54:25 +0100 Subject: [PATCH] Introduce object freeze (#12580) * Introduce object freeze * do nothing at property change --- src/App/DocumentObject.cpp | 28 ++++ src/App/DocumentObject.h | 7 + src/Gui/CommandFeat.cpp | 50 +++++++ src/Gui/Icons/Std_ToggleFreeze.svg | 201 +++++++++++++++++++++++++++++ src/Gui/Icons/resource.qrc | 4 +- src/Gui/Tree.cpp | 32 +++++ src/Gui/Workbench.cpp | 3 +- 7 files changed, 321 insertions(+), 4 deletions(-) create mode 100644 src/Gui/Icons/Std_ToggleFreeze.svg diff --git a/src/App/DocumentObject.cpp b/src/App/DocumentObject.cpp index 708b6ea3b9..297ab2154b 100644 --- a/src/App/DocumentObject.cpp +++ b/src/App/DocumentObject.cpp @@ -213,6 +213,28 @@ void DocumentObject::touch(bool noRecompute) _pDoc->signalTouchedObject(*this); } +/** + * @brief Set this document object freezed. + * A freezed document object does not recompute ever. + */ +void DocumentObject::freeze() +{ + StatusBits.set(ObjectStatus::Freeze); + // use the signalTouchedObject to refresh the Gui + if (_pDoc) + _pDoc->signalTouchedObject(*this); +} + +/** + * @brief Set this document object unfreezed. + * A freezed document object does not recompute ever. + */ +void DocumentObject::unfreeze(bool noRecompute) +{ + StatusBits.set(ObjectStatus::Freeze, false); + touch(noRecompute); +} + /** * @brief Check whether the document object is touched or not. * @return true if document object is touched, false if not. @@ -240,6 +262,9 @@ void DocumentObject::enforceRecompute() */ bool DocumentObject::mustRecompute() const { + if (StatusBits.test(ObjectStatus::Freeze)) + return false; + if (StatusBits.test(ObjectStatus::Enforce)) return true; @@ -726,6 +751,9 @@ void DocumentObject::onBeforeChange(const Property* prop) /// get called by the container when a Property was changed void DocumentObject::onChanged(const Property* prop) { + if (isFreezed()) + return; + if(GetApplication().isClosingAll()) return; diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index b9b745ad54..a321f97370 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -67,6 +67,7 @@ enum ObjectStatus { PendingTransactionUpdate = 18, // mark that the object expects a call to onUndoRedoFinished() after transaction is finished. RecomputeExtension = 19, // mark the object to recompute its extensions TouchOnColorChange = 20, // inform view provider touch object on color change + Freeze = 21, // do not recompute ever }; /** Return object for feature execution @@ -177,6 +178,12 @@ public: bool isRestoring() const {return StatusBits.test(ObjectStatus::Restore);} /// returns true if this objects is currently removed from the document bool isRemoving() const {return StatusBits.test(ObjectStatus::Remove);} + /// set this document object freezed (prevent recomputation) + void freeze(); + /// set this document object unfreezed (and touch it) + void unfreeze(bool noRecompute=false); + /// returns true if this objects is currently freezed + bool isFreezed() const {return StatusBits.test(ObjectStatus::Freeze);} /// return the status bits unsigned long getStatus() const {return StatusBits.to_ulong();} bool testStatus(ObjectStatus pos) const {return StatusBits.test(size_t(pos));} diff --git a/src/Gui/CommandFeat.cpp b/src/Gui/CommandFeat.cpp index e80dae50f7..31dcb0a3e4 100644 --- a/src/Gui/CommandFeat.cpp +++ b/src/Gui/CommandFeat.cpp @@ -120,6 +120,55 @@ bool StdCmdRandomColor::isActive() return (Gui::Selection().size() != 0); } +//=========================================================================== +// Std_ToggleFreeze +//=========================================================================== +DEF_STD_CMD_A(StdCmdToggleFreeze) + +StdCmdToggleFreeze::StdCmdToggleFreeze() + : Command("Std_ToggleFreeze") +{ + sGroup = "File"; + sMenuText = QT_TR_NOOP("Toggle freeze"); + static std::string toolTip = std::string("

") + + QT_TR_NOOP("Toggles freeze sate of the selected objects. A freezed object is not recomputed when its parents change.") + + "

"; + sToolTipText = toolTip.c_str(); + sStatusTip = sToolTipText; + sWhatsThis = "Std_ToggleFreeze"; + sPixmap = "Std_ToggleFreeze"; + sAccel = ""; + eType = AlterDoc; +} + +void StdCmdToggleFreeze::activated(int iMsg) +{ + Q_UNUSED(iMsg); + getActiveGuiDocument()->openCommand(QT_TRANSLATE_NOOP("Command", "Toggle freeze")); + + std::vector sels = Gui::Selection().getCompleteSelection(); + + for (Gui::SelectionSingleton::SelObj& sel : sels) { + App::DocumentObject* obj = sel.pObject; + if (!obj) + continue; + + if (obj->isFreezed()) + obj->unfreeze(); + else + obj->freeze(); + } + + getActiveGuiDocument()->commitCommand(); +} + +bool StdCmdToggleFreeze::isActive() +{ + return (Gui::Selection().size() != 0); +} + + + //=========================================================================== // Std_SendToPythonConsole @@ -221,6 +270,7 @@ void CreateFeatCommands() CommandManager &rcCmdMgr = Application::Instance->commandManager(); rcCmdMgr.addCommand(new StdCmdFeatRecompute()); + rcCmdMgr.addCommand(new StdCmdToggleFreeze()); rcCmdMgr.addCommand(new StdCmdRandomColor()); rcCmdMgr.addCommand(new StdCmdSendToPythonConsole()); } diff --git a/src/Gui/Icons/Std_ToggleFreeze.svg b/src/Gui/Icons/Std_ToggleFreeze.svg new file mode 100644 index 0000000000..dbae009f61 --- /dev/null +++ b/src/Gui/Icons/Std_ToggleFreeze.svg @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Gui/Icons/resource.qrc b/src/Gui/Icons/resource.qrc index 072fa97833..6911a75902 100644 --- a/src/Gui/Icons/resource.qrc +++ b/src/Gui/Icons/resource.qrc @@ -270,10 +270,8 @@ image-plane.svg image-scaling.svg VarSet.svg + Std_ToggleFreeze.svg - - - index.theme diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 1bbd5def68..0c07f2682b 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -5163,8 +5163,10 @@ void DocumentObjectItem::testStatus(bool resetStatus, QIcon& icon1, QIcon& icon2 auto linked = obj->getLinkedObject(false); bool external = object()->getDocument() != getOwnerDocument()->document() || (linked && linked->getDocument() != obj->getDocument()); + bool freezed = pObject->isFreezed(); int currentStatus = + ((freezed ? 0 : 1) << 5) | ((external ? 0 : 1) << 4) | ((object()->showInTree() ? 0 : 1) << 3) | ((pObject->isError() ? 1 : 0) << 2) | @@ -5320,6 +5322,36 @@ void DocumentObjectItem::testStatus(bool resetStatus, QIcon& icon1, QIcon& icon2 pxOn = BitmapFactory().merge(pxOn, pxExternal, BitmapFactoryInst::BottomRight); } + if (freezed) { + static QPixmap pxFreeze; + if (pxFreeze.isNull()) { + // object is in freezed state + const char* const feature_freezed_xpm[] = { + "16 16 2 1", + " c None", + ". c #00EEFF", + " . . . ", + " . ... . ", + " .. . .. ", + " .... . .... ", + " .. . .. ", + " . . . . .", + " . ... . ", + " ...............", + " . ... . ", + " . . . . .", + " .. . .. ", + " .... . .... ", + " .. . .. ", + " . ... . ", + " . . . ", + " "}; + pxFreeze = QPixmap(feature_freezed_xpm); + } + pxOff = BitmapFactory().merge(pxOff, pxFreeze, BitmapFactoryInst::TopLeft); + pxOn = BitmapFactory().merge(pxOn, pxFreeze, BitmapFactoryInst::TopLeft); + } + icon.addPixmap(pxOn, QIcon::Normal, QIcon::On); icon.addPixmap(pxOff, QIcon::Normal, QIcon::Off); diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp index 131e938f98..46fe3abc94 100644 --- a/src/Gui/Workbench.cpp +++ b/src/Gui/Workbench.cpp @@ -609,7 +609,8 @@ void StdWorkbench::setupContextMenu(const char* recipient, MenuItem* item) const else if (strcmp(recipient,"Tree") == 0) { if (Gui::Selection().countObjectsOfType(App::DocumentObject::getClassTypeId()) > 0) { - *item << "Std_Placement" << "Std_ToggleVisibility" << "Std_ShowSelection" << "Std_HideSelection" + *item << "Std_ToggleFreeze" << "Separator" + << "Std_Placement" << "Std_ToggleVisibility" << "Std_ShowSelection" << "Std_HideSelection" << "Std_ToggleSelectability" << "Std_TreeSelectAllInstances" << "Separator" << "Std_SetAppearance" << "Std_RandomColor" << "Std_ToggleTransparency" << "Separator" << "Std_Cut" << "Std_Copy" << "Std_Paste" << "Std_Delete"