| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <FCConfig.h>
|
| |
|
| | #include <Inventor/SoFullPath.h>
|
| | #include <Inventor/SoPickedPoint.h>
|
| | #include <Inventor/actions/SoCallbackAction.h>
|
| | #include <Inventor/actions/SoGetBoundingBoxAction.h>
|
| | #include <Inventor/actions/SoGetPrimitiveCountAction.h>
|
| | #include <Inventor/actions/SoGLRenderAction.h>
|
| | #include <Inventor/actions/SoHandleEventAction.h>
|
| | #include <Inventor/actions/SoWriteAction.h>
|
| | #include <Inventor/bundles/SoMaterialBundle.h>
|
| | #include <Inventor/details/SoFaceDetail.h>
|
| | #include <Inventor/details/SoLineDetail.h>
|
| | #include <Inventor/elements/SoCacheElement.h>
|
| | #include <Inventor/elements/SoCoordinateElement.h>
|
| | #include <Inventor/elements/SoDrawStyleElement.h>
|
| | #include <Inventor/elements/SoGLCacheContextElement.h>
|
| | #include <Inventor/elements/SoLazyElement.h>
|
| | #include <Inventor/elements/SoLineWidthElement.h>
|
| | #include <Inventor/elements/SoMaterialBindingElement.h>
|
| | #include <Inventor/elements/SoModelMatrixElement.h>
|
| | #include <Inventor/elements/SoOverrideElement.h>
|
| | #include <Inventor/elements/SoShapeStyleElement.h>
|
| | #include <Inventor/elements/SoSwitchElement.h>
|
| | #include <Inventor/elements/SoTextureEnabledElement.h>
|
| | #include <Inventor/events/SoLocation2Event.h>
|
| | #include <Inventor/events/SoMouseButtonEvent.h>
|
| | #include <Inventor/misc/SoChildList.h>
|
| | #include <Inventor/misc/SoState.h>
|
| | #include <Inventor/nodes/SoCoordinate3.h>
|
| | #include <Inventor/nodes/SoCube.h>
|
| | #include <Inventor/nodes/SoIndexedFaceSet.h>
|
| | #include <Inventor/nodes/SoIndexedLineSet.h>
|
| | #include <Inventor/nodes/SoMaterial.h>
|
| | #include <Inventor/nodes/SoMaterialBinding.h>
|
| | #include <Inventor/nodes/SoNormalBinding.h>
|
| | #include <Inventor/nodes/SoPointSet.h>
|
| | #include <Inventor/threads/SbStorage.h>
|
| |
|
| |
|
| | #ifdef FC_OS_MACOSX
|
| | # include <OpenGL/gl.h>
|
| | #else
|
| | # ifdef FC_OS_WIN32
|
| | # include <windows.h>
|
| | # endif
|
| | # include <GL/gl.h>
|
| | #endif
|
| |
|
| | #include <QOpenGLWidget>
|
| |
|
| | #include <App/Document.h>
|
| | #include <App/GeoFeature.h>
|
| | #include <App/ElementNamingUtils.h>
|
| | #include <Base/Tools.h>
|
| | #include <Base/UnitsApi.h>
|
| |
|
| | #include "SoFCUnifiedSelection.h"
|
| | #include "Application.h"
|
| | #include "Document.h"
|
| | #include "DocumentObserver.h"
|
| | #include "MainWindow.h"
|
| | #include "SoFCInteractiveElement.h"
|
| | #include "SoFCSelectionAction.h"
|
| | #include "ViewParams.h"
|
| | #include "ViewProvider.h"
|
| | #include "ViewProviderDocumentObject.h"
|
| |
|
| |
|
| | FC_LOG_LEVEL_INIT("SoFCUnifiedSelection", false, true, true)
|
| |
|
| | using namespace Gui;
|
| |
|
| | namespace Gui
|
| | {
|
| | void printPreselectionInfo(
|
| | const char* documentName,
|
| | const char* objectName,
|
| | const char* subElementName,
|
| | float x,
|
| | float y,
|
| | float z,
|
| | double precision
|
| | );
|
| | }
|
| |
|
| | SoFullPath* Gui::SoFCUnifiedSelection::currentHighlightPath = nullptr;
|
| |
|
| |
|
| |
|
| | SO_NODE_SOURCE(SoFCUnifiedSelection)
|
| |
|
| | |
| | |
| |
|
| | SoFCUnifiedSelection::SoFCUnifiedSelection()
|
| | {
|
| | SO_NODE_CONSTRUCTOR(SoFCUnifiedSelection);
|
| |
|
| | SO_NODE_ADD_FIELD(colorHighlight, (SbColor(1.0f, 0.6f, 0.0f)));
|
| | SO_NODE_ADD_FIELD(colorSelection, (SbColor(0.1f, 0.8f, 0.1f)));
|
| | SO_NODE_ADD_FIELD(preselectionMode, (AUTO));
|
| | SO_NODE_ADD_FIELD(selectionMode, (ON));
|
| | SO_NODE_ADD_FIELD(selectionEnabled, (true));
|
| | SO_NODE_ADD_FIELD(useNewSelection, (true));
|
| |
|
| | SO_NODE_DEFINE_ENUM_VALUE(PreselectionModes, AUTO);
|
| | SO_NODE_DEFINE_ENUM_VALUE(PreselectionModes, ON);
|
| | SO_NODE_DEFINE_ENUM_VALUE(PreselectionModes, OFF);
|
| | SO_NODE_SET_SF_ENUM_TYPE(preselectionMode, PreselectionModes);
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | detailPath = static_cast<SoFullPath*>(new SoPath(20));
|
| | detailPath->ref();
|
| |
|
| | setPreSelection = false;
|
| | preSelection = -1;
|
| | useNewSelection = ViewParams::instance()->getUseNewSelection();
|
| | }
|
| |
|
| | |
| | |
| |
|
| | SoFCUnifiedSelection::~SoFCUnifiedSelection()
|
| | {
|
| |
|
| |
|
| | if (currentHighlightPath) {
|
| | currentHighlightPath->unref();
|
| | currentHighlightPath = nullptr;
|
| | }
|
| | if (detailPath) {
|
| | detailPath->unref();
|
| | detailPath = nullptr;
|
| | }
|
| | }
|
| |
|
| |
|
| | void SoFCUnifiedSelection::initClass()
|
| | {
|
| | SO_NODE_INIT_CLASS(SoFCUnifiedSelection, SoSeparator, "Separator");
|
| | }
|
| |
|
| | void SoFCUnifiedSelection::finish()
|
| | {
|
| | atexit_cleanup();
|
| | }
|
| |
|
| | bool SoFCUnifiedSelection::hasHighlight()
|
| | {
|
| | return currentHighlightPath != nullptr;
|
| | }
|
| |
|
| | void SoFCUnifiedSelection::applySettings()
|
| | {
|
| | float transparency;
|
| | ParameterGrp::handle hGrp = Gui::WindowParameter::getDefaultParameter()->GetGroup("View");
|
| | bool enablePreselection = hGrp->GetBool("EnablePreselection", true);
|
| | if (!enablePreselection) {
|
| | this->preselectionMode = SoFCUnifiedSelection::OFF;
|
| | }
|
| | else {
|
| |
|
| | SbColor highlightColor = this->colorHighlight.getValue();
|
| | auto highlight = (unsigned long)(highlightColor.getPackedValue());
|
| | highlight = hGrp->GetUnsigned("HighlightColor", highlight);
|
| | highlightColor.setPackedValue((uint32_t)highlight, transparency);
|
| | this->colorHighlight.setValue(highlightColor);
|
| | }
|
| |
|
| | bool enableSelection = hGrp->GetBool("EnableSelection", true);
|
| | if (!enableSelection) {
|
| | this->selectionMode = SoFCUnifiedSelection::OFF;
|
| | }
|
| | else {
|
| |
|
| | SbColor selectionColor = this->colorSelection.getValue();
|
| | auto selection = (unsigned long)(selectionColor.getPackedValue());
|
| | selection = hGrp->GetUnsigned("SelectionColor", selection);
|
| | selectionColor.setPackedValue((uint32_t)selection, transparency);
|
| | this->colorSelection.setValue(selectionColor);
|
| | }
|
| | }
|
| |
|
| | const char* SoFCUnifiedSelection::getFileFormatName() const
|
| | {
|
| | return "Separator";
|
| | }
|
| |
|
| | void SoFCUnifiedSelection::write(SoWriteAction* action)
|
| | {
|
| | SoOutput* out = action->getOutput();
|
| | if (out->getStage() == SoOutput::WRITE) {
|
| |
|
| | if (this->writeHeader(out, true, false)) {
|
| | return;
|
| | }
|
| | SoGroup::doAction(static_cast<SoAction*>(action));
|
| | this->writeFooter(out);
|
| | }
|
| | else {
|
| | inherited::write(action);
|
| | }
|
| | }
|
| |
|
| | int SoFCUnifiedSelection::getPriority(const SoPickedPoint* p)
|
| | {
|
| | const SoDetail* detail = p->getDetail();
|
| | if (!detail) {
|
| | return 0;
|
| | }
|
| | if (detail->isOfType(SoFaceDetail::getClassTypeId())) {
|
| | return 1;
|
| | }
|
| | if (detail->isOfType(SoLineDetail::getClassTypeId())) {
|
| | return 2;
|
| | }
|
| | if (detail->isOfType(SoPointDetail::getClassTypeId())) {
|
| | return 3;
|
| | }
|
| | return 0;
|
| | }
|
| |
|
| | std::vector<SoFCUnifiedSelection::PickedInfo> SoFCUnifiedSelection::getPickedList(
|
| | SoHandleEventAction* action,
|
| | bool singlePick
|
| | ) const
|
| | {
|
| | ViewProvider* last_vp = nullptr;
|
| | std::vector<PickedInfo> ret;
|
| | const SoPickedPointList& points = action->getPickedPointList();
|
| | for (int i = 0, count = points.getLength(); i < count; ++i) {
|
| | PickedInfo info;
|
| | info.pp = points[i];
|
| | info.vpd = nullptr;
|
| | ViewProvider* vp = nullptr;
|
| | auto path = static_cast<SoFullPath*>(info.pp->getPath());
|
| | if (this->pcDocument && path && path->containsPath(action->getCurPath())) {
|
| | vp = this->pcDocument->getViewProviderByPathFromHead(path);
|
| | if (singlePick && last_vp && last_vp != vp) {
|
| | return ret;
|
| | }
|
| | }
|
| | if (!vp || !vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
|
| | if (!singlePick) {
|
| | continue;
|
| | }
|
| | if (ret.empty()) {
|
| | ret.push_back(info);
|
| | }
|
| | break;
|
| | }
|
| | info.vpd = static_cast<ViewProviderDocumentObject*>(vp);
|
| | if (!(useNewSelection.getValue() || info.vpd->useNewSelectionModel())
|
| | || !info.vpd->isSelectable()) {
|
| | if (!singlePick) {
|
| | continue;
|
| | }
|
| | if (ret.empty()) {
|
| | info.vpd = nullptr;
|
| | ret.push_back(info);
|
| | }
|
| | break;
|
| | }
|
| | if (!info.vpd->getElementPicked(info.pp, info.element)) {
|
| | continue;
|
| | }
|
| |
|
| | if (singlePick) {
|
| | last_vp = vp;
|
| | }
|
| | ret.push_back(info);
|
| | }
|
| |
|
| | if (ret.size() <= 1) {
|
| | return ret;
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | int picked_prio = getPriority(ret[0].pp);
|
| | auto last_vpd = ret[0].vpd;
|
| | const SbVec3f& picked_pt = ret.front().pp->getPoint();
|
| | auto itPicked = ret.begin();
|
| | for (auto it = ret.begin() + 1; it != ret.end(); ++it) {
|
| | auto& info = *it;
|
| | if (last_vpd != info.vpd) {
|
| | break;
|
| | }
|
| |
|
| | int cur_prio = getPriority(info.pp);
|
| | const SbVec3f& cur_pt = info.pp->getPoint();
|
| |
|
| | if ((cur_prio > picked_prio) && picked_pt.equals(cur_pt, 0.2F)) {
|
| | itPicked = it;
|
| | picked_prio = cur_prio;
|
| | }
|
| | }
|
| |
|
| | if (singlePick) {
|
| | std::vector<PickedInfo> sret(itPicked, itPicked + 1);
|
| | return sret;
|
| | }
|
| | if (itPicked != ret.begin()) {
|
| | std::swap(*itPicked, *ret.begin());
|
| | }
|
| | return ret;
|
| | }
|
| |
|
| | void SoFCUnifiedSelection::doAction(SoAction* action)
|
| | {
|
| | if (action->getTypeId() == SoFCEnablePreselectionAction::getClassTypeId()) {
|
| | auto enablePreselectionAction = static_cast<SoFCEnablePreselectionAction*>(action);
|
| | if (enablePreselectionAction->enabled) {
|
| | this->preselectionMode = SoFCUnifiedSelection::AUTO;
|
| | }
|
| | else {
|
| | this->preselectionMode = SoFCUnifiedSelection::OFF;
|
| | }
|
| | }
|
| |
|
| | if (action->getTypeId() == SoFCEnableSelectionAction::getClassTypeId()) {
|
| | auto enableSelectionAction = static_cast<SoFCEnableSelectionAction*>(action);
|
| | if (enableSelectionAction->enabled) {
|
| | this->selectionMode = SoFCUnifiedSelection::ON;
|
| | }
|
| | else {
|
| | this->selectionMode = SoFCUnifiedSelection::OFF;
|
| | }
|
| | }
|
| |
|
| | if (action->getTypeId() == SoFCSelectionColorAction::getClassTypeId()) {
|
| | auto selectionColorAction = static_cast<SoFCSelectionColorAction*>(action);
|
| | this->colorSelection = selectionColorAction->selectionColor;
|
| | }
|
| |
|
| | if (action->getTypeId() == SoFCHighlightColorAction::getClassTypeId()) {
|
| | auto highlightColorAction = static_cast<SoFCHighlightColorAction*>(action);
|
| | this->colorHighlight = highlightColorAction->highlightColor;
|
| | }
|
| |
|
| | if (action->getTypeId() == SoFCPreselectionAction::getClassTypeId()) {
|
| | auto preselectAction = static_cast<SoFCPreselectionAction*>(action);
|
| |
|
| | if (!setPreSelection && preselectAction->SelChange.Type == SelectionChanges::RmvPreselect) {
|
| | if (currentHighlightPath) {
|
| | SoHighlightElementAction highlightAction;
|
| | highlightAction.apply(currentHighlightPath);
|
| | currentHighlightPath->unref();
|
| | currentHighlightPath = nullptr;
|
| | }
|
| | }
|
| | else if (preselectionMode.getValue() != OFF
|
| | && preselectAction->SelChange.Type == SelectionChanges::SetPreselect) {
|
| | if (currentHighlightPath) {
|
| | SoHighlightElementAction highlightAction;
|
| | highlightAction.apply(currentHighlightPath);
|
| | currentHighlightPath->unref();
|
| | currentHighlightPath = nullptr;
|
| | }
|
| |
|
| | App::Document* doc = App::GetApplication().getDocument(preselectAction->SelChange.pDocName);
|
| | App::DocumentObject* obj = doc->getObject(preselectAction->SelChange.pObjectName);
|
| | ViewProvider* vp = Application::Instance->getViewProvider(obj);
|
| |
|
| |
|
| | SoDetail* detail = nullptr;
|
| | detailPath->truncate(0);
|
| | auto subName = preselectAction->SelChange.pSubName;
|
| |
|
| | SoFullPath* pathToHighlight = nullptr;
|
| | if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())
|
| | && (useNewSelection.getValue() || vp->useNewSelectionModel()) && vp->isSelectable()) {
|
| |
|
| |
|
| | if (!subName || !subName[0] || vp->getDetailPath(subName, detailPath, true, detail)) {
|
| | if (detailPath->getLength()) {
|
| | pathToHighlight = detailPath;
|
| | }
|
| | else {
|
| |
|
| | pathToHighlight = static_cast<SoFullPath*>(new SoPath(2));
|
| | pathToHighlight->ref();
|
| | pathToHighlight->append(vp->getRoot());
|
| | }
|
| | }
|
| | }
|
| | else {
|
| | detail = vp->getDetail(subName);
|
| | pathToHighlight = static_cast<SoFullPath*>(new SoPath(2));
|
| | pathToHighlight->ref();
|
| | pathToHighlight->append(vp->getRoot());
|
| | }
|
| |
|
| | if (pathToHighlight) {
|
| | SoHighlightElementAction highlightAction;
|
| | highlightAction.setHighlighted(true);
|
| | highlightAction.setColor(this->colorHighlight.getValue());
|
| | highlightAction.setElement(detail);
|
| | highlightAction.apply(pathToHighlight);
|
| |
|
| | currentHighlightPath = static_cast<SoFullPath*>(pathToHighlight->copy());
|
| | currentHighlightPath->ref();
|
| |
|
| |
|
| | if (pathToHighlight != detailPath) {
|
| | pathToHighlight->unref();
|
| | }
|
| | }
|
| |
|
| | delete detail;
|
| | }
|
| |
|
| | if (useNewSelection.getValue()) {
|
| | return;
|
| | }
|
| | }
|
| |
|
| | if (action->getTypeId() == SoFCSelectionAction::getClassTypeId()) {
|
| | auto selectionAction = static_cast<SoFCSelectionAction*>(action);
|
| | if (selectionMode.getValue() == ON
|
| | && (selectionAction->SelChange.Type == SelectionChanges::AddSelection
|
| | || selectionAction->SelChange.Type == SelectionChanges::RmvSelection)) {
|
| |
|
| | App::Document* doc = App::GetApplication().getDocument(selectionAction->SelChange.pDocName);
|
| | App::DocumentObject* obj = doc->getObject(selectionAction->SelChange.pObjectName);
|
| | ViewProvider* vp = Application::Instance->getViewProvider(obj);
|
| |
|
| |
|
| | bool isSelectable = false;
|
| | if (vp) {
|
| | if (selectionAction->SelChange.pSubName && selectionAction->SelChange.pSubName[0]) {
|
| |
|
| | auto objList = obj->getSubObjectList(selectionAction->SelChange.pSubName);
|
| |
|
| | isSelectable = true;
|
| | for (auto* checkObj : objList) {
|
| | if (auto checkVp = Application::Instance->getViewProvider(checkObj)) {
|
| | if (!checkVp->isSelectable()) {
|
| | isSelectable = false;
|
| | break;
|
| | }
|
| | }
|
| | }
|
| | }
|
| | else {
|
| | isSelectable = vp->isSelectable();
|
| | }
|
| | }
|
| |
|
| | if (vp && (useNewSelection.getValue() || vp->useNewSelectionModel()) && isSelectable) {
|
| | SoDetail* detail = nullptr;
|
| | detailPath->truncate(0);
|
| | auto subName = selectionAction->SelChange.pSubName;
|
| | App::ElementNamePair elementName;
|
| | ;
|
| | App::GeoFeature::resolveElement(obj, subName, elementName);
|
| | if (Data::isMappedElement(subName)
|
| | && !elementName.oldName.empty()) {
|
| | subName = elementName.oldName.c_str();
|
| | }
|
| | if (!selectionAction->SelChange.pSubName || !selectionAction->SelChange.pSubName[0]
|
| | || vp->getDetailPath(subName, detailPath, true, detail)) {
|
| | SoSelectionElementAction::Type type = SoSelectionElementAction::None;
|
| | if (selectionAction->SelChange.Type == SelectionChanges::AddSelection) {
|
| | if (detail) {
|
| | type = SoSelectionElementAction::Append;
|
| | }
|
| | else {
|
| | type = SoSelectionElementAction::All;
|
| | }
|
| | }
|
| | else {
|
| | if (detail) {
|
| | type = SoSelectionElementAction::Remove;
|
| | }
|
| | else {
|
| | type = SoSelectionElementAction::None;
|
| | }
|
| | }
|
| |
|
| | SoSelectionElementAction selectionAction(type);
|
| | selectionAction.setColor(this->colorSelection.getValue());
|
| | selectionAction.setElement(detail);
|
| | if (detailPath->getLength()) {
|
| | selectionAction.apply(detailPath);
|
| | }
|
| | else {
|
| | selectionAction.apply(vp->getRoot());
|
| | }
|
| | }
|
| | detailPath->truncate(0);
|
| | delete detail;
|
| | }
|
| | }
|
| | else if (selectionAction->SelChange.Type == SelectionChanges::ClrSelection) {
|
| | SoSelectionElementAction selectionAction(SoSelectionElementAction::None);
|
| | for (int i = 0; i < this->getNumChildren(); ++i) {
|
| | selectionAction.apply(this->getChild(i));
|
| | }
|
| | }
|
| | else if (selectionMode.getValue() == ON
|
| | && selectionAction->SelChange.Type == SelectionChanges::SetSelection) {
|
| | std::vector<ViewProvider*> vps;
|
| | if (this->pcDocument) {
|
| | vps = this->pcDocument->getViewProvidersOfType(
|
| | ViewProviderDocumentObject::getClassTypeId()
|
| | );
|
| | }
|
| | for (const auto& vp : vps) {
|
| | auto vpd = static_cast<ViewProviderDocumentObject*>(vp);
|
| | if (useNewSelection.getValue() || vpd->useNewSelectionModel()) {
|
| | SoSelectionElementAction::Type type;
|
| | if (Selection().isSelected(vpd->getObject()) && vpd->isSelectable()) {
|
| | type = SoSelectionElementAction::All;
|
| | }
|
| | else {
|
| | type = SoSelectionElementAction::None;
|
| | }
|
| |
|
| | SoSelectionElementAction selectionAction(type);
|
| | selectionAction.setColor(this->colorSelection.getValue());
|
| | selectionAction.apply(vpd->getRoot());
|
| | }
|
| | }
|
| | }
|
| | else if (selectionAction->SelChange.Type == SelectionChanges::SetPreselectSignal) {
|
| |
|
| | App::Document* doc = App::GetApplication().getDocument(selectionAction->SelChange.pDocName);
|
| | App::DocumentObject* obj = doc->getObject(selectionAction->SelChange.pObjectName);
|
| | ViewProvider* vp = Application::Instance->getViewProvider(obj);
|
| | if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())
|
| | && (useNewSelection.getValue() || vp->useNewSelectionModel()) && vp->isSelectable()) {
|
| | detailPath->truncate(0);
|
| | SoDetail* det = nullptr;
|
| | if (vp->getDetailPath(selectionAction->SelChange.pSubName, detailPath, true, det)) {
|
| | setPreselect(
|
| | detailPath,
|
| | det,
|
| | static_cast<ViewProviderDocumentObject*>(vp),
|
| | selectionAction->SelChange.pSubName,
|
| | selectionAction->SelChange.x,
|
| | selectionAction->SelChange.y,
|
| | selectionAction->SelChange.z
|
| | );
|
| | }
|
| | delete det;
|
| | }
|
| | }
|
| |
|
| | if (useNewSelection.getValue()) {
|
| | return;
|
| | }
|
| | }
|
| |
|
| | inherited::doAction(action);
|
| | }
|
| |
|
| | bool SoFCUnifiedSelection::setPreselect(const PickedInfo& info)
|
| | {
|
| | if (!info.pp) {
|
| | return setPreselect(nullptr, nullptr, nullptr, nullptr, 0.0, 0.0, 0.0);
|
| | }
|
| |
|
| | const auto& pt = info.pp->getPoint();
|
| | return setPreselect(
|
| | static_cast<SoFullPath*>(info.pp->getPath()),
|
| | info.pp->getDetail(),
|
| | info.vpd,
|
| | info.element.c_str(),
|
| | pt[0],
|
| | pt[1],
|
| | pt[2]
|
| | );
|
| | }
|
| |
|
| | bool SoFCUnifiedSelection::setPreselect(
|
| | SoFullPath* path,
|
| | const SoDetail* det,
|
| | ViewProviderDocumentObject* vpd,
|
| | const char* element,
|
| | float x,
|
| | float y,
|
| | float z
|
| | )
|
| | {
|
| | Base::FlagToggler<SbBool> flag(setPreSelection);
|
| |
|
| | bool highlighted = false;
|
| | if (path && path->getLength() && vpd && vpd->getObject()
|
| | && vpd->getObject()->isAttachedToDocument()) {
|
| | const char* docname = vpd->getObject()->getDocument()->getName();
|
| | const char* objname = vpd->getObject()->getNameInDocument();
|
| |
|
| | this->preSelection = 1;
|
| |
|
| | printPreselectionInfo(docname, objname, element, x, y, z, 1e-7);
|
| |
|
| |
|
| | int ret = Gui::Selection().setPreselect(docname, objname, element, x, y, z);
|
| | if (ret < 0 && currentHighlightPath) {
|
| | return true;
|
| | }
|
| |
|
| | if (ret) {
|
| | if (currentHighlightPath) {
|
| | SoHighlightElementAction action;
|
| | action.setHighlighted(false);
|
| | action.apply(currentHighlightPath);
|
| | currentHighlightPath->unref();
|
| | currentHighlightPath = nullptr;
|
| | }
|
| | currentHighlightPath = static_cast<SoFullPath*>(path->copy());
|
| | currentHighlightPath->ref();
|
| | highlighted = true;
|
| | }
|
| | }
|
| |
|
| | if (currentHighlightPath) {
|
| | SoHighlightElementAction action;
|
| | action.setHighlighted(highlighted);
|
| | action.setColor(this->colorHighlight.getValue());
|
| | action.setElement(det);
|
| | action.apply(currentHighlightPath);
|
| | if (!highlighted) {
|
| | currentHighlightPath->unref();
|
| | currentHighlightPath = nullptr;
|
| | Selection().rmvPreselect();
|
| | }
|
| | this->touch();
|
| | }
|
| | return highlighted;
|
| | }
|
| |
|
| | bool SoFCUnifiedSelection::setSelection(const std::vector<PickedInfo>& infos, bool ctrlDown)
|
| | {
|
| | if (infos.empty() || !infos[0].vpd) {
|
| | return false;
|
| | }
|
| |
|
| | std::vector<SelectionSingleton::SelObj> sels;
|
| | if (infos.size() > 1) {
|
| | for (auto& info : infos) {
|
| | if (!info.vpd) {
|
| | continue;
|
| | }
|
| |
|
| | SelectionSingleton::SelObj sel;
|
| | sel.pResolvedObject = nullptr;
|
| | sel.pObject = info.vpd->getObject();
|
| | sel.pDoc = sel.pObject->getDocument();
|
| | sel.DocName = sel.pDoc->getName();
|
| | sel.FeatName = sel.pObject->getNameInDocument();
|
| | sel.TypeName = sel.pObject->getTypeId().getName();
|
| | sel.SubName = info.element.c_str();
|
| | const auto& pt = info.pp->getPoint();
|
| | sel.x = pt[0];
|
| | sel.y = pt[1];
|
| | sel.z = pt[2];
|
| | sels.push_back(sel);
|
| | }
|
| | }
|
| |
|
| | const auto& info = infos[0];
|
| | auto vpd = info.vpd;
|
| | if (!vpd) {
|
| | return false;
|
| | }
|
| | if (!vpd->getObject()->isAttachedToDocument()) {
|
| | return false;
|
| | }
|
| | const char* objname = vpd->getObject()->getNameInDocument();
|
| | const char* docname = vpd->getObject()->getDocument()->getName();
|
| |
|
| | auto getFullSubElementName = [vpd](std::string& subName) {
|
| | App::ElementNamePair elementName;
|
| | App::GeoFeature::resolveElement(vpd->getObject(), subName.c_str(), elementName);
|
| | if (!elementName.newName.empty()) {
|
| | auto elementNameSuffix = Data::findElementName(subName.c_str());
|
| | subName.erase(subName.find(elementNameSuffix));
|
| | subName = subName.append(elementName.newName);
|
| | }
|
| | };
|
| |
|
| | bool hasNext = false;
|
| | const SoPickedPoint* pp = info.pp;
|
| | const SoDetail* det = pp->getDetail();
|
| | SoDetail* detNext = nullptr;
|
| | auto pPath = static_cast<SoFullPath*>(pp->getPath());
|
| | const auto& pt = pp->getPoint();
|
| | SoSelectionElementAction::Type type = SoSelectionElementAction::None;
|
| | auto preselectionMode = static_cast<SelectionModes>(this->preselectionMode.getValue());
|
| | static char buf[513];
|
| | auto subName = info.element;
|
| | std::string objectName = objname;
|
| |
|
| | if (ctrlDown) {
|
| | if (Gui::Selection().isSelected(docname, objname, info.element.c_str(), ResolveMode::NoResolve)) {
|
| | Gui::Selection().rmvSelection(docname, objname, info.element.c_str(), &sels);
|
| | return true;
|
| | }
|
| | else {
|
| |
|
| |
|
| | ViewProviderWeakPtrT guard(vpd);
|
| | getFullSubElementName(subName);
|
| | bool ok = Gui::Selection()
|
| | .addSelection(docname, objname, subName.c_str(), pt[0], pt[1], pt[2], &sels);
|
| | if (guard.expired()) {
|
| | return false;
|
| | }
|
| |
|
| | if (ok && preselectionMode == OFF) {
|
| | snprintf(
|
| | buf,
|
| | 512,
|
| | "Selected: %s.%s.%s (%g, %g, %g)",
|
| | docname,
|
| | objname,
|
| | info.element.c_str(),
|
| | fabs(pt[0]) > 1e-7 ? pt[0] : 0.0,
|
| | fabs(pt[1]) > 1e-7 ? pt[1] : 0.0,
|
| | fabs(pt[2]) > 1e-7 ? pt[2] : 0.0
|
| | );
|
| |
|
| | getMainWindow()->showMessage(QString::fromLatin1(buf));
|
| | }
|
| | detailPath->truncate(0);
|
| | if (vpd->getDetailPath(info.element.c_str(), detailPath, true, detNext)
|
| | && detailPath->getLength()) {
|
| | pPath = detailPath;
|
| | det = detNext;
|
| | FC_TRACE("select next " << objectName << ", " << subName);
|
| | if (ok) {
|
| | type = hasNext ? SoSelectionElementAction::All : SoSelectionElementAction::Append;
|
| | }
|
| | else {
|
| |
|
| |
|
| |
|
| | pPath = nullptr;
|
| | }
|
| | }
|
| | }
|
| | }
|
| | else {
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | getFullSubElementName(subName);
|
| | const char* subSelected
|
| | = Gui::Selection().getSelectedElement(vpd->getObject(), subName.c_str());
|
| |
|
| | FC_TRACE(
|
| | "select " << (subSelected ? subSelected : "'null'") << ", " << objectName << ", " << subName
|
| | );
|
| | std::string newElement;
|
| | if (subSelected) {
|
| | newElement = Data::newElementName(subSelected);
|
| | subSelected = newElement.c_str();
|
| | std::string nextsub;
|
| | const char* next = strrchr(subSelected, '.');
|
| | if (next && next != subSelected) {
|
| | if (next[1] == 0) {
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | for (--next; next != subSelected; --next) {
|
| | if (*next == '.') {
|
| | break;
|
| | }
|
| | }
|
| | }
|
| | if (*next == '.') {
|
| | nextsub = std::string(subSelected, next - subSelected + 1);
|
| | }
|
| | }
|
| | if (nextsub.length() || *subSelected != 0) {
|
| | hasNext = true;
|
| | subName = nextsub;
|
| | detailPath->truncate(0);
|
| | if (vpd->getDetailPath(subName.c_str(), detailPath, true, detNext)
|
| | && detailPath->getLength()) {
|
| | pPath = detailPath;
|
| | det = detNext;
|
| | FC_TRACE("select next " << objectName << ", " << subName);
|
| | }
|
| | }
|
| | }
|
| |
|
| | FC_TRACE("clearing selection");
|
| | Gui::Selection().clearSelection();
|
| | FC_TRACE("add selection");
|
| | bool ok = Gui::Selection().addSelection(
|
| | docname,
|
| | objectName.c_str(),
|
| | subName.c_str(),
|
| | pt[0],
|
| | pt[1],
|
| | pt[2],
|
| | &sels
|
| | );
|
| | if (ok) {
|
| | type = hasNext ? SoSelectionElementAction::All : SoSelectionElementAction::Append;
|
| | }
|
| |
|
| | if (preselectionMode == OFF) {
|
| | snprintf(
|
| | buf,
|
| | 512,
|
| | "Selected: %s.%s.%s (%g, %g, %g)",
|
| | docname,
|
| | objectName.c_str(),
|
| | subName.c_str(),
|
| | fabs(pt[0]) > 1e-7 ? pt[0] : 0.0,
|
| | fabs(pt[1]) > 1e-7 ? pt[1] : 0.0,
|
| | fabs(pt[2]) > 1e-7 ? pt[2] : 0.0
|
| | );
|
| |
|
| | getMainWindow()->showMessage(QString::fromLatin1(buf));
|
| | }
|
| | }
|
| |
|
| | if (pPath) {
|
| | FC_TRACE("applying action");
|
| | SoSelectionElementAction action(type);
|
| | action.setColor(this->colorSelection.getValue());
|
| | action.setElement(det);
|
| | action.apply(pPath);
|
| | FC_TRACE("applied action");
|
| | this->touch();
|
| | }
|
| |
|
| | if (detNext) {
|
| | delete detNext;
|
| | }
|
| | return true;
|
| | }
|
| |
|
| |
|
| | void SoFCUnifiedSelection::handleEvent(SoHandleEventAction* action)
|
| | {
|
| |
|
| | if (!selectionEnabled.getValue()) {
|
| | inherited::handleEvent(action);
|
| | return;
|
| | }
|
| |
|
| | auto preselectionMode = static_cast<SelectionModes>(this->preselectionMode.getValue());
|
| | const SoEvent* event = action->getEvent();
|
| |
|
| |
|
| |
|
| |
|
| | bool isMouseMotionEvent = event->isOfType(SoLocation2Event::getClassTypeId());
|
| | if (isMouseMotionEvent) {
|
| |
|
| |
|
| |
|
| | if (preselectionMode == AUTO || preselectionMode == ON) {
|
| |
|
| | auto infos = this->getPickedList(action, true);
|
| | if (!infos.empty()) {
|
| | setPreselect(infos[0]);
|
| | }
|
| | else {
|
| | setPreselect(PickedInfo());
|
| | if (this->preSelection > 0) {
|
| | this->preSelection = 0;
|
| |
|
| |
|
| | this->touch();
|
| | }
|
| | }
|
| | }
|
| | }
|
| |
|
| | else if (event->isOfType(SoMouseButtonEvent::getClassTypeId())
|
| | && selectionMode.getValue() == SoFCUnifiedSelection::ON) {
|
| | const auto e = static_cast<const SoMouseButtonEvent*>(event);
|
| | if (SoMouseButtonEvent::isButtonReleaseEvent(e, SoMouseButtonEvent::BUTTON1)) {
|
| |
|
| | auto infos = this->getPickedList(action, !Selection().needPickedList());
|
| | bool greedySel = Gui::Selection().getSelectionStyle()
|
| | == Gui::SelectionSingleton::SelectionStyle::GreedySelection;
|
| | greedySel = greedySel || event->wasCtrlDown();
|
| | if (setSelection(infos, greedySel) || greedySel) {
|
| | action->setHandled();
|
| | }
|
| | }
|
| | }
|
| |
|
| | inherited::handleEvent(action);
|
| | }
|
| |
|
| | void SoFCUnifiedSelection::GLRenderBelowPath(SoGLRenderAction* action)
|
| | {
|
| | inherited::GLRenderBelowPath(action);
|
| |
|
| |
|
| | if (this->preSelection == 0) {
|
| |
|
| |
|
| | this->preSelection = -1;
|
| | QOpenGLWidget* window;
|
| | SoState* state = action->getState();
|
| | SoGLWidgetElement::get(state, window);
|
| | QWidget* parent = window ? window->parentWidget() : nullptr;
|
| | if (parent) {
|
| | QCursor c = parent->cursor();
|
| | if (c.shape() == Qt::ForbiddenCursor) {
|
| | c.setShape(Qt::ArrowCursor);
|
| | parent->setCursor(c);
|
| | }
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| | SO_ACTION_SOURCE(SoHighlightElementAction)
|
| |
|
| | void SoHighlightElementAction::initClass()
|
| | {
|
| | SO_ACTION_INIT_CLASS(SoHighlightElementAction, SoAction);
|
| |
|
| | SO_ENABLE(SoHighlightElementAction, SoSwitchElement);
|
| | SO_ENABLE(SoHighlightElementAction, SoModelMatrixElement);
|
| |
|
| | SO_ACTION_ADD_METHOD(SoNode, nullAction);
|
| |
|
| | SO_ENABLE(SoHighlightElementAction, SoCoordinateElement);
|
| |
|
| | SO_ACTION_ADD_METHOD(SoGroup, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoIndexedLineSet, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoIndexedFaceSet, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoPointSet, callDoAction);
|
| | }
|
| |
|
| | SoHighlightElementAction::SoHighlightElementAction()
|
| | {
|
| | SO_ACTION_CONSTRUCTOR(SoHighlightElementAction);
|
| | }
|
| |
|
| | SoHighlightElementAction::~SoHighlightElementAction() = default;
|
| |
|
| | void SoHighlightElementAction::beginTraversal(SoNode* node)
|
| | {
|
| | traverse(node);
|
| | }
|
| |
|
| | void SoHighlightElementAction::callDoAction(SoAction* action, SoNode* node)
|
| | {
|
| | node->doAction(action);
|
| | }
|
| |
|
| | void SoHighlightElementAction::setHighlighted(SbBool ok)
|
| | {
|
| | this->_highlight = ok;
|
| | }
|
| |
|
| | SbBool SoHighlightElementAction::isHighlighted() const
|
| | {
|
| | return this->_highlight;
|
| | }
|
| |
|
| | void SoHighlightElementAction::setColor(const SbColor& c)
|
| | {
|
| | this->_color = c;
|
| | }
|
| |
|
| | const SbColor& SoHighlightElementAction::getColor() const
|
| | {
|
| | return this->_color;
|
| | }
|
| |
|
| | void SoHighlightElementAction::setElement(const SoDetail* det)
|
| | {
|
| | this->_det = det;
|
| | }
|
| |
|
| | const SoDetail* SoHighlightElementAction::getElement() const
|
| | {
|
| | return this->_det;
|
| | }
|
| |
|
| |
|
| |
|
| | SO_ACTION_SOURCE(SoSelectionElementAction)
|
| |
|
| | void SoSelectionElementAction::initClass()
|
| | {
|
| | SO_ACTION_INIT_CLASS(SoSelectionElementAction, SoAction);
|
| |
|
| | SO_ENABLE(SoSelectionElementAction, SoSwitchElement);
|
| | SO_ENABLE(SoSelectionElementAction, SoModelMatrixElement);
|
| |
|
| | SO_ACTION_ADD_METHOD(SoNode, nullAction);
|
| |
|
| | SO_ENABLE(SoSelectionElementAction, SoCoordinateElement);
|
| |
|
| | SO_ACTION_ADD_METHOD(SoCoordinate3, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoGroup, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoIndexedLineSet, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoIndexedFaceSet, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoPointSet, callDoAction);
|
| | }
|
| |
|
| | SoSelectionElementAction::SoSelectionElementAction(Type t, bool secondary)
|
| | : _type(t)
|
| | , _secondary(secondary)
|
| | {
|
| | SO_ACTION_CONSTRUCTOR(SoSelectionElementAction);
|
| | }
|
| |
|
| | SoSelectionElementAction::~SoSelectionElementAction() = default;
|
| |
|
| | void SoSelectionElementAction::beginTraversal(SoNode* node)
|
| | {
|
| | traverse(node);
|
| | }
|
| |
|
| | void SoSelectionElementAction::callDoAction(SoAction* action, SoNode* node)
|
| | {
|
| | node->doAction(action);
|
| | }
|
| |
|
| | SoSelectionElementAction::Type SoSelectionElementAction::getType() const
|
| | {
|
| | return this->_type;
|
| | }
|
| |
|
| | void SoSelectionElementAction::setColor(const SbColor& c)
|
| | {
|
| | this->_color = c;
|
| | }
|
| |
|
| | const SbColor& SoSelectionElementAction::getColor() const
|
| | {
|
| | return this->_color;
|
| | }
|
| |
|
| | void SoSelectionElementAction::setElement(const SoDetail* det)
|
| | {
|
| | this->_det = det;
|
| | }
|
| |
|
| | const SoDetail* SoSelectionElementAction::getElement() const
|
| | {
|
| | return this->_det;
|
| | }
|
| |
|
| |
|
| |
|
| | SO_ACTION_SOURCE(SoVRMLAction)
|
| |
|
| | void SoVRMLAction::initClass()
|
| | {
|
| | SO_ACTION_INIT_CLASS(SoVRMLAction, SoAction);
|
| |
|
| | SO_ENABLE(SoVRMLAction, SoSwitchElement);
|
| |
|
| | SO_ACTION_ADD_METHOD(SoNode, nullAction);
|
| |
|
| | SO_ENABLE(SoVRMLAction, SoCoordinateElement);
|
| | SO_ENABLE(SoVRMLAction, SoMaterialBindingElement);
|
| | SO_ENABLE(SoVRMLAction, SoLazyElement);
|
| | SO_ENABLE(SoVRMLAction, SoShapeStyleElement);
|
| |
|
| | SO_ACTION_ADD_METHOD(SoCoordinate3, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoMaterialBinding, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoMaterial, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoNormalBinding, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoGroup, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoIndexedLineSet, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoIndexedFaceSet, callDoAction);
|
| | SO_ACTION_ADD_METHOD(SoPointSet, callDoAction);
|
| | }
|
| |
|
| | SoVRMLAction::SoVRMLAction()
|
| | {
|
| | SO_ACTION_CONSTRUCTOR(SoVRMLAction);
|
| | }
|
| |
|
| | SoVRMLAction::~SoVRMLAction() = default;
|
| |
|
| | void SoVRMLAction::setOverrideMode(SbBool on)
|
| | {
|
| | overrideMode = on;
|
| | }
|
| |
|
| | SbBool SoVRMLAction::isOverrideMode() const
|
| | {
|
| | return overrideMode;
|
| | }
|
| |
|
| | void SoVRMLAction::callDoAction(SoAction* action, SoNode* node)
|
| | {
|
| | if (node->getTypeId().isDerivedFrom(SoNormalBinding::getClassTypeId())
|
| | && action->isOfType(SoVRMLAction::getClassTypeId())) {
|
| | auto vrmlAction = static_cast<SoVRMLAction*>(action);
|
| | if (vrmlAction->overrideMode) {
|
| | auto bind = static_cast<SoNormalBinding*>(node);
|
| | vrmlAction->bindList.push_back(bind->value.getValue());
|
| |
|
| |
|
| | if (bind->value.getValue() == static_cast<int>(SoNormalBinding::PER_VERTEX_INDEXED)) {
|
| | bind->value = SoNormalBinding::OVERALL;
|
| | }
|
| | }
|
| | else if (!vrmlAction->bindList.empty()) {
|
| | static_cast<SoNormalBinding*>(node)->value = static_cast<SoNormalBinding::Binding>(
|
| | vrmlAction->bindList.front()
|
| | );
|
| | vrmlAction->bindList.pop_front();
|
| | }
|
| | }
|
| |
|
| | node->doAction(action);
|
| | }
|
| |
|
| |
|
| |
|
| | bool SoFCSelectionRoot::StackComp::operator()(const Stack& a, const Stack& b) const
|
| | {
|
| | if (a.size() - a.offset < b.size() - b.offset) {
|
| | return true;
|
| | }
|
| | if (a.size() - a.offset > b.size() - b.offset) {
|
| | return false;
|
| | }
|
| | auto it1 = a.rbegin(), end1 = a.rend() - a.offset;
|
| | auto it2 = b.rbegin();
|
| | for (; it1 != end1; ++it1, ++it2) {
|
| | if (*it1 < *it2) {
|
| | return true;
|
| | }
|
| | if (*it1 > *it2) {
|
| | return false;
|
| | }
|
| | }
|
| | return false;
|
| | }
|
| |
|
| | SoSeparator::CacheEnabled SoFCSeparator::CacheMode = SoSeparator::AUTO;
|
| | SO_NODE_SOURCE(SoFCSeparator)
|
| |
|
| | SoFCSeparator::SoFCSeparator(bool trackCacheMode)
|
| | : trackCacheMode(trackCacheMode)
|
| | {
|
| | SO_NODE_CONSTRUCTOR(SoFCSeparator);
|
| | if (!trackCacheMode) {
|
| | renderCaching = SoSeparator::OFF;
|
| | boundingBoxCaching = SoSeparator::OFF;
|
| | }
|
| | }
|
| |
|
| | void SoFCSeparator::GLRenderBelowPath(SoGLRenderAction* action)
|
| | {
|
| | if (trackCacheMode && renderCaching.getValue() != CacheMode) {
|
| | renderCaching = CacheMode;
|
| | boundingBoxCaching = CacheMode;
|
| | }
|
| | inherited::GLRenderBelowPath(action);
|
| | }
|
| |
|
| | void SoFCSeparator::initClass()
|
| | {
|
| | SO_NODE_INIT_CLASS(SoFCSeparator, SoSeparator, "FCSeparator");
|
| | }
|
| |
|
| | void SoFCSeparator::finish()
|
| | {
|
| | atexit_cleanup();
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | using SoFCBBoxRenderInfo = struct
|
| | {
|
| | SoGetBoundingBoxAction* bboxaction;
|
| | SoCube* cube;
|
| | SoColorPacker* packer;
|
| | };
|
| |
|
| | static void so_bbox_construct_data(void* closure)
|
| | {
|
| | auto data = static_cast<SoFCBBoxRenderInfo*>(closure);
|
| | data->bboxaction = nullptr;
|
| | data->cube = nullptr;
|
| | data->packer = nullptr;
|
| | }
|
| |
|
| | static void so_bbox_destruct_data(void* closure)
|
| | {
|
| | auto data = static_cast<SoFCBBoxRenderInfo*>(closure);
|
| | delete data->bboxaction;
|
| | if (data->cube) {
|
| | data->cube->unref();
|
| | }
|
| | delete data->packer;
|
| | }
|
| |
|
| | static SbStorage* so_bbox_storage = nullptr;
|
| |
|
| |
|
| | static void so_bbox_cleanup()
|
| | {
|
| | delete so_bbox_storage;
|
| | }
|
| |
|
| |
|
| |
|
| | SoFCSelectionRoot::Stack SoFCSelectionRoot::SelStack;
|
| | std::unordered_map<SoAction*, SoFCSelectionRoot::Stack> SoFCSelectionRoot::ActionStacks;
|
| | SoFCSelectionRoot::ColorStack SoFCSelectionRoot::SelColorStack;
|
| | SoFCSelectionRoot::ColorStack SoFCSelectionRoot::HlColorStack;
|
| | SoFCSelectionRoot* SoFCSelectionRoot::ShapeColorNode;
|
| |
|
| | SO_NODE_SOURCE(SoFCSelectionRoot)
|
| |
|
| | SoFCSelectionRoot::SoFCSelectionRoot(bool trackCacheMode)
|
| | : SoFCSeparator(trackCacheMode)
|
| | {
|
| | SO_NODE_CONSTRUCTOR(SoFCSelectionRoot);
|
| | SO_NODE_ADD_FIELD(selectionStyle, (Full));
|
| | SO_NODE_DEFINE_ENUM_VALUE(SelectStyles, Full);
|
| | SO_NODE_DEFINE_ENUM_VALUE(SelectStyles, Box);
|
| | SO_NODE_DEFINE_ENUM_VALUE(SelectStyles, PassThrough);
|
| | SO_NODE_SET_SF_ENUM_TYPE(selectionStyle, SelectStyles);
|
| | }
|
| |
|
| | SoFCSelectionRoot::~SoFCSelectionRoot() = default;
|
| |
|
| | void SoFCSelectionRoot::initClass()
|
| | {
|
| | SO_NODE_INIT_CLASS(SoFCSelectionRoot, SoFCSeparator, "FCSelectionRoot");
|
| |
|
| | so_bbox_storage
|
| | = new SbStorage(sizeof(SoFCBBoxRenderInfo), so_bbox_construct_data, so_bbox_destruct_data);
|
| |
|
| |
|
| | }
|
| |
|
| | void SoFCSelectionRoot::finish()
|
| | {
|
| | so_bbox_cleanup();
|
| | atexit_cleanup();
|
| | }
|
| |
|
| | SoNode* SoFCSelectionRoot::getCurrentRoot(bool front, SoNode* def)
|
| | {
|
| | if (!SelStack.empty()) {
|
| | return front ? SelStack.front() : SelStack.back();
|
| | }
|
| | return def;
|
| | }
|
| |
|
| | SoFCSelectionContextBasePtr SoFCSelectionRoot::getNodeContext(
|
| | Stack& stack,
|
| | SoNode* node,
|
| | SoFCSelectionContextBasePtr def
|
| | )
|
| | {
|
| | if (stack.empty()) {
|
| | return def;
|
| | }
|
| |
|
| | auto front = dynamic_cast<SoFCSelectionRoot*>(stack.front());
|
| | if (front == nullptr) {
|
| | return SoFCSelectionContextBasePtr();
|
| | }
|
| |
|
| | stack.front() = node;
|
| |
|
| | auto it = front->contextMap.find(stack);
|
| | stack.front() = front;
|
| | if (it != front->contextMap.end()) {
|
| | return it->second;
|
| | }
|
| | return {};
|
| | }
|
| |
|
| | SoFCSelectionContextBasePtr SoFCSelectionRoot::getNodeContext2(
|
| | Stack& stack,
|
| | SoNode* node,
|
| | SoFCSelectionContextBase::MergeFunc* merge
|
| | )
|
| | {
|
| | SoFCSelectionContextBasePtr ret;
|
| | if (stack.empty()) {
|
| | return ret;
|
| | }
|
| |
|
| | auto* back = dynamic_cast<SoFCSelectionRoot*>(stack.back());
|
| | if (back == nullptr || back->contextMap2.empty()) {
|
| | return ret;
|
| | }
|
| |
|
| | int status = 0;
|
| | auto& map = back->contextMap2;
|
| | stack.back() = node;
|
| | for (stack.offset = 0; stack.offset < stack.size(); ++stack.offset) {
|
| | auto it = map.find(stack);
|
| | SoFCSelectionContextBasePtr ctx;
|
| | if (it != map.end()) {
|
| | ctx = it->second;
|
| | }
|
| | status
|
| | = merge(status, ret, ctx, stack.offset == stack.size() - 1 ? nullptr : stack[stack.offset]);
|
| | if (status < 0) {
|
| | break;
|
| | }
|
| | }
|
| | stack.offset = 0;
|
| | stack.back() = back;
|
| | return ret;
|
| | }
|
| |
|
| | std::pair<bool, SoFCSelectionContextBasePtr*> SoFCSelectionRoot::findActionContext(
|
| | SoAction* action,
|
| | SoNode* _node,
|
| | bool create,
|
| | bool erase
|
| | )
|
| | {
|
| | std::pair<bool, SoFCSelectionContextBasePtr*> res(false, 0);
|
| |
|
| | if (action->isOfType(SoSelectionElementAction::getClassTypeId())) {
|
| | res.first = static_cast<SoSelectionElementAction*>(action)->isSecondary();
|
| | }
|
| |
|
| | auto it = ActionStacks.find(action);
|
| | if (it == ActionStacks.end() || it->second.empty()) {
|
| | return res;
|
| | }
|
| |
|
| | auto& stack = it->second;
|
| |
|
| | if (res.first) {
|
| | auto back = dynamic_cast<SoFCSelectionRoot*>(stack.back());
|
| | if (back != nullptr) {
|
| | stack.back() = _node;
|
| | if (create) {
|
| | res.second = &back->contextMap2[stack];
|
| | }
|
| | else {
|
| | auto it = back->contextMap2.find(stack);
|
| | if (it != back->contextMap2.end()) {
|
| | res.second = &it->second;
|
| | if (erase) {
|
| | back->contextMap2.erase(it);
|
| | }
|
| | }
|
| | }
|
| | stack.back() = back;
|
| | }
|
| | }
|
| | else {
|
| | auto front = dynamic_cast<SoFCSelectionRoot*>(stack.front());
|
| | if (front != nullptr) {
|
| | stack.front() = _node;
|
| | if (create) {
|
| | res.second = &front->contextMap[stack];
|
| | }
|
| | else {
|
| | auto it = front->contextMap.find(stack);
|
| | if (it != front->contextMap.end()) {
|
| | res.second = &it->second;
|
| | if (erase) {
|
| | front->contextMap.erase(it);
|
| | }
|
| | }
|
| | }
|
| | stack.front() = front;
|
| | }
|
| | }
|
| | return res;
|
| | }
|
| |
|
| | bool SoFCSelectionRoot::renderBBox(SoGLRenderAction* action, SoNode* node, SbColor color)
|
| | {
|
| | auto data = static_cast<SoFCBBoxRenderInfo*>(so_bbox_storage->get());
|
| | if (!data->bboxaction) {
|
| |
|
| |
|
| | data->bboxaction = new SoGetBoundingBoxAction(SbViewportRegion());
|
| | data->cube = new SoCube;
|
| | data->cube->ref();
|
| | data->packer = new SoColorPacker;
|
| | }
|
| |
|
| | SbBox3f bbox;
|
| | data->bboxaction->setViewportRegion(action->getViewportRegion());
|
| | data->bboxaction->apply(node);
|
| | bbox = data->bboxaction->getBoundingBox();
|
| | if (bbox.isEmpty()) {
|
| | return false;
|
| | }
|
| |
|
| | auto state = action->getState();
|
| |
|
| | state->push();
|
| |
|
| | SoMaterialBindingElement::set(state, SoMaterialBindingElement::OVERALL);
|
| | SoLazyElement::setEmissive(state, &color);
|
| | SoLazyElement::setDiffuse(state, node, 1, &color, data->packer);
|
| | SoDrawStyleElement::set(state, node, SoDrawStyleElement::LINES);
|
| | SoLineWidthElement::set(state, node, 1.0f);
|
| |
|
| | const static float trans = 0.0;
|
| | SoLazyElement::setTransparency(state, node, 1, &trans, data->packer);
|
| |
|
| | float x, y, z;
|
| | bbox.getSize(x, y, z);
|
| | data->cube->width = x + 0.001;
|
| | data->cube->height = y + 0.001;
|
| | data->cube->depth = z + 0.001;
|
| |
|
| | SoModelMatrixElement::translateBy(state, node, bbox.getCenter());
|
| |
|
| | SoMaterialBundle mb(action);
|
| | mb.sendFirst();
|
| |
|
| | data->cube->GLRender(action);
|
| |
|
| | state->pop();
|
| | return true;
|
| | }
|
| |
|
| | static std::time_t _CyclicLastReported;
|
| |
|
| | void SoFCSelectionRoot::renderPrivate(SoGLRenderAction* action, bool inPath)
|
| | {
|
| | if (ViewParams::instance()->getCoinCycleCheck() && !SelStack.nodeSet.insert(this).second) {
|
| | std::time_t t = std::time(nullptr);
|
| | if (_CyclicLastReported < t) {
|
| | _CyclicLastReported = t + 5;
|
| | FC_ERR("Cyclic scene graph: " << getName());
|
| | }
|
| | return;
|
| | }
|
| | SelStack.push_back(this);
|
| | if (_renderPrivate(action, inPath)) {
|
| | if (inPath) {
|
| | SoSeparator::GLRenderInPath(action);
|
| | }
|
| | else {
|
| | SoSeparator::GLRenderBelowPath(action);
|
| | }
|
| | }
|
| | SelStack.pop_back();
|
| | SelStack.nodeSet.erase(this);
|
| | }
|
| |
|
| | bool SoFCSelectionRoot::_renderPrivate(SoGLRenderAction* action, bool inPath)
|
| | {
|
| | auto ctx2 = std::static_pointer_cast<SelContext>(
|
| | getNodeContext2(SelStack, this, SelContext::merge)
|
| | );
|
| | if (ctx2 && ctx2->hideAll) {
|
| | return false;
|
| | }
|
| |
|
| | auto state = action->getState();
|
| | SelContextPtr ctx = getRenderContext<SelContext>(this);
|
| | int style = selectionStyle.getValue();
|
| | if ((style == SoFCSelectionRoot::Box || ViewParams::instance()->getShowSelectionBoundingBox())
|
| | && ctx && !ctx->hideAll && (ctx->selAll || ctx->hlAll)) {
|
| | if (style == SoFCSelectionRoot::PassThrough) {
|
| | style = SoFCSelectionRoot::Box;
|
| | }
|
| | else {
|
| | renderBBox(action, this, ctx->hlAll ? ctx->hlColor : ctx->selColor);
|
| | return true;
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | bool colorPushed = false;
|
| | if (!ShapeColorNode && overrideColor && !SoOverrideElement::getDiffuseColorOverride(state)
|
| | && (style == SoFCSelectionRoot::Box || !ctx || (!ctx->selAll && !ctx->hideAll))) {
|
| | ShapeColorNode = this;
|
| | colorPushed = true;
|
| | state->push();
|
| | auto& packer = ShapeColorNode->shapeColorPacker;
|
| | auto& trans = ShapeColorNode->transOverride;
|
| | auto& color = ShapeColorNode->colorOverride;
|
| | if (!SoOverrideElement::getTransparencyOverride(state)) {
|
| | SoLazyElement::setTransparency(state, ShapeColorNode, 1, &trans, &packer);
|
| | SoOverrideElement::setTransparencyOverride(state, ShapeColorNode, true);
|
| | }
|
| | SoLazyElement::setDiffuse(state, ShapeColorNode, 1, &color, &packer);
|
| | SoOverrideElement::setDiffuseColorOverride(state, ShapeColorNode, true);
|
| | SoMaterialBindingElement::set(state, ShapeColorNode, SoMaterialBindingElement::OVERALL);
|
| | SoOverrideElement::setMaterialBindingOverride(state, ShapeColorNode, true);
|
| |
|
| | SoTextureEnabledElement::set(state, ShapeColorNode, false);
|
| | }
|
| |
|
| | if (!ctx) {
|
| | if (inPath) {
|
| | SoSeparator::GLRenderInPath(action);
|
| | }
|
| | else {
|
| | SoSeparator::GLRenderBelowPath(action);
|
| | }
|
| | }
|
| | else {
|
| | bool selPushed;
|
| | bool hlPushed;
|
| | if ((selPushed = ctx->selAll)) {
|
| | SelColorStack.push_back(ctx->selColor);
|
| |
|
| | if (style != SoFCSelectionRoot::Box) {
|
| | state->push();
|
| | auto& color = SelColorStack.back();
|
| | SoLazyElement::setEmissive(state, &color);
|
| | SoOverrideElement::setEmissiveColorOverride(state, this, true);
|
| | if (SoLazyElement::getLightModel(state) == SoLazyElement::BASE_COLOR) {
|
| | auto& packer = shapeColorPacker;
|
| | SoLazyElement::setDiffuse(state, this, 1, &color, &packer);
|
| | SoOverrideElement::setDiffuseColorOverride(state, this, true);
|
| | SoMaterialBindingElement::set(state, this, SoMaterialBindingElement::OVERALL);
|
| | SoOverrideElement::setMaterialBindingOverride(state, this, true);
|
| | }
|
| | }
|
| | }
|
| |
|
| | if ((hlPushed = ctx->hlAll)) {
|
| | HlColorStack.push_back(ctx->hlColor);
|
| | }
|
| |
|
| | if (inPath) {
|
| | SoSeparator::GLRenderInPath(action);
|
| | }
|
| | else {
|
| | SoSeparator::GLRenderBelowPath(action);
|
| | }
|
| |
|
| | if (selPushed) {
|
| | SelColorStack.pop_back();
|
| |
|
| | if (style != SoFCSelectionRoot::Box) {
|
| | state->pop();
|
| | }
|
| | }
|
| | if (hlPushed) {
|
| | HlColorStack.pop_back();
|
| | }
|
| | }
|
| |
|
| | if (colorPushed) {
|
| | ShapeColorNode = nullptr;
|
| | state->pop();
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| | void SoFCSelectionRoot::GLRenderBelowPath(SoGLRenderAction* action)
|
| | {
|
| | renderPrivate(action, false);
|
| | }
|
| |
|
| | void SoFCSelectionRoot::GLRenderInPath(SoGLRenderAction* action)
|
| | {
|
| | if (action->getCurPathCode() == SoAction::BELOW_PATH) {
|
| | return GLRenderBelowPath(action);
|
| | }
|
| | renderPrivate(action, true);
|
| | }
|
| |
|
| | bool SoFCSelectionRoot::checkColorOverride(SoState* state)
|
| | {
|
| | if (ShapeColorNode) {
|
| | if (!SoOverrideElement::getDiffuseColorOverride(state)) {
|
| | state->push();
|
| | auto& packer = ShapeColorNode->shapeColorPacker;
|
| | auto& trans = ShapeColorNode->transOverride;
|
| | auto& color = ShapeColorNode->colorOverride;
|
| | if (!SoOverrideElement::getTransparencyOverride(state)) {
|
| | SoLazyElement::setTransparency(state, ShapeColorNode, 1, &trans, &packer);
|
| | SoOverrideElement::setTransparencyOverride(state, ShapeColorNode, true);
|
| | }
|
| | SoLazyElement::setDiffuse(state, ShapeColorNode, 1, &color, &packer);
|
| | SoOverrideElement::setDiffuseColorOverride(state, ShapeColorNode, true);
|
| | SoMaterialBindingElement::set(state, ShapeColorNode, SoMaterialBindingElement::OVERALL);
|
| | SoOverrideElement::setMaterialBindingOverride(state, ShapeColorNode, true);
|
| |
|
| | SoTextureEnabledElement::set(state, ShapeColorNode, false);
|
| | return true;
|
| | }
|
| | }
|
| | return false;
|
| | }
|
| |
|
| | void SoFCSelectionRoot::checkSelection(bool& sel, SbColor& selColor, bool& hl, SbColor& hlColor)
|
| | {
|
| | sel = false;
|
| | hl = false;
|
| | if ((sel = !SelColorStack.empty())) {
|
| | selColor = SelColorStack.back();
|
| | }
|
| | if ((hl = !HlColorStack.empty())) {
|
| | hlColor = HlColorStack.back();
|
| | }
|
| | }
|
| |
|
| | void SoFCSelectionRoot::resetContext()
|
| | {
|
| | contextMap.clear();
|
| | }
|
| |
|
| | void SoFCSelectionRoot::moveActionStack(SoAction* from, SoAction* to, bool erase)
|
| | {
|
| | auto it = ActionStacks.find(from);
|
| | if (it == ActionStacks.end()) {
|
| | return;
|
| | }
|
| | auto& stack = ActionStacks[to];
|
| | assert(stack.empty());
|
| | stack.swap(it->second);
|
| | if (erase) {
|
| | ActionStacks.erase(it);
|
| | }
|
| | }
|
| |
|
| | #define BEGIN_ACTION \
|
| | auto& stack = ActionStacks[action]; \
|
| | if (ViewParams::instance()->getCoinCycleCheck() && !stack.nodeSet.insert(this).second) { \
|
| | std::time_t t = std::time(0); \
|
| | if (_CyclicLastReported < t) { \
|
| | _CyclicLastReported = t + 5; \
|
| | FC_ERR("Cyclic scene graph: " << getName()); \
|
| | } \
|
| | return; \
|
| | } \
|
| | stack.push_back(this); \
|
| | auto size = stack.size();
|
| |
|
| | #define END_ACTION \
|
| | if (stack.size() != size || stack.back() != this) \
|
| | FC_ERR("action stack fault"); \
|
| | else { \
|
| | stack.nodeSet.erase(this); \
|
| | stack.pop_back(); \
|
| | if (stack.empty()) \
|
| | ActionStacks.erase(action); \
|
| | }
|
| |
|
| | void SoFCSelectionRoot::pick(SoPickAction* action)
|
| | {
|
| | BEGIN_ACTION;
|
| | if (doActionPrivate(stack, action)) {
|
| | inherited::pick(action);
|
| | }
|
| | END_ACTION;
|
| | }
|
| |
|
| | void SoFCSelectionRoot::rayPick(SoRayPickAction* action)
|
| | {
|
| | BEGIN_ACTION;
|
| | if (doActionPrivate(stack, action)) {
|
| | inherited::rayPick(action);
|
| | }
|
| | END_ACTION;
|
| | }
|
| |
|
| | void SoFCSelectionRoot::handleEvent(SoHandleEventAction* action)
|
| | {
|
| | BEGIN_ACTION;
|
| | inherited::handleEvent(action);
|
| | END_ACTION;
|
| | }
|
| |
|
| | void SoFCSelectionRoot::search(SoSearchAction* action)
|
| | {
|
| | BEGIN_ACTION;
|
| | inherited::search(action);
|
| | END_ACTION;
|
| | }
|
| |
|
| | void SoFCSelectionRoot::getPrimitiveCount(SoGetPrimitiveCountAction* action)
|
| | {
|
| | BEGIN_ACTION;
|
| | inherited::getPrimitiveCount(action);
|
| | END_ACTION;
|
| | }
|
| |
|
| | void SoFCSelectionRoot::getBoundingBox(SoGetBoundingBoxAction* action)
|
| | {
|
| | BEGIN_ACTION;
|
| | if (doActionPrivate(stack, action)) {
|
| | inherited::getBoundingBox(action);
|
| | }
|
| | END_ACTION;
|
| | }
|
| |
|
| | void SoFCSelectionRoot::getMatrix(SoGetMatrixAction* action)
|
| | {
|
| | BEGIN_ACTION;
|
| | if (doActionPrivate(stack, action)) {
|
| | inherited::getMatrix(action);
|
| | }
|
| | END_ACTION;
|
| | }
|
| |
|
| | void SoFCSelectionRoot::callback(SoCallbackAction* action)
|
| | {
|
| | BEGIN_ACTION;
|
| | inherited::callback(action);
|
| | END_ACTION;
|
| | }
|
| |
|
| | void SoFCSelectionRoot::doAction(SoAction* action)
|
| | {
|
| | BEGIN_ACTION
|
| | if (doActionPrivate(stack, action)) {
|
| | inherited::doAction(action);
|
| | }
|
| | END_ACTION
|
| | }
|
| |
|
| | bool SoFCSelectionRoot::doActionPrivate(Stack& stack, SoAction* action)
|
| | {
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | SelContextPtr ctx2;
|
| | bool ctx2Searched = false;
|
| | bool isTail = false;
|
| | if (action->getCurPathCode() == SoAction::IN_PATH) {
|
| | auto path = action->getPathAppliedTo();
|
| | if (path) {
|
| | isTail = path->getTail() == this
|
| | || (path->getLength() > 1 && path->getNodeFromTail(1) == this
|
| | && path->getTail()->isOfType(SoSwitch::getClassTypeId()));
|
| | }
|
| |
|
| | if (!action->isOfType(SoSelectionElementAction::getClassTypeId())) {
|
| | ctx2Searched = true;
|
| | ctx2 = std::static_pointer_cast<SelContext>(
|
| | getNodeContext2(stack, this, SelContext::merge)
|
| | );
|
| | if (ctx2 && ctx2->hideAll) {
|
| | return false;
|
| | }
|
| | }
|
| | if (!isTail) {
|
| | return true;
|
| | }
|
| | }
|
| | else if (action->getWhatAppliedTo() != SoAction::NODE
|
| | && action->getCurPathCode() != SoAction::BELOW_PATH) {
|
| | return true;
|
| | }
|
| |
|
| | if (action->isOfType(SoSelectionElementAction::getClassTypeId())) {
|
| | auto selAction = static_cast<SoSelectionElementAction*>(action);
|
| | if (selAction->isSecondary()) {
|
| | if (selAction->getType() == SoSelectionElementAction::Show
|
| | || (selAction->getType() == SoSelectionElementAction::Color
|
| | && selAction->getColors().empty()
|
| | && action->getWhatAppliedTo() == SoAction::NODE)) {
|
| | auto ctx = getActionContext(action, this, SelContextPtr(), false);
|
| | if (ctx && ctx->hideAll) {
|
| | ctx->hideAll = false;
|
| | if (!ctx->hlAll && !ctx->selAll) {
|
| | removeActionContext(action, this);
|
| | }
|
| | touch();
|
| | }
|
| |
|
| |
|
| | return selAction->getType() == SoSelectionElementAction::Color
|
| | || action->getWhatAppliedTo() == SoAction::NODE;
|
| | }
|
| | else if (selAction->getType() == SoSelectionElementAction::Hide) {
|
| | if (action->getCurPathCode() == SoAction::BELOW_PATH || isTail) {
|
| | auto ctx = getActionContext(action, this, SelContextPtr());
|
| | if (ctx && !ctx->hideAll) {
|
| | ctx->hideAll = true;
|
| | touch();
|
| | }
|
| | return false;
|
| | }
|
| | }
|
| | return true;
|
| | }
|
| |
|
| | if (selAction->getType() == SoSelectionElementAction::None) {
|
| | if (action->getWhatAppliedTo() == SoAction::NODE) {
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | resetContext();
|
| | touch();
|
| | return false;
|
| | }
|
| |
|
| | auto ctx = getActionContext(action, this, SelContextPtr(), false);
|
| | if (ctx && ctx->selAll) {
|
| | ctx->selAll = false;
|
| | touch();
|
| | return false;
|
| | }
|
| | }
|
| | else if (selAction->getType() == SoSelectionElementAction::All) {
|
| | auto ctx = getActionContext(action, this, SelContextPtr());
|
| | assert(ctx);
|
| | ctx->selAll = true;
|
| | ctx->selColor = selAction->getColor();
|
| | touch();
|
| | return false;
|
| | }
|
| | return true;
|
| | }
|
| |
|
| | if (action->isOfType(SoHighlightElementAction::getClassTypeId())) {
|
| | auto highlightAction = static_cast<SoHighlightElementAction*>(action);
|
| | if (highlightAction->isHighlighted()) {
|
| | if (highlightAction->getElement()) {
|
| | auto ctx = getActionContext(action, this, SelContextPtr(), false);
|
| | if (ctx && ctx->hlAll) {
|
| | ctx->hlAll = false;
|
| | touch();
|
| | }
|
| | }
|
| | else {
|
| | auto ctx = getActionContext(action, this, SelContextPtr());
|
| | assert(ctx);
|
| | ctx->hlAll = true;
|
| | ctx->hlColor = highlightAction->getColor();
|
| | touch();
|
| | return false;
|
| | }
|
| | }
|
| | else {
|
| | auto ctx = getActionContext(action, this, SelContextPtr(), false);
|
| | if (ctx && ctx->hlAll) {
|
| | ctx->hlAll = false;
|
| | touch();
|
| | return false;
|
| | }
|
| | }
|
| | return true;
|
| | }
|
| |
|
| | if (!ctx2Searched) {
|
| | ctx2 = std::static_pointer_cast<SelContext>(getNodeContext2(stack, this, SelContext::merge));
|
| | if (ctx2 && ctx2->hideAll) {
|
| | return false;
|
| | }
|
| | }
|
| | return true;
|
| | }
|
| |
|
| | int SoFCSelectionRoot::SelContext::merge(
|
| | int status,
|
| | SoFCSelectionContextBasePtr& output,
|
| | SoFCSelectionContextBasePtr input,
|
| | SoNode*
|
| | )
|
| | {
|
| | auto ctx = std::dynamic_pointer_cast<SelContext>(input);
|
| | if (ctx && ctx->hideAll) {
|
| | output = ctx;
|
| | return -1;
|
| | }
|
| | return status;
|
| | }
|
| |
|
| |
|
| |
|
| | SO_NODE_SOURCE(SoFCPathAnnotation)
|
| |
|
| | SoFCPathAnnotation::SoFCPathAnnotation()
|
| | {
|
| | SO_NODE_CONSTRUCTOR(SoFCPathAnnotation);
|
| | path = nullptr;
|
| | tmpPath = nullptr;
|
| | det = nullptr;
|
| | }
|
| |
|
| | SoFCPathAnnotation::~SoFCPathAnnotation()
|
| | {
|
| | if (path) {
|
| | path->unref();
|
| | }
|
| | if (tmpPath) {
|
| | tmpPath->unref();
|
| | }
|
| | delete det;
|
| | }
|
| |
|
| | void SoFCPathAnnotation::finish()
|
| | {
|
| | atexit_cleanup();
|
| | }
|
| |
|
| | void SoFCPathAnnotation::initClass()
|
| | {
|
| | SO_NODE_INIT_CLASS(SoFCPathAnnotation, SoSeparator, "Separator");
|
| | }
|
| |
|
| | void SoFCPathAnnotation::GLRender(SoGLRenderAction* action)
|
| | {
|
| | switch (action->getCurPathCode()) {
|
| | case SoAction::NO_PATH:
|
| | case SoAction::BELOW_PATH:
|
| | this->GLRenderBelowPath(action);
|
| | break;
|
| | case SoAction::OFF_PATH:
|
| | break;
|
| | case SoAction::IN_PATH:
|
| | this->GLRenderInPath(action);
|
| | break;
|
| | }
|
| | }
|
| |
|
| | void SoFCPathAnnotation::GLRenderBelowPath(SoGLRenderAction* action)
|
| | {
|
| | if (!path || !path->getLength() || !tmpPath || !tmpPath->getLength()) {
|
| | return;
|
| | }
|
| |
|
| | if (path->getLength() != tmpPath->getLength()) {
|
| |
|
| |
|
| |
|
| | for (int i = path->getLength() - 1; i < tmpPath->getLength() - 1; ++i) {
|
| | auto children = path->getNode(i)->getChildren();
|
| | if (children) {
|
| | int idx = children->find(tmpPath->getNode(i + 1));
|
| | if (idx >= 0) {
|
| | path->append(idx);
|
| | continue;
|
| | }
|
| | }
|
| | tmpPath->unref();
|
| | tmpPath = nullptr;
|
| | return;
|
| | }
|
| | }
|
| |
|
| | SoState* state = action->getState();
|
| | SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
|
| |
|
| | if (action->isRenderingDelayedPaths()) {
|
| | SbBool zbenabled = glIsEnabled(GL_DEPTH_TEST);
|
| | if (zbenabled) {
|
| | glDisable(GL_DEPTH_TEST);
|
| | }
|
| |
|
| | if (det) {
|
| | inherited::GLRenderInPath(action);
|
| | }
|
| | else {
|
| | bool bbox = ViewParams::instance()->getShowSelectionBoundingBox();
|
| | if (!bbox) {
|
| | for (int i = 0, count = path->getLength(); i < count; ++i) {
|
| | if (!path->getNode(i)->isOfType(SoFCSelectionRoot::getClassTypeId())) {
|
| | continue;
|
| | }
|
| | auto node = dynamic_cast<SoFCSelectionRoot*>(path->getNode(i));
|
| | if (node != nullptr && node->selectionStyle.getValue() == SoFCSelectionRoot::Box) {
|
| | bbox = true;
|
| | break;
|
| | }
|
| | }
|
| | }
|
| | if (!bbox) {
|
| | inherited::GLRenderInPath(action);
|
| | }
|
| | else {
|
| | bool sel = false;
|
| | bool hl = false;
|
| | SbColor selColor, hlColor;
|
| | SoFCSelectionRoot::checkSelection(sel, selColor, hl, hlColor);
|
| | if (sel || hl) {
|
| | SoFCSelectionRoot::renderBBox(action, this, hl ? hlColor : selColor);
|
| | }
|
| | else {
|
| | inherited::GLRenderInPath(action);
|
| | }
|
| | }
|
| | }
|
| |
|
| | if (zbenabled) {
|
| | glEnable(GL_DEPTH_TEST);
|
| | }
|
| | }
|
| | else {
|
| | SoCacheElement::invalidate(action->getState());
|
| | auto curPath = action->getCurPath();
|
| | auto newPath = new SoPath(curPath->getLength() + path->getLength());
|
| | newPath->append(curPath);
|
| | newPath->append(path);
|
| | action->addDelayedPath(newPath);
|
| | }
|
| | }
|
| |
|
| | void SoFCPathAnnotation::GLRenderInPath(SoGLRenderAction* action)
|
| | {
|
| | GLRenderBelowPath(action);
|
| | }
|
| |
|
| | void SoFCPathAnnotation::setDetail(SoDetail* d)
|
| | {
|
| | if (d != det) {
|
| | delete det;
|
| | det = d;
|
| | }
|
| | }
|
| |
|
| | void SoFCPathAnnotation::setPath(SoPath* newPath)
|
| | {
|
| | if (path) {
|
| | path->unref();
|
| | coinRemoveAllChildren(this);
|
| | path = nullptr;
|
| | if (tmpPath) {
|
| | tmpPath->unref();
|
| | tmpPath = nullptr;
|
| | }
|
| | }
|
| | if (!newPath || !newPath->getLength()) {
|
| | return;
|
| | }
|
| |
|
| | tmpPath = new SoTempPath(newPath->getLength());
|
| | tmpPath->ref();
|
| | for (int i = 0; i < newPath->getLength(); ++i) {
|
| | tmpPath->append(newPath->getNode(i));
|
| | }
|
| | path = newPath->copy();
|
| | path->ref();
|
| | addChild(path->getNode(0));
|
| | }
|
| |
|
| | void SoFCPathAnnotation::getBoundingBox(SoGetBoundingBoxAction* action)
|
| | {
|
| | if (path) {
|
| | SoGetBoundingBoxAction bboxAction(action->getViewportRegion());
|
| | SoFCSelectionRoot::moveActionStack(action, &bboxAction, false);
|
| | bboxAction.apply(path);
|
| | SoFCSelectionRoot::moveActionStack(&bboxAction, action, true);
|
| | auto bbox = bboxAction.getBoundingBox();
|
| | if (!bbox.isEmpty()) {
|
| | action->extendBy(bbox);
|
| | }
|
| | }
|
| | }
|
| |
|