diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt
index cc5a764517..54dab95773 100644
--- a/src/Gui/CMakeLists.txt
+++ b/src/Gui/CMakeLists.txt
@@ -1022,6 +1022,7 @@ SET(Inventor_CPP_SRCS
SoFCOffscreenRenderer.cpp
SoFCSelection.cpp
SoFCUnifiedSelection.cpp
+ SoFCSelectionContext.cpp
SoFCSelectionAction.cpp
SoFCVectorizeSVGAction.cpp
SoFCVectorizeU3DAction.cpp
@@ -1047,6 +1048,7 @@ SET(Inventor_SRCS
SoFCOffscreenRenderer.h
SoFCSelection.h
SoFCUnifiedSelection.h
+ SoFCSelectionContext.h
SoFCSelectionAction.h
SoFCVectorizeSVGAction.h
SoFCVectorizeU3DAction.h
diff --git a/src/Gui/DlgSettings3DView.ui b/src/Gui/DlgSettings3DView.ui
index 5c7c276d52..48469bbdac 100644
--- a/src/Gui/DlgSettings3DView.ui
+++ b/src/Gui/DlgSettings3DView.ui
@@ -145,6 +145,39 @@ will be shown at the lower left in opened files
+ -
+
+
-
+
+
+ Render cache
+
+
+
+ -
+
+
+ 0
+
+
-
+
+ Auto
+
+
+ -
+
+ Distributed
+
+
+ -
+
+ Centralized
+
+
+
+
+
+
-
diff --git a/src/Gui/DlgSettings3DViewImp.cpp b/src/Gui/DlgSettings3DViewImp.cpp
index 93c58eb16a..7b088b594d 100644
--- a/src/Gui/DlgSettings3DViewImp.cpp
+++ b/src/Gui/DlgSettings3DViewImp.cpp
@@ -88,6 +88,9 @@ void DlgSettings3DViewImp::saveSettings()
index = this->naviCubeCorner->currentIndex();
hGrp->SetInt("CornerNaviCube", index);
+ index = this->renderCache->currentIndex();
+ hGrp->SetInt("RenderCache", index);
+
QVariant const &vBoxMarkerSize = this->boxMarkerSize->itemData(this->boxMarkerSize->currentIndex());
hGrp->SetInt("MarkerSize", vBoxMarkerSize.toInt());
@@ -158,6 +161,9 @@ void DlgSettings3DViewImp::loadSettings()
index = hGrp->GetInt("CornerNaviCube", 1);
naviCubeCorner->setCurrentIndex(index);
+ index = hGrp->GetInt("RenderCache", 0);
+ renderCache->setCurrentIndex(index);
+
int const current = hGrp->GetInt("MarkerSize", 9L);
this->boxMarkerSize->addItem(tr("5px"), QVariant(5));
this->boxMarkerSize->addItem(tr("7px"), QVariant(7));
diff --git a/src/Gui/Quarter/SoQTQuarterAdaptor.cpp b/src/Gui/Quarter/SoQTQuarterAdaptor.cpp
index 47b4314cef..c26d1f0b48 100644
--- a/src/Gui/Quarter/SoQTQuarterAdaptor.cpp
+++ b/src/Gui/Quarter/SoQTQuarterAdaptor.cpp
@@ -714,32 +714,37 @@ bool SIM::Coin3D::Quarter::SoQTQuarterAdaptor::processSoEvent(const SoEvent* eve
*/
void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::paintEvent(QPaintEvent* event)
{
+ double start = SbTime::getTimeOfDay().getValue();
QuarterWidget::paintEvent(event);
-
- this->framesPerSecond = addFrametime(SbTime::getTimeOfDay().getValue());
+ this->framesPerSecond = addFrametime(start);
}
void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::resetFrameCounter(void)
{
this->framecount = 0;
- this->frames.assign(100, 0.0f);
- this->totaldraw = 0.0f;
+ this->frametime = 0.0f;
+ this->drawtime = 0.0f;
this->starttime = SbTime::getTimeOfDay().getValue();
this->framesPerSecond = SbVec2f(0, 0);
}
-SbVec2f SIM::Coin3D::Quarter::SoQTQuarterAdaptor::addFrametime(double timeofday)
+SbVec2f SIM::Coin3D::Quarter::SoQTQuarterAdaptor::addFrametime(double starttime)
{
- int framearray_size = 100;
this->framecount++;
- int arrayptr = (this->framecount - 1) % framearray_size;
+ double timeofday = SbTime::getTimeOfDay().getValue();
- double renderTime = timeofday - this->starttime;
- this->totaldraw += (float(renderTime) - this->frames[arrayptr]);
- float drawfps = this->totaldraw / std::min(this->framecount, framearray_size);
+ // draw time is the actual time spent on rendering
+ double drawtime = timeofday - starttime;
+#define FPS_FACTOR 0.7
+ this->drawtime = (drawtime*FPS_FACTOR) + this->drawtime*(1.0-FPS_FACTOR);
+
+ // frame time is the time spent since the last frame. There could an
+ // indefinite pause between the last frame because the scene is not
+ // changing. So we limit the skew to 5 second.
+ double frametime = std::min(timeofday-this->starttime, std::max(drawtime,5000.0));
+ this->frametime = (frametime*FPS_FACTOR) + this->frametime*(1.0-FPS_FACTOR);
- this->frames[arrayptr] = static_cast(renderTime);
this->starttime = timeofday;
- return SbVec2f(1000 * drawfps, 1.0f / drawfps);
+ return SbVec2f(1000 * this->drawtime, 1.0f / this->frametime);
}
diff --git a/src/Gui/Quarter/SoQTQuarterAdaptor.h b/src/Gui/Quarter/SoQTQuarterAdaptor.h
index 3f9cc9fe96..5131c15c07 100644
--- a/src/Gui/Quarter/SoQTQuarterAdaptor.h
+++ b/src/Gui/Quarter/SoQTQuarterAdaptor.h
@@ -117,9 +117,8 @@ private:
SoCallbackList m_interactionStartCallback;
SoCallbackList m_interactionEndCallback;
- // Keep track of the frames-per-second counter.
- std::vector frames;
- float totaldraw;
+ double frametime;
+ double drawtime;
double starttime;
int framecount;
diff --git a/src/Gui/SceneInspector.cpp b/src/Gui/SceneInspector.cpp
index 87bbf42253..9d87cf62cc 100644
--- a/src/Gui/SceneInspector.cpp
+++ b/src/Gui/SceneInspector.cpp
@@ -25,6 +25,7 @@
#ifndef _PreComp_
# include
# include
+# include
#endif
#include "SceneInspector.h"
@@ -102,12 +103,21 @@ void SceneModel::setNode(QModelIndex index, SoNode* node)
setNode(this->index(i, 0, index), child);
QHash::iterator it = nodeNames.find(child);
- if (it != nodeNames.end()) {
- this->setData(this->index(i, 1, index), QVariant(it.value()));
- }
- else {
- this->setData(this->index(i, 1, index), QVariant(QString::fromLatin1(child->getName())));
+ QString name;
+ QTextStream stream(&name);
+ stream << child << ", ";
+ if(child->isOfType(SoSwitch::getClassTypeId())) {
+ auto pcSwitch = static_cast(child);
+ stream << pcSwitch->whichChild.getValue() << ", ";
+ } else if (child->isOfType(SoSeparator::getClassTypeId())) {
+ auto pcSeparator = static_cast(child);
+ stream << pcSeparator->renderCaching.getValue() << ", ";
}
+ if (it != nodeNames.end())
+ stream << it.value();
+ else
+ stream << child->getName();
+ this->setData(this->index(i, 1, index), QVariant(name));
}
}
// insert icon
diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp
index df2cafa485..3c9c7fd7be 100644
--- a/src/Gui/SoFCDB.cpp
+++ b/src/Gui/SoFCDB.cpp
@@ -122,6 +122,9 @@ void Gui::SoFCDB::init()
MarkerBitmaps ::initClass();
SoFCCSysDragger ::initClass();
SmSwitchboard ::initClass();
+ SoFCSeparator ::initClass();
+ SoFCSelectionRoot ::initClass();
+ SoFCPathAnnotation ::initClass();
PropertyItem ::init();
PropertySeparatorItem ::init();
@@ -203,6 +206,9 @@ void Gui::SoFCDB::finish()
SoFCSelectionColorAction ::finish();
SoUpdateVBOAction ::finish();
SoFCHighlightColorAction ::finish();
+ SoFCSeparator ::finish();
+ SoFCSelectionRoot ::finish();
+ SoFCPathAnnotation ::finish();
storage->unref();
storage = nullptr;
diff --git a/src/Gui/SoFCInteractiveElement.cpp b/src/Gui/SoFCInteractiveElement.cpp
index c5bb38fdb2..4b60fe1715 100644
--- a/src/Gui/SoFCInteractiveElement.cpp
+++ b/src/Gui/SoFCInteractiveElement.cpp
@@ -23,6 +23,7 @@
#include "PreCompiled.h"
+#include
#include "SoFCInteractiveElement.h"
using namespace Gui;
@@ -248,6 +249,16 @@ void SoGLVBOActivatedElement::get(SoState * state, SbBool& active)
const SoGLVBOActivatedElement* self = static_cast
(SoElement::getConstElement(state, classStackIndex));
active = self->active;
+ if(active) {
+ uint32_t flags = SoOverrideElement::getFlags(state);
+ if(flags & (SoOverrideElement::COLOR_INDEX|
+ SoOverrideElement::DIFFUSE_COLOR|
+ SoOverrideElement::MATERIAL_BINDING|
+ SoOverrideElement::TRANSPARENCY|
+ SoOverrideElement::NORMAL_VECTOR|
+ SoOverrideElement::NORMAL_BINDING))
+ active = false;
+ }
}
void SoGLVBOActivatedElement::push(SoState * state)
diff --git a/src/Gui/SoFCSelection.cpp b/src/Gui/SoFCSelection.cpp
index 2eec373bbd..58c15aa728 100644
--- a/src/Gui/SoFCSelection.cpp
+++ b/src/Gui/SoFCSelection.cpp
@@ -54,13 +54,20 @@
#include "Selection.h"
#include "SoFCSelectionAction.h"
#include "SoFCInteractiveElement.h"
+#include "SoFCUnifiedSelection.h"
+#include "ViewParams.h"
// For 64-bit system the method using the front buffer doesn't work at all for lines.
// Thus, use the method which forces a redraw every time. This is a bit slower but at
// least it works.
-#if defined(_OCC64) // is set by configure or cmake
+//
+// Disable front buffer in all cases, in order to spare the repeating logic of
+// handling selection contextn. SoFCSelection is not really used that much
+// anyway.
+//
+// #if defined(_OCC64) // is set by configure or cmake
# define NO_FRONTBUFFER
-#endif
+// #endif
using namespace Gui;
@@ -87,6 +94,7 @@ SoFCSelection::SoFCSelection()
SO_NODE_ADD_FIELD(documentName, (""));
SO_NODE_ADD_FIELD(objectName, (""));
SO_NODE_ADD_FIELD(subElementName, (""));
+ SO_NODE_ADD_FIELD(useNewSelection, (true));
SO_NODE_DEFINE_ENUM_VALUE(Styles, EMISSIVE);
SO_NODE_DEFINE_ENUM_VALUE(Styles, EMISSIVE_DIFFUSE);
@@ -111,6 +119,10 @@ SoFCSelection::SoFCSelection()
bCtrl = false;
selected = NOTSELECTED;
+
+ useNewSelection = ViewParams::instance()->getUseNewSelection();
+ selContext = std::make_shared();
+ selContext2 = std::make_shared();
}
/*!
@@ -151,6 +163,46 @@ SoFCSelection::turnOffCurrentHighlight(SoGLRenderAction * action)
void SoFCSelection::doAction(SoAction *action)
{
+ if(useNewSelection.getValue() && action->getCurPathCode()!=SoAction::OFF_PATH) {
+ if (action->getTypeId() == Gui::SoHighlightElementAction::getClassTypeId()) {
+ Gui::SoHighlightElementAction* hlaction = static_cast(action);
+ if(!hlaction->isHighlighted()) {
+ auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
+ if(ctx->isHighlighted()) {
+ ctx->highlightIndex = -1;
+ touch();
+ }
+ }else{
+ auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
+ ctx->highlightColor = hlaction->getColor();
+ if(!ctx->isHighlighted()) {
+ ctx->highlightIndex = 0;
+ touch();
+ }
+ }
+ return;
+ } else if (action->getTypeId() == Gui::SoSelectionElementAction::getClassTypeId()) {
+ Gui::SoSelectionElementAction* selaction = static_cast(action);
+ if (selaction->getType() == Gui::SoSelectionElementAction::All ||
+ selaction->getType() == Gui::SoSelectionElementAction::Append) {
+ SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
+ ctx->selectionColor = selaction->getColor();
+ if(!ctx->isSelectAll()) {
+ ctx->selectAll();
+ this->touch();
+ }
+ } else if (selaction->getType() == Gui::SoSelectionElementAction::None ||
+ selaction->getType() == Gui::SoSelectionElementAction::Remove) {
+ SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
+ if(ctx && ctx->isSelected()) {
+ ctx->selectionIndex.clear();
+ this->touch();
+ }
+ }
+ return;
+ }
+ }
+
if (action->getTypeId() == SoFCDocumentAction::getClassTypeId()) {
SoFCDocumentAction *docaction = (SoFCDocumentAction*)action;
this->documentName = docaction->documentName;
@@ -164,84 +216,87 @@ void SoFCSelection::doAction(SoAction *action)
objaction->setHandled();
}
- if (action->getTypeId() == SoFCEnableHighlightAction::getClassTypeId()) {
- SoFCEnableHighlightAction *preaction = (SoFCEnableHighlightAction*)action;
- if (preaction->highlight) {
- this->highlightMode = SoFCSelection::AUTO;
- }
- else {
- this->highlightMode = SoFCSelection::OFF;
- }
- }
+ if(!useNewSelection.getValue()) {
- if (action->getTypeId() == SoFCEnableSelectionAction::getClassTypeId()) {
- SoFCEnableSelectionAction *selaction = (SoFCEnableSelectionAction*)action;
- if (selaction->selection) {
- this->selectionMode = SoFCSelection::SEL_ON;
- }
- else {
- this->selectionMode = SoFCSelection::SEL_OFF;
- if (selected.getValue() == SELECTED) {
- this->selected = NOTSELECTED;
+ if (action->getTypeId() == SoFCEnableHighlightAction::getClassTypeId()) {
+ SoFCEnableHighlightAction *preaction = (SoFCEnableHighlightAction*)action;
+ if (preaction->highlight) {
+ this->highlightMode = SoFCSelection::AUTO;
+ }
+ else {
+ this->highlightMode = SoFCSelection::OFF;
}
}
- }
- if (action->getTypeId() == SoFCSelectionColorAction::getClassTypeId()) {
- SoFCSelectionColorAction *colaction = (SoFCSelectionColorAction*)action;
- this->colorSelection = colaction->selectionColor;
- }
+ if (action->getTypeId() == SoFCEnableSelectionAction::getClassTypeId()) {
+ SoFCEnableSelectionAction *selaction = (SoFCEnableSelectionAction*)action;
+ if (selaction->selection) {
+ this->selectionMode = SoFCSelection::SEL_ON;
+ }
+ else {
+ this->selectionMode = SoFCSelection::SEL_OFF;
+ if (selected.getValue() == SELECTED) {
+ this->selected = NOTSELECTED;
+ }
+ }
+ }
- if (action->getTypeId() == SoFCHighlightColorAction::getClassTypeId()) {
- SoFCHighlightColorAction *colaction = (SoFCHighlightColorAction*)action;
- this->colorHighlight = colaction->highlightColor;
- }
+ if (action->getTypeId() == SoFCSelectionColorAction::getClassTypeId()) {
+ SoFCSelectionColorAction *colaction = (SoFCSelectionColorAction*)action;
+ this->colorSelection = colaction->selectionColor;
+ }
- if (selectionMode.getValue() == SEL_ON && action->getTypeId() == SoFCSelectionAction::getClassTypeId()) {
- SoFCSelectionAction *selaction = static_cast(action);
+ if (action->getTypeId() == SoFCHighlightColorAction::getClassTypeId()) {
+ SoFCHighlightColorAction *colaction = (SoFCHighlightColorAction*)action;
+ this->colorHighlight = colaction->highlightColor;
+ }
- if (selaction->SelChange.Type == SelectionChanges::AddSelection ||
- selaction->SelChange.Type == SelectionChanges::RmvSelection) {
- if (documentName.getValue() == selaction->SelChange.pDocName &&
- objectName.getValue() == selaction->SelChange.pObjectName &&
- (subElementName.getValue() == selaction->SelChange.pSubName ||
- *(selaction->SelChange.pSubName) == '\0') ) {
- if (selaction->SelChange.Type == SelectionChanges::AddSelection) {
- if(selected.getValue() == NOTSELECTED){
+ if (selectionMode.getValue() == SEL_ON && action->getTypeId() == SoFCSelectionAction::getClassTypeId()) {
+ SoFCSelectionAction *selaction = static_cast(action);
+
+ if (selaction->SelChange.Type == SelectionChanges::AddSelection ||
+ selaction->SelChange.Type == SelectionChanges::RmvSelection) {
+ if (documentName.getValue() == selaction->SelChange.pDocName &&
+ objectName.getValue() == selaction->SelChange.pObjectName &&
+ (subElementName.getValue() == selaction->SelChange.pSubName ||
+ *(selaction->SelChange.pSubName) == '\0') ) {
+ if (selaction->SelChange.Type == SelectionChanges::AddSelection) {
+ if(selected.getValue() == NOTSELECTED){
+ selected = SELECTED;
+ }
+ }
+ else {
+ if(selected.getValue() == SELECTED){
+ selected = NOTSELECTED;
+ }
+ }
+ return;
+ }
+ }
+ else if (selaction->SelChange.Type == SelectionChanges::ClrSelection) {
+ if (documentName.getValue() == selaction->SelChange.pDocName ||
+ strcmp(selaction->SelChange.pDocName,"") == 0){
+ if(selected.getValue() == SELECTED){
+ selected = NOTSELECTED;
+ }
+
+ }
+ }
+ else if (selaction->SelChange.Type == SelectionChanges::SetSelection) {
+ bool sel = Selection().isSelected(
+ documentName.getValue().getString(),
+ objectName.getValue().getString()/*,
+ subElementName.getValue().getString()*/);
+ if (sel) {
+ if (selected.getValue() == NOTSELECTED) {
selected = SELECTED;
}
}
else {
- if(selected.getValue() == SELECTED){
+ if (selected.getValue() == SELECTED) {
selected = NOTSELECTED;
}
}
- return;
- }
- }
- else if (selaction->SelChange.Type == SelectionChanges::ClrSelection) {
- if (documentName.getValue() == selaction->SelChange.pDocName ||
- strcmp(selaction->SelChange.pDocName,"") == 0){
- if(selected.getValue() == SELECTED){
- selected = NOTSELECTED;
- }
-
- }
- }
- else if (selaction->SelChange.Type == SelectionChanges::SetSelection) {
- bool sel = Selection().isSelected(
- documentName.getValue().getString(),
- objectName.getValue().getString()/*,
- subElementName.getValue().getString()*/);
- if (sel) {
- if (selected.getValue() == NOTSELECTED) {
- selected = SELECTED;
- }
- }
- else {
- if (selected.getValue() == SELECTED) {
- selected = NOTSELECTED;
- }
}
}
}
@@ -309,6 +364,11 @@ SoFCSelection::getPickedPoint(SoHandleEventAction* action) const
void
SoFCSelection::handleEvent(SoHandleEventAction * action)
{
+ if(useNewSelection.getValue()) {
+ inherited::handleEvent( action );
+ return;
+ }
+
static char buf[513];
HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
const SoEvent * event = action->getEvent();
@@ -337,12 +397,13 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
}
}
- snprintf(buf,512,"Preselected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
+ const auto &pt = pp->getPoint();
+ snprintf(buf,512,"Preselected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
- ,pp->getPoint()[0]
- ,pp->getPoint()[1]
- ,pp->getPoint()[2]);
+ ,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));
}
@@ -380,6 +441,7 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
// Otherwise the tree signals that an object is preselected even though it is hidden. (Werner)
const SoPickedPoint * pp = this->getPickedPoint(action);
if (pp && pp->getPath()->containsPath(action->getCurPath())) {
+ const auto &pt = pp->getPoint();
if (bCtrl) {
if (Gui::Selection().isSelected(documentName.getValue().getString()
,objectName.getValue().getString()
@@ -391,17 +453,15 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
- ,pp->getPoint()[0]
- ,pp->getPoint()[1]
- ,pp->getPoint()[2]);
+ ,pt[0] ,pt[1] ,pt[2]);
if (mymode == OFF) {
- snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
+ snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
- ,pp->getPoint()[0]
- ,pp->getPoint()[1]
- ,pp->getPoint()[2]);
+ ,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));
}
@@ -415,27 +475,22 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
- ,pp->getPoint()[0]
- ,pp->getPoint()[1]
- ,pp->getPoint()[2]);
+ ,pt[0] ,pt[1] ,pt[2]);
}
else {
Gui::Selection().clearSelection(documentName.getValue().getString());
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
- ,0
- ,pp->getPoint()[0]
- ,pp->getPoint()[1]
- ,pp->getPoint()[2]);
+ ,0 ,pt[0] ,pt[1] ,pt[2]);
}
if (mymode == OFF) {
- snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
+ snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
- ,pp->getPoint()[0]
- ,pp->getPoint()[1]
- ,pp->getPoint()[2]);
+ ,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));
}
@@ -544,6 +599,7 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
// Otherwise the tree signals that an object is preselected even though it is hidden. (Werner)
const SoPickedPoint * pp = this->getPickedPoint(action);
if (pp && pp->getPath()->containsPath(action->getCurPath())) {
+ const auto &pt = pp->getPoint();
if (bCtrl) {
if (Gui::Selection().isSelected(documentName.getValue().getString()
,objectName.getValue().getString()
@@ -556,17 +612,15 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
- ,pp->getPoint()[0]
- ,pp->getPoint()[1]
- ,pp->getPoint()[2]);
+ ,pt[0] ,pt[1] ,pt[2]);
if (mymode == OFF) {
- snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
+ snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
- ,pp->getPoint()[0]
- ,pp->getPoint()[1]
- ,pp->getPoint()[2]);
+ ,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));
}
@@ -580,27 +634,22 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
- ,pp->getPoint()[0]
- ,pp->getPoint()[1]
- ,pp->getPoint()[2]);
+ ,pt[0] ,pt[1] ,pt[2]);
}
else {
Gui::Selection().clearSelection(documentName.getValue().getString());
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
- ,0
- ,pp->getPoint()[0]
- ,pp->getPoint()[1]
- ,pp->getPoint()[2]);
+ ,0 ,pt[0] ,pt[1] ,pt[2]);
}
if (mymode == OFF) {
- snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
+ snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
- ,pp->getPoint()[0]
- ,pp->getPoint()[1]
- ,pp->getPoint()[2]);
+ ,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));
}
@@ -621,15 +670,24 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
void
SoFCSelection::GLRenderBelowPath(SoGLRenderAction * action)
{
+ SoState * state = action->getState();
+ SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext(this,selContext);
+ if(selContext2->checkGlobal(ctx))
+ ctx = selContext2;
+ if(!useNewSelection.getValue() && selContext == ctx) {
+ ctx->selectionColor = this->colorSelection.getValue();
+ ctx->highlightColor = this->colorHighlight.getValue();
+ if(this->selected.getValue()==SELECTED)
+ ctx->selectAll();
+ else
+ ctx->selectionIndex.clear();
+ ctx->highlightIndex = this->highlighted?0:-1;
+ }
+
#ifdef NO_FRONTBUFFER
// check if preselection is active
- HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
- bool preselected = highlighted && mymode == AUTO;
- SoState * state = action->getState();
state->push();
- if (preselected || this->highlightMode.getValue() == ON || this->selected.getValue() == SELECTED) {
- this->setOverride(action);
- }
+ this->setOverride(action,ctx);
inherited::GLRenderBelowPath(action);
state->pop();
#else
@@ -652,22 +710,65 @@ SoFCSelection::GLRenderBelowPath(SoGLRenderAction * action)
void SoFCSelection::GLRender(SoGLRenderAction * action)
{
+ SoState * state = action->getState();
+ SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext(this,selContext);
+ if(selContext2->checkGlobal(ctx))
+ ctx = selContext2;
+ if(!useNewSelection.getValue() && selContext == ctx) {
+ ctx->selectionColor = this->colorSelection.getValue();
+ ctx->highlightColor = this->colorHighlight.getValue();
+ if(this->selected.getValue()==SELECTED)
+ ctx->selectAll();
+ else
+ ctx->selectionIndex.clear();
+ ctx->highlightIndex = this->highlighted?0:-1;
+ }
+
+#ifdef NO_FRONTBUFFER
+ // check if preselection is active
+ state->push();
+ this->setOverride(action,ctx);
inherited::GLRender(action);
+ state->pop();
+#else
+ // Set up state for locate highlighting (if necessary)
+ GLint oldDepthFunc;
+ SbBool drawHighlighted = preRender(action, oldDepthFunc);
+
+ // now invoke the parent method
+ inherited::GLRender(action);
+
+ // Restore old depth buffer model if needed
+ if (drawHighlighted || highlighted)
+ glDepthFunc((GLenum)oldDepthFunc);
+
+ // Clean up state if needed
+ if (drawHighlighted)
+ action->getState()->pop();
+#endif
}
// doc from parent
void
SoFCSelection::GLRenderInPath(SoGLRenderAction * action)
{
+ SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext(this,selContext);
+ if(selContext2->checkGlobal(ctx))
+ ctx = selContext2;
+ if(!useNewSelection.getValue() && selContext == ctx) {
+ ctx->selectionColor = this->colorSelection.getValue();
+ ctx->highlightColor = this->colorHighlight.getValue();
+ if(this->selected.getValue()==SELECTED)
+ ctx->selectAll();
+ else
+ ctx->selectionIndex.clear();
+ ctx->highlightIndex = this->highlighted?0:-1;
+ }
#ifdef NO_FRONTBUFFER
// check if preselection is active
- HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
- bool preselected = highlighted && mymode == AUTO;
SoState * state = action->getState();
state->push();
- if (preselected || this->highlightMode.getValue() == ON || this->selected.getValue() == SELECTED) {
- this->setOverride(action);
- }
+ this->setOverride(action,ctx);
inherited::GLRenderInPath(action);
state->pop();
#else
@@ -848,24 +949,41 @@ SoFCSelection::readInstance ( SoInput * in, unsigned short flags )
// update override state before rendering
//
void
-SoFCSelection::setOverride(SoGLRenderAction * action)
+SoFCSelection::setOverride(SoGLRenderAction * action, SelContextPtr ctx)
{
+ HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
+ bool preselected = ctx && ctx->isHighlighted() && (useNewSelection.getValue()||mymode == AUTO);
+ if (!preselected && mymode!=ON && (!ctx || !ctx->isSelected()))
+ return;
+
+ // uniqueId is returned by SoNode::getNodeId(). It is used to notify change
+ // and for render cache update. In order to update cache on selection state
+ // change, We manually change the id here by using a combined hash of the
+ // original id and context pointer.
+ auto oldId = this->uniqueId;
+ this->uniqueId ^= std::hash()(ctx.get()) + 0x9e3779b9 + (oldId << 6) + (oldId >> 2);
+
//Base::Console().Log("SoFCSelection::setOverride() (%p)\n",this);
SoState * state = action->getState();
- if(this->selected.getValue() == SELECTED)
- SoLazyElement::setEmissive(state, &this->colorSelection.getValue());
- else
- SoLazyElement::setEmissive(state, &this->colorHighlight.getValue());
+
+ SoMaterialBindingElement::set(state,SoMaterialBindingElement::OVERALL);
+
+ if(!preselected)
+ SoLazyElement::setEmissive(state, &ctx->selectionColor);
+ else
+ SoLazyElement::setEmissive(state, &ctx->highlightColor);
SoOverrideElement::setEmissiveColorOverride(state, this, true);
Styles mystyle = (Styles) this->style.getValue();
if (mystyle == SoFCSelection::EMISSIVE_DIFFUSE) {
- if(this->selected.getValue() == SELECTED)
- SoLazyElement::setDiffuse(state, this,1, &this->colorSelection.getValue(),&colorpacker);
+ if(!preselected)
+ SoLazyElement::setDiffuse(state, this,1, &ctx->selectionColor,&colorpacker);
else
- SoLazyElement::setDiffuse(state, this,1, &this->colorHighlight.getValue(),&colorpacker);
+ SoLazyElement::setDiffuse(state, this,1, &ctx->highlightColor,&colorpacker);
SoOverrideElement::setDiffuseColorOverride(state, this, true);
}
+
+ this->uniqueId = oldId;
}
// private convenience method
diff --git a/src/Gui/SoFCSelection.h b/src/Gui/SoFCSelection.h
index 61e54ffa7a..64a00cffc9 100644
--- a/src/Gui/SoFCSelection.h
+++ b/src/Gui/SoFCSelection.h
@@ -41,6 +41,9 @@
#include
#include
#include
+#include
+#include
+#include "SoFCSelectionContext.h"
class SoFullPath;
class SoPickedPoint;
@@ -94,6 +97,7 @@ public:
SoSFString documentName;
SoSFString objectName;
SoSFString subElementName;
+ SoSFBool useNewSelection;
virtual void doAction(SoAction *action);
virtual void GLRender(SoGLRenderAction * action);
@@ -105,13 +109,20 @@ public:
protected:
virtual ~SoFCSelection();
+
+ typedef SoFCSelectionContext SelContext;
+ typedef std::shared_ptr SelContextPtr;
+ SelContextPtr selContext;
+ SelContextPtr selContext2;
+
virtual void redrawHighlighted(SoAction * act, SbBool flag);
+
virtual SbBool readInstance(SoInput * in, unsigned short flags);
private:
static int getPriority(const SoPickedPoint*);
static void turnoffcurrent(SoAction * action);
- void setOverride(SoGLRenderAction * action);
+ void setOverride(SoGLRenderAction * action, SelContextPtr);
SbBool isHighlighted(SoAction *action);
SbBool preRender(SoGLRenderAction *act, GLint &oldDepthFunc);
const SoPickedPoint* getPickedPoint(SoHandleEventAction*) const;
diff --git a/src/Gui/SoFCSelectionContext.cpp b/src/Gui/SoFCSelectionContext.cpp
new file mode 100644
index 0000000000..bd350cf5fe
--- /dev/null
+++ b/src/Gui/SoFCSelectionContext.cpp
@@ -0,0 +1,283 @@
+/****************************************************************************
+ * Copyright (c) 2018 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"
+#include
+#include
+#include
+#include
+#include "SoFCUnifiedSelection.h"
+#include "Selection.h"
+
+using namespace Gui;
+
+/////////////////////////////////////////////////////////////////////////////
+
+SoFCSelectionContext::~SoFCSelectionContext() {
+ if(counter)
+ *counter -= 1;
+}
+
+bool SoFCSelectionContext::checkGlobal(SoFCSelectionContextPtr ctx) {
+ bool sel = false;
+ bool hl = false;
+ SoFCSelectionRoot::checkSelection(sel,selectionColor,hl,highlightColor);
+ if(sel)
+ selectionIndex.insert(-1);
+ else if(ctx && hl) {
+ selectionColor = ctx->selectionColor;
+ selectionIndex = ctx->selectionIndex;
+ }else
+ selectionIndex.clear();
+ if(hl)
+ highlightAll();
+ else if(ctx && sel) {
+ highlightIndex = ctx->highlightIndex;
+ highlightColor = ctx->highlightColor;
+ }else
+ removeHighlight();
+ return sel||hl;
+}
+
+bool SoFCSelectionContext::removeIndex(int index) {
+ auto it = selectionIndex.find(index);
+ if(it != selectionIndex.end()) {
+ selectionIndex.erase(it);
+ return true;
+ }
+ return false;
+}
+
+int SoFCSelectionContext::merge(int status, SoFCSelectionContextBasePtr &output,
+ SoFCSelectionContextBasePtr input, SoFCSelectionRoot *)
+{
+ auto ctx = std::dynamic_pointer_cast(input);
+ if(!ctx)
+ return status;
+
+ if(ctx->selectionIndex.empty()) {
+ output = ctx;
+ return -1;
+ }
+
+ auto ret = std::dynamic_pointer_cast(output);
+ if(!ret) {
+ output = ctx;
+ return 0;
+ }
+
+ if(ctx->isSelectAll())
+ return status;
+
+ if(ret->isSelectAll()) {
+ if(!status) {
+ output = ret->copy();
+ ret = std::dynamic_pointer_cast(ret);
+ assert(ret);
+ }
+ ret->selectionIndex = ctx->selectionIndex;
+ return status;
+ }
+
+ std::vector remove;
+ for(auto idx : ret->selectionIndex) {
+ if(!ctx->selectionIndex.count(idx))
+ remove.push_back(idx);
+ }
+
+ for(auto idx : remove) {
+ if(!status) {
+ status = 1;
+ output = ret->copy();
+ ret = std::dynamic_pointer_cast(ret);
+ assert(ret);
+ }
+ ret->selectionIndex.erase(idx);
+ if(ret->selectionIndex.empty())
+ return -1;
+ }
+ return status;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+bool SoFCSelectionContextEx::setColors(
+ const std::map &colors, const std::string &element) {
+ std::map tmp;
+ auto it = colors.find("");
+ if(it!=colors.end())
+ tmp[-1] = it->second;
+ for(auto it=colors.lower_bound(element);it!=colors.end();++it) {
+ if(!boost::starts_with(it->first,element))
+ break;
+ if(it->first.size()==element.size())
+ tmp[-1] = it->second;
+ else {
+ int idx = std::atoi(it->first.c_str()+4);
+ if(idx>0) {
+ idx -= 1;
+ tmp[idx] = it->second;
+ }
+ }
+ }
+ if(tmp == this->colors)
+ return false;
+ this->colors.swap(tmp);
+ return true;
+}
+
+uint32_t SoFCSelectionContextEx::packColor(const App::Color &c, bool &hasTransparency) {
+ float trans = std::max(trans0,c.a);
+ if(trans>0)
+ hasTransparency = true;
+ return SbColor(c.r,c.g,c.b).getPackedValue(trans);
+}
+
+bool SoFCSelectionContextEx::applyColor(int idx, std::vector &packedColors, bool &hasTransparency) {
+ if(colors.empty())
+ return false;
+ auto it = colors.find(idx);
+ if(it==colors.end()) {
+ if(colors.begin()->first >= 0)
+ return false;
+ it = colors.begin();
+ }
+ packedColors.push_back(packColor(it->second,hasTransparency));
+ return true;
+}
+
+bool SoFCSelectionContextEx::isSingleColor(uint32_t &color, bool &hasTransparency) {
+ if(colors.size() && colors.begin()->first<0) {
+ color = packColor(colors.begin()->second,hasTransparency);
+ return colors.size()==1;
+ }
+ return false;
+}
+
+int SoFCSelectionContextEx::merge(int status, SoFCSelectionContextBasePtr &output,
+ SoFCSelectionContextBasePtr input, SoFCSelectionRoot *node)
+{
+ auto ctx = std::dynamic_pointer_cast(input);
+ if(!ctx) {
+ if(node && node->hasColorOverride()) {
+ if(!status)
+ status = 2;
+ else if(status == 1)
+ status = 3;
+ }
+ return status;
+ }
+
+ int status_copy = status;
+ if(status==2)
+ status_copy = 0;
+ else if(status==3)
+ status_copy = 1;
+ status_copy = SoFCSelectionContext::merge(status_copy,output,input,node);
+ if(status_copy < 0)
+ return status_copy;
+
+ if(status>1) {
+ // When status>1 it means there is color override before us, all
+ // subsequent color override will be bypassed
+ if(status_copy==1)
+ status = 3;
+ else
+ status = 2;
+ return status;
+ }
+
+ status = status_copy;
+ auto ret = std::dynamic_pointer_cast(output);
+ assert(ret);
+ for(auto &v : ctx->colors) {
+ if(ret->colors.count(v.first))
+ continue;
+ if(!status) {
+ status = 1;
+ output = ret->copy();
+ ret = std::dynamic_pointer_cast(output);
+ assert(ret);
+ }
+ ret->colors.insert(v);
+ }
+
+ if(node && node->hasColorOverride()) {
+ if(!status)
+ status = 2;
+ else if(status == 1)
+ status = 3;
+ }
+ return status;
+}
+
+///////////////////////////////////////////////////////////////////////
+
+SoFCSelectionCounter::SoFCSelectionCounter()
+ :counter(std::make_shared(0))
+ ,hasSelection(false)
+ ,hasPreselection(false)
+{}
+
+
+SoFCSelectionCounter::~SoFCSelectionCounter()
+{}
+
+
+bool SoFCSelectionCounter::checkRenderCache(SoState *state) {
+ if(*counter ||
+ (hasSelection && Selection().hasSelection()) ||
+ (hasPreselection && Selection().hasPreselection()))
+ {
+ if(SoFCSelectionRoot::getCacheMode()!=SoSeparator::OFF)
+ SoCacheElement::invalidate(state);
+ return false;
+ }
+ if(!Selection().hasPreselection())
+ hasPreselection = false;
+ if(!Selection().hasSelection())
+ hasSelection = false;
+ return true;
+}
+
+void SoFCSelectionCounter::checkAction(SoHighlightElementAction *hlaction) {
+ if(hlaction->isHighlighted())
+ hasPreselection = true;
+}
+
+void SoFCSelectionCounter::checkAction(SoSelectionElementAction *selaction, SoFCSelectionContextPtr ctx) {
+ switch(selaction->getType()) {
+ case SoSelectionElementAction::None:
+ return;
+ case SoSelectionElementAction::All:
+ case SoSelectionElementAction::Append:
+ hasSelection = true;
+ break;
+ default:
+ break;
+ }
+ if(selaction->isSecondary()) {
+ if(ctx && !ctx->counter) {
+ *counter += 1;
+ ctx->counter = counter;
+ }
+ }
+}
diff --git a/src/Gui/SoFCSelectionContext.h b/src/Gui/SoFCSelectionContext.h
new file mode 100644
index 0000000000..b87d013ffd
--- /dev/null
+++ b/src/Gui/SoFCSelectionContext.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+ * Copyright (c) 2018 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_SOFCSELECTIONCONTEXT_H
+#define GUI_SOFCSELECTIONCONTEXT_H
+
+#include