FreeCAD

Форк
0
/
SoFCSelection.cpp 
1064 строки · 43.8 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2005 Jürgen Riegel <juergen.riegel@web.de>              *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24

25
#ifndef _PreComp_
26
# include <QString>
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>
41
#endif
42

43
#include <Base/UnitsApi.h>
44

45
#include "SoFCSelection.h"
46
#include "MainWindow.h"
47
#include "SoFCSelectionAction.h"
48
#include "SoFCUnifiedSelection.h"
49
#include "ViewParams.h"
50

51

52
# define NO_FRONTBUFFER
53

54

55
using namespace Gui;
56

57
namespace Gui {
58
void printPreselectionInfo(const char* documentName,
59
                           const char* objectName,
60
                           const char* subElementName,
61
                           float x, float y, float z,
62
                           double precision);
63
}
64

65
SoFullPath * Gui::SoFCSelection::currenthighlight = nullptr;
66

67

68
// *************************************************************************
69

70
SO_NODE_SOURCE(SoFCSelection)
71

72
/*!
73
  Constructor.
74
*/
75
SoFCSelection::SoFCSelection()
76
{
77
    SO_NODE_CONSTRUCTOR(SoFCSelection);
78

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));
89

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);
94

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);
99

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);
103

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);
107

108
    highlighted = false;
109
    bShift      = false;
110
    bCtrl       = false;
111

112
    selected = NOTSELECTED;
113

114
    useNewSelection = ViewParams::instance()->getUseNewSelection();
115
    selContext = std::make_shared<SelContext>();
116
    selContext2 = std::make_shared<SelContext>();
117
}
118

119
/*!
120
  Destructor.
121
*/
122
SoFCSelection::~SoFCSelection()
123
{
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;
130
    }
131
    //delete THIS;
132
}
133

134
// doc from parent
135
void
136
SoFCSelection::initClass()
137
{
138
    SO_NODE_INIT_CLASS(SoFCSelection,SoGroup,"Group");
139
}
140

141
void SoFCSelection::finish()
142
{
143
    atexit_cleanup();
144
}
145

146
/*!
147
  Static method that can be used to turn off the current highlight.
148
*/
149
void
150
SoFCSelection::turnOffCurrentHighlight(SoGLRenderAction * action)
151
{
152
    SoFCSelection::turnoffcurrent(action);
153
}
154

155
void SoFCSelection::doAction(SoAction *action)
156
{
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;
164
                    touch();
165
                }
166
            }
167
            else {
168
                auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
169
                if (ctx) {
170
                    ctx->highlightColor = hlaction->getColor();
171
                    if (!ctx->isHighlighted()) {
172
                        ctx->highlightIndex = 0;
173
                        touch();
174
                    }
175
                }
176
            }
177
            return;
178
        }
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);
184
                if (ctx) {
185
                    ctx->selectionColor = selaction->getColor();
186
                    if(!ctx->isSelectAll()) {
187
                        ctx->selectAll();
188
                        this->touch();
189
                    }
190
                }
191
            }
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();
197
                    this->touch();
198
                }
199
            }
200
            return;
201
        }
202
    }
203

204
    if (action->getTypeId() == SoFCDocumentAction::getClassTypeId()) {
205
        auto docaction = static_cast<SoFCDocumentAction*>(action);
206
        this->documentName = docaction->documentName;
207
    }
208

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();
215
    }
216

217
    if(!useNewSelection.getValue()) {
218

219
        if (action->getTypeId() == SoFCEnableHighlightAction::getClassTypeId()) {
220
            auto preaction = static_cast<SoFCEnableHighlightAction*>(action);
221
            if (preaction->highlight) {
222
                this->highlightMode = SoFCSelection::AUTO;
223
            }
224
            else {
225
                this->highlightMode = SoFCSelection::OFF;
226
            }
227
        }
228

229
        if (action->getTypeId() == SoFCEnableSelectionAction::getClassTypeId()) {
230
            auto selaction = static_cast<SoFCEnableSelectionAction*>(action);
231
            if (selaction->selection) {
232
                this->selectionMode = SoFCSelection::SEL_ON;
233
            }
234
            else {
235
                this->selectionMode = SoFCSelection::SEL_OFF;
236
                if (selected.getValue() == SELECTED) {
237
                    this->selected = NOTSELECTED;
238
                }
239
            }
240
        }
241

242
        if (action->getTypeId() == SoFCSelectionColorAction::getClassTypeId()) {
243
            auto colaction = static_cast<SoFCSelectionColorAction*>(action);
244
            this->colorSelection = colaction->selectionColor;
245
        }
246

247
        if (action->getTypeId() == SoFCHighlightColorAction::getClassTypeId()) {
248
            auto colaction = static_cast<SoFCHighlightColorAction*>(action);
249
            this->colorHighlight = colaction->highlightColor;
250
        }
251

252
        if (selectionMode.getValue() == SEL_ON && action->getTypeId() == SoFCSelectionAction::getClassTypeId()) {
253
            auto selaction = static_cast<SoFCSelectionAction*>(action);
254

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){
263
                            selected = SELECTED;
264
                        }
265
                    }
266
                    else {
267
                        if(selected.getValue() == SELECTED){
268
                            selected = NOTSELECTED;
269
                        }
270
                    }
271
                    return;
272
                }
273
            }
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;
279
                    }
280

281
                }
282
            }
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()*/);
288
                if (sel) {
289
                    if (selected.getValue() == NOTSELECTED) {
290
                        selected = SELECTED;
291
                    }
292
                }
293
                else {
294
                    if (selected.getValue() == SELECTED) {
295
                        selected = NOTSELECTED;
296
                    }
297
                }
298
            }
299
        }
300
    }
301

302
    inherited::doAction( action );
303
}
304

305
int SoFCSelection::getPriority(const SoPickedPoint* p)
306
{
307
    const SoDetail* detail = p->getDetail();
308
    if(!detail)
309
        return 0;
310
    if(detail->isOfType(SoFaceDetail::getClassTypeId()))
311
        return 1;
312
    if(detail->isOfType(SoLineDetail::getClassTypeId()))
313
        return 2;
314
    if(detail->isOfType(SoPointDetail::getClassTypeId()))
315
        return 3;
316
    return 0;
317
}
318

319
const SoPickedPoint*
320
SoFCSelection::getPickedPoint(SoHandleEventAction* action) const
321
{
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)
328
        return nullptr;
329
    else if (points.getLength() == 1)
330
        return points[0];
331

332
    const SoPickedPoint* picked = points[0];
333

334
    int picked_prio = getPriority(picked);
335
    const SbVec3f& picked_pt = picked->getPoint();
336

337

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();
342

343
        if ((cur_prio > picked_prio) && picked_pt.equals(cur_pt, 0.01f)) {
344
            picked = cur;
345
            picked_prio = cur_prio;
346
        }
347
    }
348
    return picked;
349

350
}
351

352
// doc from parent
353
void
354
SoFCSelection::handleEvent(SoHandleEventAction * action)
355
{
356
    if(useNewSelection.getValue()) {
357
       inherited::handleEvent( action );
358
       return;
359
    }
360

361
    static char buf[513];
362
    auto mymode = static_cast<HighlightModes>(this->highlightMode.getValue());
363
    const SoEvent * event = action->getEvent();
364
#ifdef NO_FRONTBUFFER
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())) {
373
                if (!highlighted) {
374
                    if (Gui::Selection().setPreselect(documentName.getValue().getString()
375
                                           ,objectName.getValue().getString()
376
                                           ,subElementName.getValue().getString()
377
                                           ,pp->getPoint()[0]
378
                                           ,pp->getPoint()[1]
379
                                           ,pp->getPoint()[2])){
380
                        SoFCSelection::turnoffcurrent(action);
381
                        SoFCSelection::currenthighlight = static_cast<SoFullPath*>(action->getCurPath()->copy());
382
                        SoFCSelection::currenthighlight->ref();
383
                        highlighted = true;
384
                        this->touch(); // force scene redraw
385
                        this->redrawHighlighted(action, true);
386
                    }
387
                }
388

389
                const auto &pt = pp->getPoint();
390

391
                printPreselectionInfo(documentName.getValue().getString(),
392
                                      objectName.getValue().getString(),
393
                                      subElementName.getValue().getString(),
394
                                      pt[0], pt[1], pt[2], 1e-7);
395
            }
396
            else { // picked point
397
                if (highlighted) {
398
                    if (mymode == AUTO)
399
                        SoFCSelection::turnoffcurrent(action);
400
                    //FIXME: I think we should set 'highlighted' to false whenever no point is picked
401
                    //else
402
                    highlighted = false;
403
                    Gui::Selection().rmvPreselect();
404
                }
405
            }
406
        }
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)     )
412
            bShift = true;
413
        if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_SHIFT)   ||
414
            SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_SHIFT)   )
415
            bShift = false;
416
        if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_CONTROL)   ||
417
            SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_CONTROL)   )
418
            bCtrl = true;
419
        if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_CONTROL) ||
420
            SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_CONTROL) )
421
            bCtrl = false;
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();
431
                if (bCtrl) {
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());
438
                    } else {
439
                        Gui::Selection().addSelection(documentName.getValue().getString()
440
                                          ,objectName.getValue().getString()
441
                                          ,subElementName.getValue().getString()
442
                                          ,pt[0] ,pt[1] ,pt[2]);
443

444
                        if (mymode == OFF) {
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);
451

452
                            getMainWindow()->showMessage(QString::fromLatin1(buf));
453
                        }
454
                    }
455
                }
456
                else { // Ctrl
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]);
465
                    }
466
                    else {
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]);
471
                    }
472

473
                    if (mymode == OFF) {
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);
480

481
                        getMainWindow()->showMessage(QString::fromLatin1(buf));
482
                    }
483
                }
484

485
                action->setHandled();
486
            } // picked point
487
        } // mouse release
488
    }
489

490
    inherited::handleEvent(action);
491
#else
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 );
499
    //    return;
500
    //}
501

502

503
    //
504
    // If this is a mouseMotion event, then check for locate highlighting
505
    //
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())) {
517
                    if (node != this)
518
                    underTheMouse = false;
519
                    break; // found the lowest LocHL - look no further
520
                }
521
            }
522
        }
523
        // Am I currently highlighted?
524
        if (isHighlighted(action)) {
525
            if (! underTheMouse) {
526
                // re-draw the object with it's normal color
527
                //if(mymode != OFF)
528
                redrawHighlighted(action, false);
529
                Gui::Selection().rmvPreselect();
530
            }
531
            else {
532
                action->setHandled();
533
                //const SoPickedPoint * pp = action->getPickedPoint();
534
                Gui::Selection().setPreselectCoord(pp->getPoint()[0]
535
                                                 ,pp->getPoint()[1]
536
                                                 ,pp->getPoint()[2]);
537
            }
538
        }
539
        // Else I am not currently highlighted
540
        else {
541
            // If under the mouse, then highlight!
542
            if (underTheMouse) {
543
                // draw this object highlighted
544
                if (mymode != OFF)
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()
550
                                                 ,pp->getPoint()[0]
551
                                                 ,pp->getPoint()[1]
552
                                                 ,pp->getPoint()[2]);
553
            }
554
        }
555
    }
556
    // key press events
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)     )
561
            bShift = true;
562
        if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_SHIFT)   ||
563
            SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_SHIFT)   )
564
            bShift = false;
565
        if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_CONTROL)   ||
566
            SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_CONTROL)   )
567
            bCtrl = true;
568
        if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_CONTROL) ||
569
            SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_CONTROL) )
570
            bCtrl = false;
571
    }
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();
582
                if (bCtrl) {
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());
589
                    }
590
                    else {
591
                        Gui::Selection().addSelection(documentName.getValue().getString()
592
                                          ,objectName.getValue().getString()
593
                                          ,subElementName.getValue().getString()
594
                                          ,pt[0] ,pt[1] ,pt[2]);
595

596
                        if (mymode == OFF) {
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);
603

604
                            getMainWindow()->showMessage(QString::fromLatin1(buf));
605
                        }
606
                    }
607
                }
608
                else { // Ctrl
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]);
617
                    }
618
                    else {
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]);
623
                    }
624

625
                    if (mymode == OFF) {
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);
632

633
                        getMainWindow()->showMessage(QString::fromLatin1(buf));
634
                    }
635
                }
636

637
                action->setHandled();
638
            } // picked point
639
        } // mouse release
640
    }
641

642
    // Let the base class traverse the children.
643
    if (action->getGrabber() != this)
644
        inherited::handleEvent(action);
645
#endif
646
}
647

648
// doc from parent
649
void
650
SoFCSelection::GLRenderBelowPath(SoGLRenderAction * action)
651
{
652
    SoState * state = action->getState();
653
    SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext);
654
    if(selContext2->checkGlobal(ctx))
655
        ctx = selContext2;
656
    if(!useNewSelection.getValue() && selContext == ctx) {
657
        ctx->selectionColor = this->colorSelection.getValue();
658
        ctx->highlightColor = this->colorHighlight.getValue();
659
        if(this->selected.getValue()==SELECTED)
660
            ctx->selectAll();
661
        else
662
            ctx->selectionIndex.clear();
663
        ctx->highlightIndex = this->highlighted?0:-1;
664
    }
665

666
#ifdef NO_FRONTBUFFER
667
    // check if preselection is active
668
    if(this->setOverride(action,ctx)) {
669
        inherited::GLRenderBelowPath(action);
670
        state->pop();
671
    } else
672
        inherited::GLRenderBelowPath(action);
673
#else
674
    // Set up state for locate highlighting (if necessary)
675
    GLint oldDepthFunc;
676
    SbBool drawHighlighted = preRender(action, oldDepthFunc);
677

678
    // now invoke the parent method
679
    inherited::GLRenderBelowPath(action);
680

681
    // Restore old depth buffer model if needed
682
    if (drawHighlighted || highlighted)
683
        glDepthFunc((GLenum)oldDepthFunc);
684

685
    // Clean up state if needed
686
    if (drawHighlighted)
687
        action->getState()->pop();
688
#endif
689
}
690

691
void SoFCSelection::GLRender(SoGLRenderAction * action)
692
{
693
    SoState * state = action->getState();
694
    SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext);
695
    if(selContext2->checkGlobal(ctx))
696
        ctx = selContext2;
697
    if(!useNewSelection.getValue() && selContext == ctx) {
698
        ctx->selectionColor = this->colorSelection.getValue();
699
        ctx->highlightColor = this->colorHighlight.getValue();
700
        if(this->selected.getValue()==SELECTED)
701
            ctx->selectAll();
702
        else
703
            ctx->selectionIndex.clear();
704
        ctx->highlightIndex = this->highlighted?0:-1;
705
    }
706

707
#ifdef NO_FRONTBUFFER
708
    // check if preselection is active
709
    if(this->setOverride(action,ctx)) {
710
        inherited::GLRender(action);
711
        state->pop();
712
    } else
713
        inherited::GLRender(action);
714
#else
715
    // Set up state for locate highlighting (if necessary)
716
    GLint oldDepthFunc;
717
    SbBool drawHighlighted = preRender(action, oldDepthFunc);
718

719
    // now invoke the parent method
720
    inherited::GLRender(action);
721

722
    // Restore old depth buffer model if needed
723
    if (drawHighlighted || highlighted)
724
        glDepthFunc((GLenum)oldDepthFunc);
725

726
    // Clean up state if needed
727
    if (drawHighlighted)
728
        action->getState()->pop();
729
#endif
730
}
731

732
// doc from parent
733
void
734
SoFCSelection::GLRenderInPath(SoGLRenderAction * action)
735
{
736
    SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext);
737
    if(selContext2->checkGlobal(ctx))
738
        ctx = selContext2;
739
    if(!useNewSelection.getValue() && selContext == ctx) {
740
        ctx->selectionColor = this->colorSelection.getValue();
741
        ctx->highlightColor = this->colorHighlight.getValue();
742
        if(this->selected.getValue()==SELECTED)
743
            ctx->selectAll();
744
        else
745
            ctx->selectionIndex.clear();
746
        ctx->highlightIndex = this->highlighted?0:-1;
747
    }
748
#ifdef NO_FRONTBUFFER
749
    // check if preselection is active
750
    SoState * state = action->getState();
751
    if(this->setOverride(action,ctx)) {
752
        inherited::GLRenderInPath(action);
753
        state->pop();
754
    } else
755
        inherited::GLRenderInPath(action);
756
#else
757
    // Set up state for locate highlighting (if necessary)
758
    GLint oldDepthFunc;
759
    SbBool drawHighlighted = preRender(action, oldDepthFunc);
760

761
    // now invoke the parent method
762
    inherited::GLRenderInPath(action);
763

764
    // Restore old depth buffer model if needed
765
    if (drawHighlighted || highlighted)
766
        glDepthFunc((GLenum)oldDepthFunc);
767

768
    // Clean up state if needed
769
    if (drawHighlighted)
770
        action->getState()->pop();
771
#endif
772
}
773

774
SbBool
775
SoFCSelection::preRender(SoGLRenderAction *action, GLint &oldDepthFunc)
776
//
777
////////////////////////////////////////////////////////////////////////
778
{
779
    // If not performing locate highlighting, just return.
780
    if (highlightMode.getValue() == OFF)
781
        return false;
782

783
    SoState *state = action->getState();
784

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);
789

790
    SbBool drawHighlighted = (highlightMode.getValue() == ON || isHighlighted(action) || selected.getValue() == SELECTED);
791

792
    if (drawHighlighted) {
793
        // prevent diffuse & emissive color from leaking out...
794
        state->push();
795
        SbColor col;
796
        if (selected.getValue() == SELECTED)
797
            col = colorSelection.getValue();
798
        else
799
            col = colorHighlight.getValue();
800

801
        // Emissive Color
802
        SoLazyElement::setEmissive(state, &col);
803
        SoOverrideElement::setEmissiveColorOverride(state, this, true);
804

805
        // Diffuse Color
806
        if (style.getValue() == EMISSIVE_DIFFUSE) {
807
            SoLazyElement::setDiffuse(state, this, 1, &col, &colorpacker);
808
            SoOverrideElement::setDiffuseColorOverride(state, this, true);
809
        }
810
    }
811

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);
821
    }
822

823
    return drawHighlighted;
824
}
825

826
/*!
827
  Empty method in Coin. Can be used by subclasses to be told
828
  when status change.
829
*/
830
void
831
SoFCSelection::redrawHighlighted(SoAction *  action , SbBool  doHighlight )
832
{
833
    //Base::Console().Log("SoFCSelection::redrawHighlighted() (%p) doHigh=%d \n",this,doHighlight?1:0);
834

835
#ifdef NO_FRONTBUFFER
836
    Q_UNUSED(action);
837
    Q_UNUSED(doHighlight);
838
#else
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)) {
843

844
        SoNode *tail = currenthighlight->getTail();
845
        if (tail->isOfType( SoFCSelection::getClassTypeId())) {
846
            static_cast<SoFCSelection *>(tail)->redrawHighlighted(action, false);
847
        }
848
        else {
849
            // Just get rid of the path. It's no longer valid for redraw.
850
            currenthighlight->unref();
851
            currenthighlight = nullptr;
852
        }
853
    }
854

855
    SoPath *pathToRender;
856
    // save the path to ourself for later de-highlight
857
    if (doHighlight) {
858
        if (currenthighlight)
859
            currenthighlight->unref();
860
        currenthighlight = static_cast<SoFullPath *>(action->getCurPath()->copy());
861
        currenthighlight->ref();
862

863
        // We will be rendering this new path to highlight it
864
        pathToRender = currenthighlight;
865
        pathToRender->ref();
866
    }
867
    // delete our path if we are no longer highlighted
868
    else {
869
        if (currenthighlight) {
870
            // We will be rendering this old path to unhighlight it
871
            pathToRender = currenthighlight;
872
            pathToRender->ref();
873

874
            currenthighlight->unref();
875
            currenthighlight = nullptr;
876
        }
877
    }
878

879
    // If highlighting is forced on for this node, we don't need this special render.
880
    if (highlightMode.getValue() != AUTO) {
881
        pathToRender->unref();
882
        return;
883
    }
884

885
    SoState *state = action->getState();
886

887
    QtGLWidget* window;
888
    SoGLRenderAction *glAction;
889
    SoGLWidgetElement::get(state, window);
890
    SoGLRenderActionElement::get(state, glAction);
891

892
    // If we don't have a current window, then simply return...
893
    if (!window /*|| context == NULL || display == NULL*/ || !glAction)
894
        return;
895

896
    window->makeCurrent();
897
#ifndef WIN32
898
    // set the current window
899
    //glXMakeCurrent(display, window, context);
900
#endif
901
    // render into the front buffer (save the current buffering type)
902
    GLint whichBuffer;
903
    glGetIntegerv(GL_DRAW_BUFFER, &whichBuffer);
904
    if (whichBuffer != GL_FRONT)
905
        glDrawBuffer(GL_FRONT);
906

907
    highlighted = true;
908
    glAction->apply(pathToRender);
909
    highlighted = false;
910

911
    // restore the buffering type
912
    if (whichBuffer != GL_FRONT)
913
        glDrawBuffer((GLenum)whichBuffer);
914
    glFlush();
915

916
    pathToRender->unref();
917
#endif
918
}
919

920
SbBool
921
SoFCSelection::readInstance  (  SoInput *  in, unsigned short  flags )
922
{
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);
925
    return ret;
926
}
927
//
928
// update override state before rendering
929
//
930
bool
931
SoFCSelection::setOverride(SoGLRenderAction * action, SelContextPtr ctx)
932
{
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()))
936
        return false;
937

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);
944

945
    auto mystyle = static_cast<Styles>(this->style.getValue());
946

947
    if (mystyle == SoFCSelection::BOX) {
948
        if (ctx) {
949
            SoFCSelectionRoot::renderBBox(
950
                    action, this, preselected ? ctx->highlightColor : ctx->selectionColor);
951
        }
952
        this->uniqueId = oldId;
953
        return false;
954
    }
955

956
    //Base::Console().Log("SoFCSelection::setOverride() (%p)\n",this);
957
    SoState * state = action->getState();
958
    state->push();
959

960
    SoMaterialBindingElement::set(state,SoMaterialBindingElement::OVERALL);
961
    SoOverrideElement::setMaterialBindingOverride(state,this,true);
962

963
    if (!preselected && ctx)
964
        SoLazyElement::setEmissive(state, &ctx->selectionColor);
965
    else if (ctx)
966
        SoLazyElement::setEmissive(state, &ctx->highlightColor);
967
    SoOverrideElement::setEmissiveColorOverride(state, this, true);
968

969
    if(SoLazyElement::getLightModel(state)==SoLazyElement::BASE_COLOR
970
            || mystyle == SoFCSelection::EMISSIVE_DIFFUSE)
971
    {
972
        if (!preselected && ctx)
973
            SoLazyElement::setDiffuse(state, this, 1, &ctx->selectionColor,&colorpacker);
974
        else if (ctx)
975
            SoLazyElement::setDiffuse(state, this, 1, &ctx->highlightColor,&colorpacker);
976
        SoOverrideElement::setDiffuseColorOverride(state, this, true);
977
    }
978

979
    this->uniqueId = oldId;
980
    return true;
981
}
982

983
// private convenience method
984
void
985
SoFCSelection::turnoffcurrent(SoAction * action)
986
{
987
#ifdef NO_FRONTBUFFER
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
994
            if (action)
995
                static_cast<SoFCSelection*>(tail)->redrawHighlighted(action, false);
996
        }
997
    }
998
    if (SoFCSelection::currenthighlight) {
999
        SoFCSelection::currenthighlight->unref();
1000
        SoFCSelection::currenthighlight = nullptr;
1001
    }
1002
#else
1003
    if (!currenthighlight)
1004
        return;
1005

1006
    SoNode *tail = currenthighlight->getTail();
1007
    if (tail->isOfType(SoFCSelection::getClassTypeId())) {
1008

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);
1014
    }
1015
    else {
1016
        // Just get rid of the path. It's no longer valid for redraw.
1017
        currenthighlight->unref();
1018
        currenthighlight = nullptr;
1019
    }
1020
#endif
1021
}
1022

1023
SbBool
1024
SoFCSelection::isHighlighted(SoAction *action)
1025
//
1026
////////////////////////////////////////////////////////////////////////
1027
{
1028
    auto actionPath = static_cast<const SoFullPath *>(action->getCurPath());
1029
    return (currenthighlight &&
1030
        currenthighlight->getTail() == actionPath->getTail() && // nested SoHL!
1031
        *currenthighlight == *actionPath);
1032
}
1033

1034
void SoFCSelection::applySettings ()
1035
{
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
1038
    float transparency;
1039
    ParameterGrp::handle hGrp = Gui::WindowParameter::getDefaultParameter()->GetGroup("View");
1040
    bool enablePre = hGrp->GetBool("EnablePreselection", true);
1041
    bool enableSel = hGrp->GetBool("EnableSelection", true);
1042
    if (!enablePre) {
1043
        this->highlightMode = Gui::SoFCSelection::OFF;
1044
    }
1045
    else {
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);
1052
    }
1053
    if (!enableSel) {
1054
        this->selectionMode = Gui::SoFCSelection::SEL_OFF;
1055
    }
1056
    else {
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);
1063
    }
1064
}
1065

1066

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.