/**************************************************************************** * 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; std::set visited; 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; } // avoid endless-loops if (!visited.insert(childVp).second) { 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"); } }