1
/***************************************************************************
2
* Copyright (c) 2005 Jürgen Riegel <juergen.riegel@web.de> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
27
# include <Inventor/SoFullPath.h>
28
# include <Inventor/SoPickedPoint.h>
29
# include <Inventor/actions/SoGLRenderAction.h>
30
# include <Inventor/actions/SoHandleEventAction.h>
31
# include <Inventor/details/SoFaceDetail.h>
32
# include <Inventor/details/SoLineDetail.h>
33
# include <Inventor/elements/SoLazyElement.h>
34
# include <Inventor/elements/SoMaterialBindingElement.h>
35
# include <Inventor/elements/SoOverrideElement.h>
36
# include <Inventor/elements/SoWindowElement.h>
37
# include <Inventor/events/SoKeyboardEvent.h>
38
# include <Inventor/events/SoLocation2Event.h>
39
# include <Inventor/events/SoMouseButtonEvent.h>
40
# include <Inventor/misc/SoState.h>
43
#include <Base/UnitsApi.h>
45
#include "SoFCSelection.h"
46
#include "MainWindow.h"
47
#include "SoFCSelectionAction.h"
48
#include "SoFCUnifiedSelection.h"
49
#include "ViewParams.h"
52
# define NO_FRONTBUFFER
58
void printPreselectionInfo(const char* documentName,
59
const char* objectName,
60
const char* subElementName,
61
float x, float y, float z,
65
SoFullPath * Gui::SoFCSelection::currenthighlight = nullptr;
68
// *************************************************************************
70
SO_NODE_SOURCE(SoFCSelection)
75
SoFCSelection::SoFCSelection()
77
SO_NODE_CONSTRUCTOR(SoFCSelection);
79
SO_NODE_ADD_FIELD(colorHighlight, (SbColor(0.8f, 0.1f, 0.1f)));
80
SO_NODE_ADD_FIELD(colorSelection, (SbColor(0.1f, 0.8f, 0.1f)));
81
SO_NODE_ADD_FIELD(style, (EMISSIVE));
82
SO_NODE_ADD_FIELD(highlightMode, (AUTO));
83
SO_NODE_ADD_FIELD(selectionMode, (SEL_ON));
84
SO_NODE_ADD_FIELD(selected, (NOTSELECTED));
85
SO_NODE_ADD_FIELD(documentName, (""));
86
SO_NODE_ADD_FIELD(objectName, (""));
87
SO_NODE_ADD_FIELD(subElementName, (""));
88
SO_NODE_ADD_FIELD(useNewSelection, (true));
90
SO_NODE_DEFINE_ENUM_VALUE(Styles, EMISSIVE);
91
SO_NODE_DEFINE_ENUM_VALUE(Styles, EMISSIVE_DIFFUSE);
92
SO_NODE_DEFINE_ENUM_VALUE(Styles, BOX);
93
SO_NODE_SET_SF_ENUM_TYPE(style, Styles);
95
SO_NODE_DEFINE_ENUM_VALUE(HighlightModes, AUTO);
96
SO_NODE_DEFINE_ENUM_VALUE(HighlightModes, ON);
97
SO_NODE_DEFINE_ENUM_VALUE(HighlightModes, OFF);
98
SO_NODE_SET_SF_ENUM_TYPE (highlightMode, HighlightModes);
100
SO_NODE_DEFINE_ENUM_VALUE(SelectionModes, SEL_ON);
101
SO_NODE_DEFINE_ENUM_VALUE(SelectionModes, SEL_OFF);
102
SO_NODE_SET_SF_ENUM_TYPE (selectionMode, SelectionModes);
104
SO_NODE_DEFINE_ENUM_VALUE(Selected, NOTSELECTED);
105
SO_NODE_DEFINE_ENUM_VALUE(Selected, SELECTED);
106
SO_NODE_SET_SF_ENUM_TYPE(selected, Selected);
112
selected = NOTSELECTED;
114
useNewSelection = ViewParams::instance()->getUseNewSelection();
115
selContext = std::make_shared<SelContext>();
116
selContext2 = std::make_shared<SelContext>();
122
SoFCSelection::~SoFCSelection()
124
// If we're being deleted and we're the current highlight,
125
// NULL out that variable
126
if (currenthighlight &&
127
(!currenthighlight->getTail()->isOfType(SoFCSelection::getClassTypeId()))) {
128
currenthighlight->unref();
129
currenthighlight = nullptr;
136
SoFCSelection::initClass()
138
SO_NODE_INIT_CLASS(SoFCSelection,SoGroup,"Group");
141
void SoFCSelection::finish()
147
Static method that can be used to turn off the current highlight.
150
SoFCSelection::turnOffCurrentHighlight(SoGLRenderAction * action)
152
SoFCSelection::turnoffcurrent(action);
155
void SoFCSelection::doAction(SoAction *action)
157
if(useNewSelection.getValue() && action->getCurPathCode()!=SoAction::OFF_PATH) {
158
if (action->getTypeId() == Gui::SoHighlightElementAction::getClassTypeId()) {
159
auto hlaction = static_cast<Gui::SoHighlightElementAction*>(action);
160
if (!hlaction->isHighlighted()) {
161
auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
162
if (ctx && ctx->isHighlighted()) {
163
ctx->highlightIndex = -1;
168
auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
170
ctx->highlightColor = hlaction->getColor();
171
if (!ctx->isHighlighted()) {
172
ctx->highlightIndex = 0;
179
else if (action->getTypeId() == Gui::SoSelectionElementAction::getClassTypeId()) {
180
auto selaction = static_cast<Gui::SoSelectionElementAction*>(action);
181
if (selaction->getType() == Gui::SoSelectionElementAction::All ||
182
selaction->getType() == Gui::SoSelectionElementAction::Append) {
183
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
185
ctx->selectionColor = selaction->getColor();
186
if(!ctx->isSelectAll()) {
192
else if (selaction->getType() == Gui::SoSelectionElementAction::None ||
193
selaction->getType() == Gui::SoSelectionElementAction::Remove) {
194
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
195
if (ctx && ctx->isSelected()) {
196
ctx->selectionIndex.clear();
204
if (action->getTypeId() == SoFCDocumentAction::getClassTypeId()) {
205
auto docaction = static_cast<SoFCDocumentAction*>(action);
206
this->documentName = docaction->documentName;
209
if (action->getTypeId() == SoFCDocumentObjectAction::getClassTypeId()) {
210
auto objaction = static_cast<SoFCDocumentObjectAction*>(action);
211
objaction->documentName = this->documentName.getValue();
212
objaction->objectName = this->objectName.getValue();
213
objaction->componentName = this->subElementName.getValue();
214
objaction->setHandled();
217
if(!useNewSelection.getValue()) {
219
if (action->getTypeId() == SoFCEnableHighlightAction::getClassTypeId()) {
220
auto preaction = static_cast<SoFCEnableHighlightAction*>(action);
221
if (preaction->highlight) {
222
this->highlightMode = SoFCSelection::AUTO;
225
this->highlightMode = SoFCSelection::OFF;
229
if (action->getTypeId() == SoFCEnableSelectionAction::getClassTypeId()) {
230
auto selaction = static_cast<SoFCEnableSelectionAction*>(action);
231
if (selaction->selection) {
232
this->selectionMode = SoFCSelection::SEL_ON;
235
this->selectionMode = SoFCSelection::SEL_OFF;
236
if (selected.getValue() == SELECTED) {
237
this->selected = NOTSELECTED;
242
if (action->getTypeId() == SoFCSelectionColorAction::getClassTypeId()) {
243
auto colaction = static_cast<SoFCSelectionColorAction*>(action);
244
this->colorSelection = colaction->selectionColor;
247
if (action->getTypeId() == SoFCHighlightColorAction::getClassTypeId()) {
248
auto colaction = static_cast<SoFCHighlightColorAction*>(action);
249
this->colorHighlight = colaction->highlightColor;
252
if (selectionMode.getValue() == SEL_ON && action->getTypeId() == SoFCSelectionAction::getClassTypeId()) {
253
auto selaction = static_cast<SoFCSelectionAction*>(action);
255
if (selaction->SelChange.Type == SelectionChanges::AddSelection ||
256
selaction->SelChange.Type == SelectionChanges::RmvSelection) {
257
if (documentName.getValue() == selaction->SelChange.pDocName &&
258
objectName.getValue() == selaction->SelChange.pObjectName &&
259
(subElementName.getValue() == selaction->SelChange.pSubName ||
260
*(selaction->SelChange.pSubName) == '\0') ) {
261
if (selaction->SelChange.Type == SelectionChanges::AddSelection) {
262
if(selected.getValue() == NOTSELECTED){
267
if(selected.getValue() == SELECTED){
268
selected = NOTSELECTED;
274
else if (selaction->SelChange.Type == SelectionChanges::ClrSelection) {
275
if (documentName.getValue() == selaction->SelChange.pDocName ||
276
strcmp(selaction->SelChange.pDocName,"") == 0){
277
if(selected.getValue() == SELECTED){
278
selected = NOTSELECTED;
283
else if (selaction->SelChange.Type == SelectionChanges::SetSelection) {
284
bool sel = Selection().isSelected(
285
documentName.getValue().getString(),
286
objectName.getValue().getString()/*,
287
subElementName.getValue().getString()*/);
289
if (selected.getValue() == NOTSELECTED) {
294
if (selected.getValue() == SELECTED) {
295
selected = NOTSELECTED;
302
inherited::doAction( action );
305
int SoFCSelection::getPriority(const SoPickedPoint* p)
307
const SoDetail* detail = p->getDetail();
310
if(detail->isOfType(SoFaceDetail::getClassTypeId()))
312
if(detail->isOfType(SoLineDetail::getClassTypeId()))
314
if(detail->isOfType(SoPointDetail::getClassTypeId()))
320
SoFCSelection::getPickedPoint(SoHandleEventAction* action) const
322
// To identify the picking of lines in a concave area we have to
323
// get all intersection points. If we have two or more intersection
324
// points where the first is of a face and the second of a line with
325
// almost similar coordinates we use the second point, instead.
326
const SoPickedPointList & points = action->getPickedPointList();
327
if (points.getLength() == 0)
329
else if (points.getLength() == 1)
332
const SoPickedPoint* picked = points[0];
334
int picked_prio = getPriority(picked);
335
const SbVec3f& picked_pt = picked->getPoint();
338
for(int i=1; i<points.getLength();i++) {
339
const SoPickedPoint* cur = points[i];
340
int cur_prio = getPriority(cur);
341
const SbVec3f& cur_pt = cur->getPoint();
343
if ((cur_prio > picked_prio) && picked_pt.equals(cur_pt, 0.01f)) {
345
picked_prio = cur_prio;
354
SoFCSelection::handleEvent(SoHandleEventAction * action)
356
if(useNewSelection.getValue()) {
357
inherited::handleEvent( action );
361
static char buf[513];
362
auto mymode = static_cast<HighlightModes>(this->highlightMode.getValue());
363
const SoEvent * event = action->getEvent();
365
// mouse move events for preselection
366
if (event->isOfType(SoLocation2Event::getClassTypeId())) {
367
// NOTE: If preselection is off then we do not check for a picked point because otherwise this search may slow
368
// down extremely the system on really big data sets. In this case we just check for a picked point if the data
369
// set has been selected.
370
if (mymode == AUTO || mymode == ON) {
371
const SoPickedPoint * pp = this->getPickedPoint(action);
372
if (pp && pp->getPath()->containsPath(action->getCurPath())) {
374
if (Gui::Selection().setPreselect(documentName.getValue().getString()
375
,objectName.getValue().getString()
376
,subElementName.getValue().getString()
379
,pp->getPoint()[2])){
380
SoFCSelection::turnoffcurrent(action);
381
SoFCSelection::currenthighlight = static_cast<SoFullPath*>(action->getCurPath()->copy());
382
SoFCSelection::currenthighlight->ref();
384
this->touch(); // force scene redraw
385
this->redrawHighlighted(action, true);
389
const auto &pt = pp->getPoint();
391
printPreselectionInfo(documentName.getValue().getString(),
392
objectName.getValue().getString(),
393
subElementName.getValue().getString(),
394
pt[0], pt[1], pt[2], 1e-7);
396
else { // picked point
399
SoFCSelection::turnoffcurrent(action);
400
//FIXME: I think we should set 'highlighted' to false whenever no point is picked
403
Gui::Selection().rmvPreselect();
407
} // key press events
408
else if (event->isOfType(SoKeyboardEvent ::getClassTypeId())) {
409
auto const e = static_cast<const SoKeyboardEvent *>(event);
410
if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_SHIFT) ||
411
SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_SHIFT) )
413
if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_SHIFT) ||
414
SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_SHIFT) )
416
if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_CONTROL) ||
417
SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_CONTROL) )
419
if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_CONTROL) ||
420
SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_CONTROL) )
422
} // mouse press events for (de)selection
423
else if (event->isOfType(SoMouseButtonEvent::getClassTypeId())) {
424
auto const e = static_cast<const SoMouseButtonEvent *>(event);
425
if (SoMouseButtonEvent::isButtonReleaseEvent(e,SoMouseButtonEvent::BUTTON1)) {
426
//FIXME: Shouldn't we remove the preselection for newly selected objects?
427
// Otherwise the tree signals that an object is preselected even though it is hidden. (Werner)
428
const SoPickedPoint * pp = this->getPickedPoint(action);
429
if (pp && pp->getPath()->containsPath(action->getCurPath())) {
430
const auto &pt = pp->getPoint();
432
if (Gui::Selection().isSelected(documentName.getValue().getString()
433
,objectName.getValue().getString()
434
,subElementName.getValue().getString())) {
435
Gui::Selection().rmvSelection(documentName.getValue().getString()
436
,objectName.getValue().getString()
437
,subElementName.getValue().getString());
439
Gui::Selection().addSelection(documentName.getValue().getString()
440
,objectName.getValue().getString()
441
,subElementName.getValue().getString()
442
,pt[0] ,pt[1] ,pt[2]);
445
snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
446
,objectName.getValue().getString()
447
,subElementName.getValue().getString()
448
,fabs(pt[0])>1e-7?pt[0]:0.0
449
,fabs(pt[1])>1e-7?pt[1]:0.0
450
,fabs(pt[2])>1e-7?pt[2]:0.0);
452
getMainWindow()->showMessage(QString::fromLatin1(buf));
457
if (!Gui::Selection().isSelected(documentName.getValue().getString()
458
,objectName.getValue().getString()
459
,subElementName.getValue().getString())) {
460
Gui::Selection().clearSelection(documentName.getValue().getString());
461
Gui::Selection().addSelection(documentName.getValue().getString()
462
,objectName.getValue().getString()
463
,subElementName.getValue().getString()
464
,pt[0] ,pt[1] ,pt[2]);
467
Gui::Selection().clearSelection(documentName.getValue().getString());
468
Gui::Selection().addSelection(documentName.getValue().getString()
469
,objectName.getValue().getString()
470
,nullptr ,pt[0] ,pt[1] ,pt[2]);
474
snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
475
,objectName.getValue().getString()
476
,subElementName.getValue().getString()
477
,fabs(pt[0])>1e-7?pt[0]:0.0
478
,fabs(pt[1])>1e-7?pt[1]:0.0
479
,fabs(pt[2])>1e-7?pt[2]:0.0);
481
getMainWindow()->showMessage(QString::fromLatin1(buf));
485
action->setHandled();
490
inherited::handleEvent(action);
492
// If we don't need to pick for locate highlighting,
493
// then just behave as separator and return.
494
// NOTE: we still have to pick for ON even though we don't have
495
// to re-render, because the app needs to be notified as the mouse
496
// goes over locate highlight nodes.
497
//if (highlightMode.getValue() == OFF) {
498
// inherited::handleEvent( action );
504
// If this is a mouseMotion event, then check for locate highlighting
506
if (event->isOfType(SoLocation2Event::getClassTypeId())) {
507
// check to see if the mouse is over our geometry...
508
SbBool underTheMouse = false;
509
const SoPickedPoint * pp = this->getPickedPoint(action);
510
SoFullPath *pPath = (pp != NULL) ? (SoFullPath *) pp->getPath() : NULL;
511
if (pPath && pPath->containsPath(action->getCurPath())) {
512
// Make sure I'm the lowest LocHL in the pick path!
513
underTheMouse = true;
514
for (int i = 0; i < pPath->getLength(); i++) {
515
SoNode *node = pPath->getNodeFromTail(i);
516
if (node->isOfType(SoFCSelection::getClassTypeId())) {
518
underTheMouse = false;
519
break; // found the lowest LocHL - look no further
523
// Am I currently highlighted?
524
if (isHighlighted(action)) {
525
if (! underTheMouse) {
526
// re-draw the object with it's normal color
528
redrawHighlighted(action, false);
529
Gui::Selection().rmvPreselect();
532
action->setHandled();
533
//const SoPickedPoint * pp = action->getPickedPoint();
534
Gui::Selection().setPreselectCoord(pp->getPoint()[0]
539
// Else I am not currently highlighted
541
// If under the mouse, then highlight!
543
// draw this object highlighted
545
redrawHighlighted(action, true);
546
//const SoPickedPoint * pp = action->getPickedPoint();
547
Gui::Selection().setPreselect(documentName.getValue().getString()
548
,objectName.getValue().getString()
549
,subElementName.getValue().getString()
557
else if (event->isOfType(SoKeyboardEvent ::getClassTypeId())) {
558
const SoKeyboardEvent * const e = static_cast<const SoKeyboardEvent *>(event);
559
if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_SHIFT) ||
560
SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_SHIFT) )
562
if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_SHIFT) ||
563
SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_SHIFT) )
565
if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_CONTROL) ||
566
SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_CONTROL) )
568
if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_CONTROL) ||
569
SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_CONTROL) )
572
// mouse press events for (de)selection (only if selection is enabled on this node)
573
else if (event->isOfType(SoMouseButtonEvent::getClassTypeId()) &&
574
selectionMode.getValue() == SoFCSelection::SEL_ON) {
575
const SoMouseButtonEvent * const e = static_cast<const SoMouseButtonEvent *>(event);
576
if (SoMouseButtonEvent::isButtonReleaseEvent(e,SoMouseButtonEvent::BUTTON1)) {
577
//FIXME: Shouldn't we remove the preselection for newly selected objects?
578
// Otherwise the tree signals that an object is preselected even though it is hidden. (Werner)
579
const SoPickedPoint * pp = this->getPickedPoint(action);
580
if (pp && pp->getPath()->containsPath(action->getCurPath())) {
581
const auto &pt = pp->getPoint();
583
if (Gui::Selection().isSelected(documentName.getValue().getString()
584
,objectName.getValue().getString()
585
,subElementName.getValue().getString())) {
586
Gui::Selection().rmvSelection(documentName.getValue().getString()
587
,objectName.getValue().getString()
588
,subElementName.getValue().getString());
591
Gui::Selection().addSelection(documentName.getValue().getString()
592
,objectName.getValue().getString()
593
,subElementName.getValue().getString()
594
,pt[0] ,pt[1] ,pt[2]);
597
snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
598
,objectName.getValue().getString()
599
,subElementName.getValue().getString()
600
,fabs(pt[0])>1e-7?pt[0]:0.0
601
,fabs(pt[1])>1e-7?pt[1]:0.0
602
,fabs(pt[2])>1e-7?pt[2]:0.0);
604
getMainWindow()->showMessage(QString::fromLatin1(buf));
609
if (!Gui::Selection().isSelected(documentName.getValue().getString()
610
,objectName.getValue().getString()
611
,subElementName.getValue().getString())) {
612
Gui::Selection().clearSelection(documentName.getValue().getString());
613
Gui::Selection().addSelection(documentName.getValue().getString()
614
,objectName.getValue().getString()
615
,subElementName.getValue().getString()
616
,pt[0] ,pt[1] ,pt[2]);
619
Gui::Selection().clearSelection(documentName.getValue().getString());
620
Gui::Selection().addSelection(documentName.getValue().getString()
621
,objectName.getValue().getString()
622
,0 ,pt[0] ,pt[1] ,pt[2]);
626
snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
627
,objectName.getValue().getString()
628
,subElementName.getValue().getString()
629
,fabs(pt[0])>1e-7?pt[0]:0.0
630
,fabs(pt[1])>1e-7?pt[1]:0.0
631
,fabs(pt[2])>1e-7?pt[2]:0.0);
633
getMainWindow()->showMessage(QString::fromLatin1(buf));
637
action->setHandled();
642
// Let the base class traverse the children.
643
if (action->getGrabber() != this)
644
inherited::handleEvent(action);
650
SoFCSelection::GLRenderBelowPath(SoGLRenderAction * action)
652
SoState * state = action->getState();
653
SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext);
654
if(selContext2->checkGlobal(ctx))
656
if(!useNewSelection.getValue() && selContext == ctx) {
657
ctx->selectionColor = this->colorSelection.getValue();
658
ctx->highlightColor = this->colorHighlight.getValue();
659
if(this->selected.getValue()==SELECTED)
662
ctx->selectionIndex.clear();
663
ctx->highlightIndex = this->highlighted?0:-1;
667
// check if preselection is active
668
if(this->setOverride(action,ctx)) {
669
inherited::GLRenderBelowPath(action);
672
inherited::GLRenderBelowPath(action);
674
// Set up state for locate highlighting (if necessary)
676
SbBool drawHighlighted = preRender(action, oldDepthFunc);
678
// now invoke the parent method
679
inherited::GLRenderBelowPath(action);
681
// Restore old depth buffer model if needed
682
if (drawHighlighted || highlighted)
683
glDepthFunc((GLenum)oldDepthFunc);
685
// Clean up state if needed
687
action->getState()->pop();
691
void SoFCSelection::GLRender(SoGLRenderAction * action)
693
SoState * state = action->getState();
694
SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext);
695
if(selContext2->checkGlobal(ctx))
697
if(!useNewSelection.getValue() && selContext == ctx) {
698
ctx->selectionColor = this->colorSelection.getValue();
699
ctx->highlightColor = this->colorHighlight.getValue();
700
if(this->selected.getValue()==SELECTED)
703
ctx->selectionIndex.clear();
704
ctx->highlightIndex = this->highlighted?0:-1;
708
// check if preselection is active
709
if(this->setOverride(action,ctx)) {
710
inherited::GLRender(action);
713
inherited::GLRender(action);
715
// Set up state for locate highlighting (if necessary)
717
SbBool drawHighlighted = preRender(action, oldDepthFunc);
719
// now invoke the parent method
720
inherited::GLRender(action);
722
// Restore old depth buffer model if needed
723
if (drawHighlighted || highlighted)
724
glDepthFunc((GLenum)oldDepthFunc);
726
// Clean up state if needed
728
action->getState()->pop();
734
SoFCSelection::GLRenderInPath(SoGLRenderAction * action)
736
SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext);
737
if(selContext2->checkGlobal(ctx))
739
if(!useNewSelection.getValue() && selContext == ctx) {
740
ctx->selectionColor = this->colorSelection.getValue();
741
ctx->highlightColor = this->colorHighlight.getValue();
742
if(this->selected.getValue()==SELECTED)
745
ctx->selectionIndex.clear();
746
ctx->highlightIndex = this->highlighted?0:-1;
749
// check if preselection is active
750
SoState * state = action->getState();
751
if(this->setOverride(action,ctx)) {
752
inherited::GLRenderInPath(action);
755
inherited::GLRenderInPath(action);
757
// Set up state for locate highlighting (if necessary)
759
SbBool drawHighlighted = preRender(action, oldDepthFunc);
761
// now invoke the parent method
762
inherited::GLRenderInPath(action);
764
// Restore old depth buffer model if needed
765
if (drawHighlighted || highlighted)
766
glDepthFunc((GLenum)oldDepthFunc);
768
// Clean up state if needed
770
action->getState()->pop();
775
SoFCSelection::preRender(SoGLRenderAction *action, GLint &oldDepthFunc)
777
////////////////////////////////////////////////////////////////////////
779
// If not performing locate highlighting, just return.
780
if (highlightMode.getValue() == OFF)
783
SoState *state = action->getState();
785
// ??? prevent caching at this level - for some reason the
786
// ??? SoWindowElement::copyMatchInfo() method get called, which should
787
// ??? never be called. We are not caching this node correctly yet....
788
//SoCacheElement::invalidate(state);
790
SbBool drawHighlighted = (highlightMode.getValue() == ON || isHighlighted(action) || selected.getValue() == SELECTED);
792
if (drawHighlighted) {
793
// prevent diffuse & emissive color from leaking out...
796
if (selected.getValue() == SELECTED)
797
col = colorSelection.getValue();
799
col = colorHighlight.getValue();
802
SoLazyElement::setEmissive(state, &col);
803
SoOverrideElement::setEmissiveColorOverride(state, this, true);
806
if (style.getValue() == EMISSIVE_DIFFUSE) {
807
SoLazyElement::setDiffuse(state, this, 1, &col, &colorpacker);
808
SoOverrideElement::setDiffuseColorOverride(state, this, true);
812
// Draw on top of other things at same z-buffer depth if:
813
// [a] we're highlighted
814
// [b] this is the highlighting pass. This occurs when changing from
815
// non-hilit to lit OR VICE VERSA.
816
// Otherwise, leave it alone...
817
if (drawHighlighted || highlighted) {
818
glGetIntegerv(GL_DEPTH_FUNC, &oldDepthFunc);
819
if (oldDepthFunc != GL_LEQUAL)
820
glDepthFunc(GL_LEQUAL);
823
return drawHighlighted;
827
Empty method in Coin. Can be used by subclasses to be told
831
SoFCSelection::redrawHighlighted(SoAction * action , SbBool doHighlight )
833
//Base::Console().Log("SoFCSelection::redrawHighlighted() (%p) doHigh=%d \n",this,doHighlight?1:0);
837
Q_UNUSED(doHighlight);
839
// If we are about to highlight, and there is something else highlighted,
840
// that something else needs to unhighlight.
841
if (doHighlight && currenthighlight &&
842
!(*(static_cast<SoFullPath *>(action->getCurPath())) == *currenthighlight)) {
844
SoNode *tail = currenthighlight->getTail();
845
if (tail->isOfType( SoFCSelection::getClassTypeId())) {
846
static_cast<SoFCSelection *>(tail)->redrawHighlighted(action, false);
849
// Just get rid of the path. It's no longer valid for redraw.
850
currenthighlight->unref();
851
currenthighlight = nullptr;
855
SoPath *pathToRender;
856
// save the path to ourself for later de-highlight
858
if (currenthighlight)
859
currenthighlight->unref();
860
currenthighlight = static_cast<SoFullPath *>(action->getCurPath()->copy());
861
currenthighlight->ref();
863
// We will be rendering this new path to highlight it
864
pathToRender = currenthighlight;
867
// delete our path if we are no longer highlighted
869
if (currenthighlight) {
870
// We will be rendering this old path to unhighlight it
871
pathToRender = currenthighlight;
874
currenthighlight->unref();
875
currenthighlight = nullptr;
879
// If highlighting is forced on for this node, we don't need this special render.
880
if (highlightMode.getValue() != AUTO) {
881
pathToRender->unref();
885
SoState *state = action->getState();
888
SoGLRenderAction *glAction;
889
SoGLWidgetElement::get(state, window);
890
SoGLRenderActionElement::get(state, glAction);
892
// If we don't have a current window, then simply return...
893
if (!window /*|| context == NULL || display == NULL*/ || !glAction)
896
window->makeCurrent();
898
// set the current window
899
//glXMakeCurrent(display, window, context);
901
// render into the front buffer (save the current buffering type)
903
glGetIntegerv(GL_DRAW_BUFFER, &whichBuffer);
904
if (whichBuffer != GL_FRONT)
905
glDrawBuffer(GL_FRONT);
908
glAction->apply(pathToRender);
911
// restore the buffering type
912
if (whichBuffer != GL_FRONT)
913
glDrawBuffer((GLenum)whichBuffer);
916
pathToRender->unref();
921
SoFCSelection::readInstance ( SoInput * in, unsigned short flags )
923
// Note: The read in document name can be false, so the caller must ensure pointing to the correct document
924
SbBool ret = inherited::readInstance(in, flags);
928
// update override state before rendering
931
SoFCSelection::setOverride(SoGLRenderAction * action, SelContextPtr ctx)
933
auto mymode = static_cast<HighlightModes>(this->highlightMode.getValue());
934
bool preselected = ctx && ctx->isHighlighted() && (useNewSelection.getValue()||mymode == AUTO);
935
if (!preselected && mymode!=ON && (!ctx || !ctx->isSelected()))
938
// uniqueId is returned by SoNode::getNodeId(). It is used to notify change
939
// and for render cache update. In order to update cache on selection state
940
// change, We manually change the id here by using a combined hash of the
941
// original id and context pointer.
942
auto oldId = this->uniqueId;
943
this->uniqueId ^= std::hash<void*>()(ctx.get()) + 0x9e3779b9 + (oldId << 6) + (oldId >> 2);
945
auto mystyle = static_cast<Styles>(this->style.getValue());
947
if (mystyle == SoFCSelection::BOX) {
949
SoFCSelectionRoot::renderBBox(
950
action, this, preselected ? ctx->highlightColor : ctx->selectionColor);
952
this->uniqueId = oldId;
956
//Base::Console().Log("SoFCSelection::setOverride() (%p)\n",this);
957
SoState * state = action->getState();
960
SoMaterialBindingElement::set(state,SoMaterialBindingElement::OVERALL);
961
SoOverrideElement::setMaterialBindingOverride(state,this,true);
963
if (!preselected && ctx)
964
SoLazyElement::setEmissive(state, &ctx->selectionColor);
966
SoLazyElement::setEmissive(state, &ctx->highlightColor);
967
SoOverrideElement::setEmissiveColorOverride(state, this, true);
969
if(SoLazyElement::getLightModel(state)==SoLazyElement::BASE_COLOR
970
|| mystyle == SoFCSelection::EMISSIVE_DIFFUSE)
972
if (!preselected && ctx)
973
SoLazyElement::setDiffuse(state, this, 1, &ctx->selectionColor,&colorpacker);
975
SoLazyElement::setDiffuse(state, this, 1, &ctx->highlightColor,&colorpacker);
976
SoOverrideElement::setDiffuseColorOverride(state, this, true);
979
this->uniqueId = oldId;
983
// private convenience method
985
SoFCSelection::turnoffcurrent(SoAction * action)
988
if (SoFCSelection::currenthighlight &&
989
SoFCSelection::currenthighlight->getLength()) {
990
SoNode * tail = SoFCSelection::currenthighlight->getTail();
991
if (tail->isOfType(SoFCSelection::getClassTypeId())) {
992
static_cast<SoFCSelection*>(tail)->highlighted = false;
993
static_cast<SoFCSelection*>(tail)->touch(); // force scene redraw
995
static_cast<SoFCSelection*>(tail)->redrawHighlighted(action, false);
998
if (SoFCSelection::currenthighlight) {
999
SoFCSelection::currenthighlight->unref();
1000
SoFCSelection::currenthighlight = nullptr;
1003
if (!currenthighlight)
1006
SoNode *tail = currenthighlight->getTail();
1007
if (tail->isOfType(SoFCSelection::getClassTypeId())) {
1009
// don't redraw if we already are in the middle of rendering
1010
// (processing events during render abort might cause this)
1011
SoState *state = action->getState();
1012
if (state && state->getDepth() == 1)
1013
static_cast<SoFCSelection *>(tail)->redrawHighlighted(action, false);
1016
// Just get rid of the path. It's no longer valid for redraw.
1017
currenthighlight->unref();
1018
currenthighlight = nullptr;
1024
SoFCSelection::isHighlighted(SoAction *action)
1026
////////////////////////////////////////////////////////////////////////
1028
auto actionPath = static_cast<const SoFullPath *>(action->getCurPath());
1029
return (currenthighlight &&
1030
currenthighlight->getTail() == actionPath->getTail() && // nested SoHL!
1031
*currenthighlight == *actionPath);
1034
void SoFCSelection::applySettings ()
1036
// TODO Some view providers got copy of this code: make them use this (2015-09-03, Fat-Zer)
1037
// Note: SoFCUnifiedSelection got the same code, keep in sync or think about a way to share it
1039
ParameterGrp::handle hGrp = Gui::WindowParameter::getDefaultParameter()->GetGroup("View");
1040
bool enablePre = hGrp->GetBool("EnablePreselection", true);
1041
bool enableSel = hGrp->GetBool("EnableSelection", true);
1043
this->highlightMode = Gui::SoFCSelection::OFF;
1046
// Search for a user defined value with the current color as default
1047
SbColor highlightColor = this->colorHighlight.getValue();
1048
auto highlight = (unsigned long)(highlightColor.getPackedValue());
1049
highlight = hGrp->GetUnsigned("HighlightColor", highlight);
1050
highlightColor.setPackedValue((uint32_t)highlight, transparency);
1051
this->colorHighlight.setValue(highlightColor);
1054
this->selectionMode = Gui::SoFCSelection::SEL_OFF;
1057
// Do the same with the selection color
1058
SbColor selectionColor = this->colorSelection.getValue();
1059
auto selection = (unsigned long)(selectionColor.getPackedValue());
1060
selection = hGrp->GetUnsigned("SelectionColor", selection);
1061
selectionColor.setPackedValue((uint32_t)selection, transparency);
1062
this->colorSelection.setValue(selectionColor);