Gui: code-refactoring

Split selection handling from View3DInventorViewer and move to View3DInventorSelection
This commit is contained in:
wmayer
2022-11-16 20:27:14 +01:00
parent e1485388d4
commit 308cf4ffb0
5 changed files with 354 additions and 225 deletions

View File

@@ -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

View File

@@ -0,0 +1,277 @@
/****************************************************************************
* Copyright (c) 2022 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* 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 <Inventor/details/SoDetail.h>
# include <Inventor/nodes/SoMaterial.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoSeparator.h>
#endif
#include "Application.h"
#include "Document.h"
#include "SoFCUnifiedSelection.h"
#include "View3DInventorSelection.h"
#include "ViewProviderDocumentObject.h"
#include <App/Document.h>
#include <App/GeoFeatureGroupExtension.h>
#include <Base/Console.h>
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<SoFCPathAnnotation*>(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<ViewProviderDocumentObject*>(
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<ViewProviderDocumentObject*>(
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<ViewProvider*> 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<ViewProviderDocumentObject*>(
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");
}
}

View File

@@ -0,0 +1,67 @@
/****************************************************************************
* Copyright (c) 2022 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* 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 <map>
#include <string>
#include <Gui/Selection.h>
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<std::string, SoNode*> objectsOnTop;
std::map<std::string, SoNode*> objectsOnTopPreSel;
Gui::Document* guiDocument = nullptr;
};
} //namespace Gui
#endif // GUI_VIEW3DINVENTORSELECTION_H

View File

@@ -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<View3DInventorSelection>(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<SoFCPathAnnotation*>(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<ViewProviderDocumentObject*>(
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<ViewProviderDocumentObject*>(
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<ViewProvider*> 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<ViewProviderDocumentObject*>(
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;

View File

@@ -26,6 +26,7 @@
#include <list>
#include <map>
#include <memory>
#include <set>
#include <vector>
@@ -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<std::string,SoNode*> objectsOnTop;
std::map<std::string,SoNode*> objectsOnTopPreSel;
std::unique_ptr<View3DInventorSelection> inventorSelection;
SoSeparator * pcEditingRoot;
SoTransform * pcEditingTransform;