diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index c2f0eabf0a..ab81adc098 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -817,6 +817,7 @@ SET(View3D_CPP_SRCS View.cpp View3DInventor.cpp View3DInventorExamples.cpp + View3DInventorSelection.cpp View3DInventorViewer.cpp View3DInventorRiftViewer.cpp CoinRiftWidget.cpp @@ -836,6 +837,7 @@ SET(View3D_SRCS View.h View3DInventor.h View3DInventorExamples.h + View3DInventorSelection.h View3DInventorViewer.h View3DPy.h View3DInventorRiftViewer.h diff --git a/src/Gui/View3DInventorSelection.cpp b/src/Gui/View3DInventorSelection.cpp new file mode 100644 index 0000000000..00fce4b7e7 --- /dev/null +++ b/src/Gui/View3DInventorSelection.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** + * Copyright (c) 2022 Zheng Lei (realthunder) * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ****************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +# include +#endif + +#include "Application.h" +#include "Document.h" +#include "SoFCUnifiedSelection.h" +#include "View3DInventorSelection.h" +#include "ViewProviderDocumentObject.h" +#include +#include +#include + +FC_LOG_LEVEL_INIT("3DViewerSelection",true,true) + +using namespace Gui; + +View3DInventorSelection::View3DInventorSelection(SoFCUnifiedSelection* root) + : selectionRoot(root) +{ + selectionRoot->ref(); + + pcGroupOnTop = new SoSeparator; + pcGroupOnTop->ref(); + root->addChild(pcGroupOnTop); + + auto pcGroupOnTopPickStyle = new SoPickStyle; + pcGroupOnTopPickStyle->style = SoPickStyle::UNPICKABLE; + pcGroupOnTopPickStyle->setOverride(true); + pcGroupOnTop->addChild(pcGroupOnTopPickStyle); + + coin_setenv("COIN_SEPARATE_DIFFUSE_TRANSPARENCY_OVERRIDE", "1", TRUE); + auto pcOnTopMaterial = new SoMaterial; + pcOnTopMaterial->transparency = 0.5; + pcOnTopMaterial->diffuseColor.setIgnored(true); + pcOnTopMaterial->setOverride(true); + pcGroupOnTop->addChild(pcOnTopMaterial); + + { + auto selRoot = new SoFCSelectionRoot; + selRoot->selectionStyle = SoFCSelectionRoot::PassThrough; + pcGroupOnTopSel = selRoot; + pcGroupOnTopSel->setName("GroupOnTopSel"); + pcGroupOnTopSel->ref(); + pcGroupOnTop->addChild(pcGroupOnTopSel); + } + + { + auto selRoot = new SoFCSelectionRoot; + selRoot->selectionStyle = SoFCSelectionRoot::PassThrough; + pcGroupOnTopPreSel = selRoot; + pcGroupOnTopPreSel->setName("GroupOnTopPreSel"); + pcGroupOnTopPreSel->ref(); + pcGroupOnTop->addChild(pcGroupOnTopPreSel); + } +} + +View3DInventorSelection::~View3DInventorSelection() +{ + selectionRoot->unref(); + pcGroupOnTop->unref(); + pcGroupOnTopPreSel->unref(); + pcGroupOnTopSel->unref(); +} + +void View3DInventorSelection::checkGroupOnTop(const SelectionChanges &Reason) +{ + if (Reason.Type == SelectionChanges::SetSelection || Reason.Type == SelectionChanges::ClrSelection) { + clearGroupOnTop(); + if(Reason.Type == SelectionChanges::ClrSelection) + return; + } + if(Reason.Type == SelectionChanges::RmvPreselect || + Reason.Type == SelectionChanges::RmvPreselectSignal) + { + SoSelectionElementAction action(SoSelectionElementAction::None,true); + action.apply(pcGroupOnTopPreSel); + coinRemoveAllChildren(pcGroupOnTopPreSel); + objectsOnTopPreSel.clear(); + return; + } + if(!getDocument() || !Reason.pDocName || !Reason.pDocName[0] || !Reason.pObjectName) + return; + auto obj = getDocument()->getDocument()->getObject(Reason.pObjectName); + if(!obj || !obj->getNameInDocument()) + return; + std::string key(obj->getNameInDocument()); + key += '.'; + auto subname = Reason.pSubName; + if(subname) + key += subname; + if(Reason.Type == SelectionChanges::RmvSelection) { + auto &objs = objectsOnTop; + auto pcGroup = pcGroupOnTopSel; + auto it = objs.find(key.c_str()); + if(it == objs.end()) + return; + int index = pcGroup->findChild(it->second); + if(index >= 0) { + auto node = static_cast(it->second); + SoSelectionElementAction action(node->getDetail()? + SoSelectionElementAction::Remove:SoSelectionElementAction::None,true); + auto path = node->getPath(); + SoTempPath tmpPath(2 + (path ? path->getLength() : 0)); + tmpPath.ref(); + tmpPath.append(pcGroup); + tmpPath.append(node); + tmpPath.append(node->getPath()); + action.setElement(node->getDetail()); + action.apply(&tmpPath); + tmpPath.unrefNoDelete(); + pcGroup->removeChild(index); + FC_LOG("remove annotation " << Reason.Type << " " << key); + }else + FC_LOG("remove annotation object " << Reason.Type << " " << key); + objs.erase(it); + return; + } + + auto &objs = Reason.Type==SelectionChanges::SetPreselect?objectsOnTopPreSel:objectsOnTop; + auto pcGroup = Reason.Type==SelectionChanges::SetPreselect?pcGroupOnTopPreSel:pcGroupOnTopSel; + + if(objs.find(key.c_str())!=objs.end()) + return; + auto vp = dynamic_cast( + Application::Instance->getViewProvider(obj)); + if(!vp || !vp->isSelectable() || !vp->isShow()) + return; + auto svp = vp; + if(subname && *subname) { + auto sobj = obj->getSubObject(subname); + if(!sobj || !sobj->getNameInDocument()) + return; + if(sobj!=obj) { + svp = dynamic_cast( + Application::Instance->getViewProvider(sobj)); + if(!svp || !svp->isSelectable()) + return; + } + } + int onTop; + // onTop==2 means on top only if whole object is selected, + // onTop==3 means on top only if some sub-element is selected + // onTop==1 means either + if(Gui::Selection().needPickedList()) + onTop = 1; + else if(vp->OnTopWhenSelected.getValue()) + onTop = vp->OnTopWhenSelected.getValue(); + else + onTop = svp->OnTopWhenSelected.getValue(); + if(Reason.Type == SelectionChanges::SetPreselect) { + SoHighlightElementAction action; + action.setHighlighted(true); + action.setColor(selectionRoot->colorHighlight.getValue()); + action.apply(pcGroupOnTopPreSel); + if(!onTop) + onTop = 2; + }else { + if(!onTop) + return; + SoSelectionElementAction action(SoSelectionElementAction::All); + action.setColor(selectionRoot->colorHighlight.getValue()); + action.apply(pcGroupOnTopSel); + } + if(onTop==2 || onTop==3) { + if(subname && *subname) { + size_t len = strlen(subname); + if(subname[len-1]=='.') { + // ending with '.' means whole object selection + if(onTop == 3) + return; + }else if(onTop==2) + return; + }else if(onTop==3) + return; + } + + std::vector groups; + auto grpVp = vp; + for(auto childVp=vp;;childVp=grpVp) { + auto grp = App::GeoFeatureGroupExtension::getGroupOfObject(childVp->getObject()); + if(!grp || !grp->getNameInDocument()) break; + grpVp = dynamic_cast( + Application::Instance->getViewProvider(grp)); + if(!grpVp) break; + auto childRoot = grpVp->getChildRoot(); + auto modeSwitch = grpVp->getModeSwitch(); + auto idx = modeSwitch->whichChild.getValue(); + if(idx<0 || idx>=modeSwitch->getNumChildren() || + modeSwitch->getChild(idx)!=childRoot) + { + FC_LOG("skip " << obj->getFullName() << '.' << (subname?subname:"") + << ", hidden inside geo group"); + return; + } + if(childRoot->findChild(childVp->getRoot())<0) { + FC_LOG("cannot find '" << childVp->getObject()->getFullName() + << "' in geo group '" << grp->getNameInDocument() << "'"); + break; + } + groups.push_back(grpVp); + } + + SoTempPath path(10); + path.ref(); + + for(auto it=groups.rbegin();it!=groups.rend();++it) { + auto grpVp = *it; + path.append(grpVp->getRoot()); + path.append(grpVp->getModeSwitch()); + path.append(grpVp->getChildRoot()); + } + + SoDetail *det = nullptr; + if(vp->getDetailPath(subname, &path,true,det) && path.getLength()) { + auto node = new SoFCPathAnnotation; + node->setPath(&path); + pcGroup->addChild(node); + if(det) { + SoSelectionElementAction action(SoSelectionElementAction::Append,true); + action.setElement(det); + SoTempPath tmpPath(path.getLength()+2); + tmpPath.ref(); + tmpPath.append(pcGroup); + tmpPath.append(node); + tmpPath.append(&path); + action.apply(&tmpPath); + tmpPath.unrefNoDelete(); + node->setDetail(det); + det = nullptr; + } + FC_LOG("add annotation " << Reason.Type << " " << key); + objs[key.c_str()] = node; + } + delete det; + path.unrefNoDelete(); +} + +void View3DInventorSelection::clearGroupOnTop() +{ + if(!objectsOnTop.empty() || !objectsOnTopPreSel.empty()) { + objectsOnTop.clear(); + objectsOnTopPreSel.clear(); + SoSelectionElementAction action(SoSelectionElementAction::None,true); + action.apply(pcGroupOnTopPreSel); + action.apply(pcGroupOnTopSel); + coinRemoveAllChildren(pcGroupOnTopSel); + coinRemoveAllChildren(pcGroupOnTopPreSel); + FC_LOG("clear annotation"); + } +} diff --git a/src/Gui/View3DInventorSelection.h b/src/Gui/View3DInventorSelection.h new file mode 100644 index 0000000000..523258d5da --- /dev/null +++ b/src/Gui/View3DInventorSelection.h @@ -0,0 +1,67 @@ +/**************************************************************************** + * Copyright (c) 2022 Zheng Lei (realthunder) * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ****************************************************************************/ + +#ifndef GUI_VIEW3DINVENTORSELECTION_H +#define GUI_VIEW3DINVENTORSELECTION_H + +#include +#include +#include + +class SoGroup; +class SoNode; +class SoSeparator; + +namespace Gui { + +class Document; +class SoFCUnifiedSelection; + +class GuiExport View3DInventorSelection +{ +public: + View3DInventorSelection(SoFCUnifiedSelection* root); + ~View3DInventorSelection(); + + void setDocument(Gui::Document *pcDocument) { + guiDocument = pcDocument; + } + Gui::Document* getDocument() const { + return guiDocument; + } + + void checkGroupOnTop(const SelectionChanges &Reason); + void clearGroupOnTop(); + +private: + SoGroup * pcGroupOnTop; + SoGroup * pcGroupOnTopSel; + SoGroup * pcGroupOnTopPreSel; + SoFCUnifiedSelection* selectionRoot; + std::map objectsOnTop; + std::map objectsOnTopPreSel; + Gui::Document* guiDocument = nullptr; +}; + +} //namespace Gui + +#endif // GUI_VIEW3DINVENTORSELECTION_H diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index acd47464d3..4438a37348 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -427,34 +427,7 @@ void View3DInventorViewer::init() pcViewProviderRoot->addChild(cb); #endif - pcGroupOnTop = new SoSeparator; - pcGroupOnTop->ref(); - pcViewProviderRoot->addChild(pcGroupOnTop); - - auto pcGroupOnTopPickStyle = new SoPickStyle; - pcGroupOnTopPickStyle->style = SoPickStyle::UNPICKABLE; - pcGroupOnTopPickStyle->setOverride(true); - pcGroupOnTop->addChild(pcGroupOnTopPickStyle); - - coin_setenv("COIN_SEPARATE_DIFFUSE_TRANSPARENCY_OVERRIDE", "1", TRUE); - auto pcOnTopMaterial = new SoMaterial; - pcOnTopMaterial->transparency = 0.5; - pcOnTopMaterial->diffuseColor.setIgnored(true); - pcOnTopMaterial->setOverride(true); - pcGroupOnTop->addChild(pcOnTopMaterial); - - auto selRoot = new SoFCSelectionRoot; - selRoot->selectionStyle = SoFCSelectionRoot::PassThrough; - pcGroupOnTopSel = selRoot; - pcGroupOnTopSel->setName("GroupOnTopSel"); - pcGroupOnTopSel->ref(); - pcGroupOnTop->addChild(pcGroupOnTopSel); - selRoot = new SoFCSelectionRoot; - selRoot->selectionStyle = SoFCSelectionRoot::PassThrough; - pcGroupOnTopPreSel = selRoot; - pcGroupOnTopPreSel->setName("GroupOnTopPreSel"); - pcGroupOnTopPreSel->ref(); - pcGroupOnTop->addChild(pcGroupOnTopPreSel); + inventorSelection = std::make_unique(selectionRoot); pcClipPlane = nullptr; @@ -558,14 +531,12 @@ View3DInventorViewer::~View3DInventorViewer() this->backlight->unref(); this->backlight = nullptr; - this->pcGroupOnTop->unref(); - this->pcGroupOnTopPreSel->unref(); - this->pcGroupOnTopSel->unref(); + inventorSelection.reset(nullptr); this->pcEditingRoot->unref(); this->pcEditingTransform->unref(); - if(this->pcClipPlane) + if (this->pcClipPlane) this->pcClipPlane->unref(); delete this->navigation; @@ -639,6 +610,7 @@ void View3DInventorViewer::setDocument(Gui::Document* pcDocument) // write the document the viewer belongs to the selection node guiDocument = pcDocument; selectionRoot->pcDocument = pcDocument; + inventorSelection->setDocument(pcDocument); if(pcDocument) { const auto &sels = Selection().getSelection(pcDocument->getDocument()->getName(), ResolveMode::NoResolve); @@ -664,191 +636,6 @@ void View3DInventorViewer::initialize() this->axiscrossSize = 10; } -void View3DInventorViewer::clearGroupOnTop() { - if(!objectsOnTop.empty() || !objectsOnTopPreSel.empty()) { - objectsOnTop.clear(); - objectsOnTopPreSel.clear(); - SoSelectionElementAction action(SoSelectionElementAction::None,true); - action.apply(pcGroupOnTopPreSel); - action.apply(pcGroupOnTopSel); - coinRemoveAllChildren(pcGroupOnTopSel); - coinRemoveAllChildren(pcGroupOnTopPreSel); - FC_LOG("clear annotation"); - } -} - -void View3DInventorViewer::checkGroupOnTop(const SelectionChanges &Reason) { - if(Reason.Type == SelectionChanges::SetSelection || Reason.Type == SelectionChanges::ClrSelection) { - clearGroupOnTop(); - if(Reason.Type == SelectionChanges::ClrSelection) - return; - } - if(Reason.Type == SelectionChanges::RmvPreselect || - Reason.Type == SelectionChanges::RmvPreselectSignal) - { - SoSelectionElementAction action(SoSelectionElementAction::None,true); - action.apply(pcGroupOnTopPreSel); - coinRemoveAllChildren(pcGroupOnTopPreSel); - objectsOnTopPreSel.clear(); - return; - } - if(!getDocument() || !Reason.pDocName || !Reason.pDocName[0] || !Reason.pObjectName) - return; - auto obj = getDocument()->getDocument()->getObject(Reason.pObjectName); - if(!obj || !obj->getNameInDocument()) - return; - std::string key(obj->getNameInDocument()); - key += '.'; - auto subname = Reason.pSubName; - if(subname) - key += subname; - if(Reason.Type == SelectionChanges::RmvSelection) { - auto &objs = objectsOnTop; - auto pcGroup = pcGroupOnTopSel; - auto it = objs.find(key.c_str()); - if(it == objs.end()) - return; - int index = pcGroup->findChild(it->second); - if(index >= 0) { - auto node = static_cast(it->second); - SoSelectionElementAction action(node->getDetail()? - SoSelectionElementAction::Remove:SoSelectionElementAction::None,true); - auto path = node->getPath(); - SoTempPath tmpPath(2 + (path ? path->getLength() : 0)); - tmpPath.ref(); - tmpPath.append(pcGroup); - tmpPath.append(node); - tmpPath.append(node->getPath()); - action.setElement(node->getDetail()); - action.apply(&tmpPath); - tmpPath.unrefNoDelete(); - pcGroup->removeChild(index); - FC_LOG("remove annotation " << Reason.Type << " " << key); - }else - FC_LOG("remove annotation object " << Reason.Type << " " << key); - objs.erase(it); - return; - } - - auto &objs = Reason.Type==SelectionChanges::SetPreselect?objectsOnTopPreSel:objectsOnTop; - auto pcGroup = Reason.Type==SelectionChanges::SetPreselect?pcGroupOnTopPreSel:pcGroupOnTopSel; - - if(objs.find(key.c_str())!=objs.end()) - return; - auto vp = dynamic_cast( - Application::Instance->getViewProvider(obj)); - if(!vp || !vp->isSelectable() || !vp->isShow()) - return; - auto svp = vp; - if(subname && *subname) { - auto sobj = obj->getSubObject(subname); - if(!sobj || !sobj->getNameInDocument()) - return; - if(sobj!=obj) { - svp = dynamic_cast( - Application::Instance->getViewProvider(sobj)); - if(!svp || !svp->isSelectable()) - return; - } - } - int onTop; - // onTop==2 means on top only if whole object is selected, - // onTop==3 means on top only if some sub-element is selected - // onTop==1 means either - if(Gui::Selection().needPickedList()) - onTop = 1; - else if(vp->OnTopWhenSelected.getValue()) - onTop = vp->OnTopWhenSelected.getValue(); - else - onTop = svp->OnTopWhenSelected.getValue(); - if(Reason.Type == SelectionChanges::SetPreselect) { - SoHighlightElementAction action; - action.setHighlighted(true); - action.setColor(selectionRoot->colorHighlight.getValue()); - action.apply(pcGroupOnTopPreSel); - if(!onTop) - onTop = 2; - }else { - if(!onTop) - return; - SoSelectionElementAction action(SoSelectionElementAction::All); - action.setColor(selectionRoot->colorSelection.getValue()); - action.apply(pcGroupOnTopSel); - } - if(onTop==2 || onTop==3) { - if(subname && *subname) { - size_t len = strlen(subname); - if(subname[len-1]=='.') { - // ending with '.' means whole object selection - if(onTop == 3) - return; - }else if(onTop==2) - return; - }else if(onTop==3) - return; - } - - std::vector groups; - auto grpVp = vp; - for(auto childVp=vp;;childVp=grpVp) { - auto grp = App::GeoFeatureGroupExtension::getGroupOfObject(childVp->getObject()); - if(!grp || !grp->getNameInDocument()) break; - grpVp = dynamic_cast( - Application::Instance->getViewProvider(grp)); - if(!grpVp) break; - auto childRoot = grpVp->getChildRoot(); - auto modeSwitch = grpVp->getModeSwitch(); - auto idx = modeSwitch->whichChild.getValue(); - if(idx<0 || idx>=modeSwitch->getNumChildren() || - modeSwitch->getChild(idx)!=childRoot) - { - FC_LOG("skip " << obj->getFullName() << '.' << (subname?subname:"") - << ", hidden inside geo group"); - return; - } - if(childRoot->findChild(childVp->getRoot())<0) { - FC_LOG("cannot find '" << childVp->getObject()->getFullName() - << "' in geo group '" << grp->getNameInDocument() << "'"); - break; - } - groups.push_back(grpVp); - } - - SoTempPath path(10); - path.ref(); - - for(auto it=groups.rbegin();it!=groups.rend();++it) { - auto grpVp = *it; - path.append(grpVp->getRoot()); - path.append(grpVp->getModeSwitch()); - path.append(grpVp->getChildRoot()); - } - - SoDetail *det = nullptr; - if(vp->getDetailPath(subname, &path,true,det) && path.getLength()) { - auto node = new SoFCPathAnnotation; - node->setPath(&path); - pcGroup->addChild(node); - if(det) { - SoSelectionElementAction action(SoSelectionElementAction::Append,true); - action.setElement(det); - SoTempPath tmpPath(path.getLength()+2); - tmpPath.ref(); - tmpPath.append(pcGroup); - tmpPath.append(node); - tmpPath.append(&path); - action.apply(&tmpPath); - tmpPath.unrefNoDelete(); - node->setDetail(det); - det = nullptr; - } - FC_LOG("add annotation " << Reason.Type << " " << key); - objs[key.c_str()] = node; - } - delete det; - path.unrefNoDelete(); -} - /// @cond DOXERR void View3DInventorViewer::onSelectionChanged(const SelectionChanges &_Reason) { @@ -879,7 +666,7 @@ void View3DInventorViewer::onSelectionChanged(const SelectionChanges &_Reason) case SelectionChanges::AddSelection: case SelectionChanges::RmvSelection: case SelectionChanges::ClrSelection: - checkGroupOnTop(Reason); + inventorSelection->checkGroupOnTop(Reason); break; case SelectionChanges::SetPreselectSignal: break; diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h index 60410bfadb..ea952d806b 100644 --- a/src/Gui/View3DInventorViewer.h +++ b/src/Gui/View3DInventorViewer.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -40,6 +41,7 @@ #include "Namespace.h" #include "Selection.h" +#include "View3DInventorSelection.h" #include "Quarter/SoQTQuarterAdaptor.h" @@ -139,8 +141,6 @@ public: /// Observer message from the Selection void onSelectionChanged(const SelectionChanges &Reason) override; - void checkGroupOnTop(const SelectionChanges &Reason); - void clearGroupOnTop(); SoDirectionalLight* getBacklight() const; void setBacklight(SbBool on); @@ -449,11 +449,7 @@ private: SoSeparator * pcViewProviderRoot; - SoGroup * pcGroupOnTop; - SoGroup * pcGroupOnTopSel; - SoGroup * pcGroupOnTopPreSel; - std::map objectsOnTop; - std::map objectsOnTopPreSel; + std::unique_ptr inventorSelection; SoSeparator * pcEditingRoot; SoTransform * pcEditingTransform;