FreeCAD

Форк
0
/
View3DInventor.cpp 
837 строк · 27.4 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2004 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 <string>
27
# include <QAction>
28
# include <QApplication>
29
# include <QKeyEvent>
30
# include <QEvent>
31
# include <QDropEvent>
32
# include <QDragEnterEvent>
33
# include <QLayout>
34
# include <QMdiSubWindow>
35
# include <QMessageBox>
36
# include <QMimeData>
37
# include <QPainter>
38
# include <QPrinter>
39
# include <QPrintDialog>
40
# include <QPrintPreviewDialog>
41
# include <QStackedWidget>
42
# include <QTimer>
43
# include <QUrl>
44
# include <QWindow>
45
# include <Inventor/actions/SoGetPrimitiveCountAction.h>
46
# include <Inventor/fields/SoSFString.h>
47
# include <Inventor/nodes/SoOrthographicCamera.h>
48
# include <Inventor/nodes/SoPerspectiveCamera.h>
49
# include <Inventor/nodes/SoSeparator.h>
50
#endif
51

52
#include <App/Document.h>
53
#include <Base/Builder3D.h>
54
#include <Base/Console.h>
55
#include <Base/Interpreter.h>
56

57
#include "View3DInventor.h"
58
#include "View3DSettings.h"
59
#include "Application.h"
60
#include "BitmapFactory.h"
61
#include "Camera.h"
62
#include "Document.h"
63
#include "FileDialog.h"
64
#include "MainWindow.h"
65
#include "NaviCube.h"
66
#include "NavigationStyle.h"
67
#include "SoFCDB.h"
68
#include "SoFCSelectionAction.h"
69
#include "SoFCVectorizeSVGAction.h"
70
#include "View3DInventorViewer.h"
71
#include "View3DPy.h"
72
#include "ViewProvider.h"
73
#include "WaitCursor.h"
74

75

76
using namespace Gui;
77

78
void GLOverlayWidget::paintEvent(QPaintEvent*)
79
{
80
    QPainter paint(this);
81
    paint.drawImage(0,0,image);
82
    paint.end();
83
}
84

85
/* TRANSLATOR Gui::View3DInventor */
86

87
TYPESYSTEM_SOURCE_ABSTRACT(Gui::View3DInventor,Gui::MDIView)
88

89
View3DInventor::View3DInventor(Gui::Document* pcDocument, QWidget* parent,
90
                               const QtGLWidget* sharewidget, Qt::WindowFlags wflags)
91
    : MDIView(pcDocument, parent, wflags), _viewerPy(nullptr)
92
{
93
    stack = new QStackedWidget(this);
94
    // important for highlighting
95
    setMouseTracking(true);
96
    // accept drops on the window, get handled in dropEvent, dragEnterEvent
97
    setAcceptDrops(true);
98

99
    //anti-aliasing settings
100
    bool smoothing = false;
101
    bool glformat = false;
102
    int samples = View3DInventorViewer::getNumSamples();
103
    QtGLFormat f;
104

105
    if (samples > 1) {
106
        glformat = true;
107
        f.setSamples(samples);
108
    }
109
    else if (samples > 0) {
110
        smoothing = true;
111
    }
112

113
    if (glformat)
114
        _viewer = new View3DInventorViewer(f, this, sharewidget);
115
    else
116
        _viewer = new View3DInventorViewer(this, sharewidget);
117

118
    if (smoothing)
119
        _viewer->getSoRenderManager()->getGLRenderAction()->setSmoothing(true);
120

121
    // create the inventor widget and set the defaults
122
    _viewer->setDocument(this->_pcDocument);
123
    stack->addWidget(_viewer->getWidget());
124
    // https://forum.freecad.org/viewtopic.php?f=3&t=6055&sid=150ed90cbefba50f1e2ad4b4e6684eba
125
    // describes a minor error but trying to fix it leads to a major issue
126
    // https://forum.freecad.org/viewtopic.php?f=3&t=6085&sid=3f4bcab8007b96aaf31928b564190fd7
127
    // so the change is commented out
128
    // By default, the wheel events are processed by the 3d view AND the mdi area.
129
    //_viewer->getGLWidget()->setAttribute(Qt::WA_NoMousePropagation);
130
    setCentralWidget(stack);
131

132
    // apply the user settings
133
    applySettings();
134

135
    stopSpinTimer = new QTimer(this);
136
    connect(stopSpinTimer, &QTimer::timeout, this, &View3DInventor::stopAnimating);
137

138
    setWindowIcon(Gui::BitmapFactory().pixmap("Document"));
139
}
140

141
View3DInventor::~View3DInventor()
142
{
143
    if(_pcDocument) {
144
        SoCamera * Cam = _viewer->getSoRenderManager()->getCamera();
145
        if (Cam)
146
            _pcDocument->saveCameraSettings(SoFCDB::writeNodesToString(Cam).c_str());
147
    }
148

149
    viewSettings.reset();
150

151
    //If we destroy this viewer by calling 'delete' directly the focus proxy widget which is defined
152
    //by a widget in SoQtViewer isn't reset. This widget becomes a dangling pointer and makes
153
    //the application crash. (Probably it's better to destroy this viewer by calling close().)
154
    //See also Gui::Document::~Document().
155
    QWidget* foc = qApp->focusWidget();
156
    if (foc) {
157
        QWidget* par = foc->parentWidget();
158
        while (par) {
159
            if (par == this) {
160
                foc->setFocusProxy(nullptr);
161
                foc->clearFocus();
162
                break;
163
            }
164
            par = par->parentWidget();
165
        }
166
    }
167

168
    if (_viewerPy) {
169
        Base::PyGILStateLocker lock;
170
        Py_DECREF(_viewerPy);
171
    }
172

173
    // here is from time to time trouble!!!
174
    delete _viewer;
175
}
176

177
void View3DInventor::deleteSelf()
178
{
179
    _viewer->setSceneGraph(nullptr);
180
    _viewer->setDocument(nullptr);
181
    MDIView::deleteSelf();
182
}
183

184
PyObject *View3DInventor::getPyObject()
185
{
186
    if (!_viewerPy)
187
        _viewerPy = new View3DInventorPy(this);
188

189
    Py_INCREF(_viewerPy);
190
    return _viewerPy;
191
}
192

193
void View3DInventor::applySettings()
194
{
195
    viewSettings = std::make_unique<View3DSettings>(App::GetApplication().GetParameterGroupByPath
196
                                   ("User parameter:BaseApp/Preferences/View"), _viewer);
197
    naviSettings = std::make_unique<NaviCubeSettings>(App::GetApplication().GetParameterGroupByPath
198
                                   ("User parameter:BaseApp/Preferences/NaviCube"), _viewer);
199
    viewSettings->applySettings();
200
    naviSettings->applySettings();
201
}
202

203
void View3DInventor::onRename(Gui::Document *pDoc)
204
{
205
    SoSFString name;
206
    name.setValue(pDoc->getDocument()->getName());
207
    SoFCDocumentAction cAct(name);
208
    cAct.apply(_viewer->getSceneGraph());
209
}
210

211
void View3DInventor::onUpdate()
212
{
213
#ifdef FC_LOGUPDATECHAIN
214
    Base::Console().Log("Acti: Gui::View3DInventor::onUpdate()");
215
#endif
216
    update();
217
    _viewer->redraw();
218
}
219

220
void View3DInventor::viewAll()
221
{
222
    _viewer->viewAll();
223
}
224

225
const char *View3DInventor::getName() const
226
{
227
    return "View3DInventor";
228
}
229

230
void View3DInventor::print()
231
{
232
    QPrinter printer(QPrinter::ScreenResolution);
233
    printer.setFullPage(true);
234
    restorePrinterSettings(&printer);
235

236
    QPrintDialog dlg(&printer, this);
237
    if (dlg.exec() == QDialog::Accepted) {
238
        Gui::WaitCursor wc;
239
        print(&printer);
240
        savePrinterSettings(&printer);
241
    }
242
}
243

244
void View3DInventor::printPdf()
245
{
246
    QString filename = FileDialog::getSaveFileName(this, tr("Export PDF"), QString(),
247
        QString::fromLatin1("%1 (*.pdf)").arg(tr("PDF file")));
248
    if (!filename.isEmpty()) {
249
        Gui::WaitCursor wc;
250
        QPrinter printer(QPrinter::ScreenResolution);
251
        // setPdfVersion sets the printied PDF Version to comply with PDF/A-1b, more details under: https://www.kdab.com/creating-pdfa-documents-qt/
252
        printer.setPdfVersion(QPagedPaintDevice::PdfVersion_A1b);
253
        printer.setOutputFormat(QPrinter::PdfFormat);
254
        printer.setPageOrientation(QPageLayout::Landscape);
255
        printer.setOutputFileName(filename);
256
        print(&printer);
257
    }
258
}
259

260
void View3DInventor::printPreview()
261
{
262
    QPrinter printer(QPrinter::ScreenResolution);
263
    printer.setFullPage(true);
264
    restorePrinterSettings(&printer);
265

266
    QPrintPreviewDialog dlg(&printer, this);
267
    connect(&dlg, &QPrintPreviewDialog::paintRequested,
268
            this, qOverload<QPrinter*>(&View3DInventor::print));
269
    dlg.exec();
270
    savePrinterSettings(&printer);
271
}
272

273
void View3DInventor::print(QPrinter* printer)
274
{
275
    QPainter p(printer);
276
    p.setRenderHints(QPainter::Antialiasing);
277
    if (!p.isActive() && !printer->outputFileName().isEmpty()) {
278
        qApp->setOverrideCursor(Qt::ArrowCursor);
279
        QMessageBox::critical(this, tr("Opening file failed"),
280
            tr("Can't open file '%1' for writing.").arg(printer->outputFileName()));
281
        qApp->restoreOverrideCursor();
282
        return;
283
    }
284

285
    QRect rect = printer->pageLayout().paintRectPixels(printer->resolution());
286
    QImage img;
287
    _viewer->imageFromFramebuffer(rect.width(), rect.height(), 8, QColor(255,255,255), img);
288
    p.drawImage(0,0,img);
289
    p.end();
290
}
291

292
bool View3DInventor::containsViewProvider(const ViewProvider* vp) const
293
{
294
    return _viewer->containsViewProvider(vp);
295
}
296

297
// **********************************************************************************
298

299
bool View3DInventor::onMsg(const char* pMsg, const char** ppReturn)
300
{
301
    if (strcmp("ViewFit",pMsg) == 0) {
302
        _viewer->viewAll();
303
        return true;
304
    }
305
    else if (strcmp("ViewVR",pMsg) == 0) {
306
        // call the VR portion of the viewer
307
        _viewer->viewVR();
308
        return true;
309
    }
310
    else if(strcmp("ViewSelection",pMsg) == 0) {
311
        _viewer->viewSelection();
312
        return true;
313
    }
314
    else if(strcmp("SetStereoRedGreen",pMsg) == 0 ) {
315
        _viewer->setStereoMode(Quarter::SoQTQuarterAdaptor::ANAGLYPH);
316
        return true;
317
    }
318
    else if(strcmp("SetStereoQuadBuff",pMsg) == 0 ) {
319
        _viewer->setStereoMode(Quarter::SoQTQuarterAdaptor::QUAD_BUFFER );
320
        return true;
321
    }
322
    else if(strcmp("SetStereoInterleavedRows",pMsg) == 0 ) {
323
        _viewer->setStereoMode(Quarter::SoQTQuarterAdaptor::INTERLEAVED_ROWS );
324
        return true;
325
    }
326
    else if(strcmp("SetStereoInterleavedColumns",pMsg) == 0 ) {
327
        _viewer->setStereoMode(Quarter::SoQTQuarterAdaptor::INTERLEAVED_COLUMNS  );
328
        return true;
329
    }
330
    else if(strcmp("SetStereoOff",pMsg) == 0 ) {
331
        _viewer->setStereoMode(Quarter::SoQTQuarterAdaptor::MONO );
332
        return true;
333
    }
334
    else if(strcmp("GetCamera",pMsg) == 0 ) {
335
        SoCamera * Cam = _viewer->getSoRenderManager()->getCamera();
336
        if (!Cam)
337
            return false;
338
        *ppReturn = SoFCDB::writeNodesToString(Cam).c_str();
339
        return true;
340
    }
341
    else if(strncmp("SetCamera",pMsg,9) == 0 ) {
342
        return setCamera(pMsg+10);
343
    }
344
    else if(strncmp("Dump",pMsg,4) == 0 ) {
345
        dump(pMsg+5);
346
        return true;
347
    }
348
    else if(strcmp("ViewBottom",pMsg) == 0 ) {
349
        _viewer->setCameraOrientation(Camera::rotation(Camera::Bottom));
350
        _viewer->viewAll();
351
        return true;
352
    }
353
    else if(strcmp("ViewFront",pMsg) == 0 ) {
354
        _viewer->setCameraOrientation(Camera::rotation(Camera::Front));
355
        _viewer->viewAll();
356
        return true;
357
    }
358
    else if(strcmp("ViewLeft",pMsg) == 0 ) {
359
        _viewer->setCameraOrientation(Camera::rotation(Camera::Left));
360
        _viewer->viewAll();
361
        return true;
362
    }
363
    else if(strcmp("ViewRear",pMsg) == 0 ) {
364
        _viewer->setCameraOrientation(Camera::rotation(Camera::Rear));
365
        _viewer->viewAll();
366
        return true;
367
    }
368
    else if(strcmp("ViewRight",pMsg) == 0 ) {
369
        _viewer->setCameraOrientation(Camera::rotation(Camera::Right));
370
        _viewer->viewAll();
371
        return true;
372
    }
373
    else if(strcmp("ViewTop",pMsg) == 0 ) {
374
        _viewer->setCameraOrientation(Camera::rotation(Camera::Top));
375
        _viewer->viewAll();
376
        return true;
377
    }
378
    else if(strcmp("ViewAxo",pMsg) == 0 ) {
379
        _viewer->setCameraOrientation(Camera::rotation(Camera::Isometric));
380
        _viewer->viewAll();
381
        return true;
382
    }
383
    else if(strcmp("OrthographicCamera",pMsg) == 0 ) {
384
        _viewer->setCameraType(SoOrthographicCamera::getClassTypeId());
385
        return true;
386
    }
387
    else if(strcmp("PerspectiveCamera",pMsg) == 0 ) {
388
        _viewer->setCameraType(SoPerspectiveCamera::getClassTypeId());
389
        return true;
390
    }
391
    else  if(strcmp("Undo",pMsg) == 0 ) {
392
        getGuiDocument()->undo(1);
393
        return true;
394
    }
395
    else  if(strcmp("Redo",pMsg) == 0 ) {
396
        getGuiDocument()->redo(1);
397
        return true;
398
    }
399
    else if (strcmp("Save",pMsg) == 0) {
400
        getGuiDocument()->save();
401
        return true;
402
    }
403
    else if (strcmp("SaveAs",pMsg) == 0) {
404
        getGuiDocument()->saveAs();
405
        return true;
406
    }
407
    else if (strcmp("SaveCopy",pMsg) == 0) {
408
        getGuiDocument()->saveCopy();
409
        return true;
410
    }
411
    else if (strcmp("AlignToSelection", pMsg) == 0) {
412
        _viewer->alignToSelection();
413
        return true;
414
    }
415
    else if (strcmp("ZoomIn", pMsg) == 0) {
416
        View3DInventorViewer* viewer = getViewer();
417
        viewer->navigationStyle()->zoomIn();
418
        return true;
419
    }
420
    else if (strcmp("ZoomOut", pMsg) == 0) {
421
        View3DInventorViewer* viewer = getViewer();
422
        viewer->navigationStyle()->zoomOut();
423
        return true;
424
    }
425

426
    return false;
427
}
428

429
bool View3DInventor::onHasMsg(const char* pMsg) const
430
{
431
    if (strcmp("CanPan", pMsg) == 0) {
432
        return true;
433
    }
434
    else if (strcmp("Save",pMsg) == 0) {
435
        return true;
436
    }
437
    else if (strcmp("SaveAs",pMsg) == 0) {
438
        return true;
439
    }
440
    else if (strcmp("SaveCopy",pMsg) == 0) {
441
        return true;
442
    }
443
    else if (strcmp("Undo",pMsg) == 0) {
444
        App::Document* doc = getAppDocument();
445
        return doc && doc->getAvailableUndos() > 0;
446
    }
447
    else if (strcmp("Redo",pMsg) == 0) {
448
        App::Document* doc = getAppDocument();
449
        return doc && doc->getAvailableRedos() > 0;
450
    }
451
    else if (strcmp("Print",pMsg) == 0) {
452
        return true;
453
    }
454
    else if (strcmp("PrintPreview",pMsg) == 0) {
455
        return true;
456
    }
457
    else if (strcmp("PrintPdf",pMsg) == 0) {
458
        return true;
459
    }
460
    else if(strcmp("SetStereoRedGreen",pMsg) == 0) {
461
        return true;
462
    }
463
    else if(strcmp("SetStereoQuadBuff",pMsg) == 0) {
464
        return true;
465
    }
466
    else if(strcmp("SetStereoInterleavedRows",pMsg) == 0) {
467
        return true;
468
    }
469
    else if(strcmp("SetStereoInterleavedColumns",pMsg) == 0) {
470
        return true;
471
    }
472
    else if(strcmp("SetStereoOff",pMsg) == 0) {
473
        return true;
474
    }
475
    else if(strcmp("ViewFit",pMsg) == 0) {
476
        return true;
477
    }
478
    else if(strcmp("ViewVR",pMsg) == 0) {
479
#ifdef BUILD_VR
480
        return true;
481
#else
482
        return false;
483
#endif
484
    }
485
    else if(strcmp("ViewSelection",pMsg) == 0) {
486
        return true;
487
    }
488
    else if(strcmp("ViewBottom",pMsg) == 0) {
489
        return true;
490
    }
491
    else if(strcmp("ViewFront",pMsg) == 0) {
492
        return true;
493
    }
494
    else if(strcmp("ViewLeft",pMsg) == 0) {
495
        return true;
496
    }
497
    else if(strcmp("ViewRear",pMsg) == 0) {
498
        return true;
499
    }
500
    else if(strcmp("ViewRight",pMsg) == 0) {
501
        return true;
502
    }
503
    else if(strcmp("ViewTop",pMsg) == 0) {
504
        return true;
505
    }
506
    else if(strcmp("ViewAxo",pMsg) == 0) {
507
        return true;
508
    }
509
    else if(strcmp("GetCamera",pMsg) == 0) {
510
        return true;
511
    }
512
    else if(strncmp("SetCamera",pMsg,9) == 0) {
513
        return true;
514
    }
515
    else if(strncmp("Dump",pMsg,4) == 0) {
516
        return true;
517
    }
518
    else if (strcmp("AlignToSelection", pMsg) == 0) {
519
        return true;
520
    }
521
    if (strcmp("ZoomIn", pMsg) == 0) {
522
        return true;
523
    }
524
    if (strcmp("ZoomOut", pMsg) == 0) {
525
        return true;
526
    }
527
    if (strcmp("AllowsOverlayOnHover", pMsg) == 0) {
528
        return true;
529
    }
530

531
    return false;
532
}
533

534
bool View3DInventor::setCamera(const char* pCamera)
535
{
536
    SoCamera * CamViewer = _viewer->getSoRenderManager()->getCamera();
537
    if (!CamViewer) {
538
        throw Base::RuntimeError("No camera set so far...");
539
    }
540

541
    SoInput in;
542
    in.setBuffer((void*)pCamera,std::strlen(pCamera));
543

544
    SoNode * Cam;
545
    SoDB::read(&in,Cam);
546

547
    if (!Cam || !Cam->isOfType(SoCamera::getClassTypeId())) {
548
        throw Base::RuntimeError("Camera settings failed to read");
549
    }
550

551
    // this is to make sure to reliably delete the node
552
    CoinPtr<SoNode> camPtr(Cam, true);
553

554
    // toggle between perspective and orthographic camera
555
    if (Cam->getTypeId() != CamViewer->getTypeId()) {
556
        _viewer->setCameraType(Cam->getTypeId());
557
        CamViewer = _viewer->getSoRenderManager()->getCamera();
558
    }
559

560
    SoPerspectiveCamera  * CamViewerP = nullptr;
561
    SoOrthographicCamera * CamViewerO = nullptr;
562

563
    if (CamViewer->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
564
        CamViewerP = static_cast<SoPerspectiveCamera *>(CamViewer);  // safe downward cast, knows the type
565
    }
566
    else if (CamViewer->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
567
        CamViewerO = static_cast<SoOrthographicCamera *>(CamViewer);  // safe downward cast, knows the type
568
    }
569

570
    if (Cam->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
571
        if (CamViewerP){
572
            CamViewerP->position      = static_cast<SoPerspectiveCamera *>(Cam)->position;
573
            CamViewerP->orientation   = static_cast<SoPerspectiveCamera *>(Cam)->orientation;
574
            CamViewerP->nearDistance  = static_cast<SoPerspectiveCamera *>(Cam)->nearDistance;
575
            CamViewerP->farDistance   = static_cast<SoPerspectiveCamera *>(Cam)->farDistance;
576
            CamViewerP->focalDistance = static_cast<SoPerspectiveCamera *>(Cam)->focalDistance;
577
        }
578
        else {
579
            throw Base::TypeError("Camera type mismatch");
580
        }
581
    }
582
    else if (Cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
583
        if (CamViewerO){
584
            CamViewerO->viewportMapping  = static_cast<SoOrthographicCamera *>(Cam)->viewportMapping;
585
            CamViewerO->position         = static_cast<SoOrthographicCamera *>(Cam)->position;
586
            CamViewerO->orientation      = static_cast<SoOrthographicCamera *>(Cam)->orientation;
587
            CamViewerO->nearDistance     = static_cast<SoOrthographicCamera *>(Cam)->nearDistance;
588
            CamViewerO->farDistance      = static_cast<SoOrthographicCamera *>(Cam)->farDistance;
589
            CamViewerO->focalDistance    = static_cast<SoOrthographicCamera *>(Cam)->focalDistance;
590
            CamViewerO->aspectRatio      = static_cast<SoOrthographicCamera *>(Cam)->aspectRatio ;
591
            CamViewerO->height           = static_cast<SoOrthographicCamera *>(Cam)->height;
592
        }
593
        else {
594
            throw Base::TypeError("Camera type mismatch");
595
        }
596
    }
597

598
    return true;
599
}
600

601
void View3DInventor::toggleClippingPlane()
602
{
603
    _viewer->toggleClippingPlane();
604
}
605

606
bool View3DInventor::hasClippingPlane() const
607
{
608
    return _viewer->hasClippingPlane();
609
}
610

611
void View3DInventor::setOverlayWidget(QWidget* widget)
612
{
613
    removeOverlayWidget();
614
    stack->addWidget(widget);
615
    stack->setCurrentIndex(1);
616
}
617

618
void View3DInventor::removeOverlayWidget()
619
{
620
    stack->setCurrentIndex(0);
621
    QWidget* overlay = stack->widget(1);
622
    if (overlay) stack->removeWidget(overlay);
623
}
624

625
void View3DInventor::setOverrideCursor(const QCursor& aCursor)
626
{
627
    _viewer->getWidget()->setCursor(aCursor);
628
}
629

630
void View3DInventor::restoreOverrideCursor()
631
{
632
    _viewer->getWidget()->setCursor(QCursor(Qt::ArrowCursor));
633
}
634

635
// defined in SoFCDB.cpp
636
extern SoNode* replaceSwitchesInSceneGraph(SoNode*);
637

638
void View3DInventor::dump(const char* filename, bool onlyVisible)
639
{
640
    SoGetPrimitiveCountAction action;
641
    action.setCanApproximate(true);
642
    action.apply(_viewer->getSceneGraph());
643

644
    SoNode* node = _viewer->getSceneGraph();
645
    if (onlyVisible) {
646
        node = replaceSwitchesInSceneGraph(node);
647
        node->ref();
648
    }
649

650
    if ( action.getTriangleCount() > 100000 || action.getPointCount() > 30000 || action.getLineCount() > 10000 )
651
        _viewer->dumpToFile(node, filename, true);
652
    else
653
        _viewer->dumpToFile(node, filename, false);
654

655
    if (onlyVisible) {
656
        node->unref();
657
    }
658
}
659

660
void View3DInventor::windowStateChanged(QWidget* view)
661
{
662
    bool canStartTimer = false;
663
    if (this != view) {
664
        // If both views are child widgets of the workspace and view is maximized this view
665
        // must be hidden, hence we can start the timer.
666
        // Note: If view is top-level or fullscreen it doesn't necessarily hide the other view
667
        // e.g. if it is on a second monitor.
668
        canStartTimer = (!this->isWindow() && !view->isWindow() && view->isMaximized());
669
    } else if (isMinimized()) {
670
        // I am the active view but minimized
671
        canStartTimer = true;
672
    }
673

674
    if (canStartTimer) {
675
        int msecs = viewSettings->stopAnimatingIfDeactivated();
676
        if (!stopSpinTimer->isActive() && msecs >= 0) { // if < 0 do not stop rotation
677
            stopSpinTimer->setSingleShot(true);
678
            stopSpinTimer->start(msecs);
679
        }
680
    } else if (stopSpinTimer->isActive()) {
681
        // If this view may be visible again we can stop the timer
682
        stopSpinTimer->stop();
683
    }
684
}
685

686
void View3DInventor::stopAnimating()
687
{
688
    _viewer->stopAnimating();
689
}
690

691
/**
692
 * Drops the event \a e and writes the right Python command.
693
 */
694
void View3DInventor::dropEvent (QDropEvent * e)
695
{
696
    const QMimeData* data = e->mimeData();
697
    if (data->hasUrls()) {
698
        getMainWindow()->loadUrls(getAppDocument(), data->urls());
699
    }
700
    else {
701
        MDIView::dropEvent(e);
702
    }
703
}
704

705
void View3DInventor::dragEnterEvent (QDragEnterEvent * e)
706
{
707
    // Here we must allow uri drags and check them in dropEvent
708
    const QMimeData* data = e->mimeData();
709
    if (data->hasUrls())
710
        e->accept();
711
    else
712
        e->ignore();
713
}
714

715
void View3DInventor::setCurrentViewMode(ViewMode newmode)
716
{
717
    ViewMode oldmode = MDIView::currentViewMode();
718
    if (oldmode == newmode)
719
        return;
720

721
    if (newmode == Child) {
722
        // Fix in two steps:
723
        // The mdi view got a QWindow when it became a top-level widget and when resetting it to a child widget
724
        // the QWindow must be deleted because it has an impact on resize events and may break the layout of
725
        // mdi view inside the QMdiSubWindow.
726
        // In the second step below the layout must be invalidated after it's again a child widget to make sure
727
        // the mdi view fits into the QMdiSubWindow.
728
        QWindow* winHandle = this->windowHandle();
729
        if (winHandle)
730
            winHandle->destroy();
731
    }
732

733
    MDIView::setCurrentViewMode(newmode);
734

735
    // Internally the QOpenGLWidget switches of the multi-sampling and there is no
736
    // way to switch it on again. So as a workaround we just re-create a new viewport
737
    // The method is private but defined as slot to avoid to call it by accident.
738
    //int index = _viewer->metaObject()->indexOfMethod("replaceViewport()");
739
    //if (index >= 0) {
740
    //    _viewer->qt_metacall(QMetaObject::InvokeMetaMethod, index, 0);
741
    //}
742

743
    // This widget becomes the focus proxy of the embedded GL widget if we leave
744
    // the 'Child' mode. If we reenter 'Child' mode the focus proxy is reset to 0.
745
    // If we change from 'TopLevel' mode to 'Fullscreen' mode or vice versa nothing
746
    // happens.
747
    // Grabbing keyboard when leaving 'Child' mode (as done in a recent version) should
748
    // be avoided because when two or more windows are either in 'TopLevel' or 'Fullscreen'
749
    // mode only the last window gets all key event even if it is not the active one.
750
    //
751
    // It is important to set the focus proxy to get all key events otherwise we would lose
752
    // control after redirecting the first key event to the GL widget.
753
    if (oldmode == Child) {
754
        // To make a global shortcut working from this window we need to add
755
        // all existing actions from the mainwindow and its sub-widgets
756
        QList<QAction*> acts = getMainWindow()->findChildren<QAction*>();
757
        this->addActions(acts);
758
        _viewer->getGLWidget()->setFocusProxy(this);
759
        // To be notfified for new actions
760
        qApp->installEventFilter(this);
761
    }
762
    else if (newmode == Child) {
763
        _viewer->getGLWidget()->setFocusProxy(nullptr);
764
        qApp->removeEventFilter(this);
765
        QList<QAction*> acts = this->actions();
766
        for (QAction* it : acts)
767
            this->removeAction(it);
768

769
        // Step two
770
        auto mdi = qobject_cast<QMdiSubWindow*>(parentWidget());
771
        if (mdi && mdi->layout())
772
            mdi->layout()->invalidate();
773
    }
774
}
775

776
bool View3DInventor::eventFilter(QObject* watched, QEvent* e)
777
{
778
    // As long as this widget is a top-level window (either in 'TopLevel' or 'FullScreen' mode) we
779
    // need to be notified when an action is added to a widget. This action must also be added to
780
    // this window to allow to make use of its shortcut (if defined).
781
    // Note: We don't need to care about removing an action if its parent widget gets destroyed.
782
    // This does the action itself for us.
783
    if (watched != this && e->type() == QEvent::ActionAdded) {
784
        auto a = static_cast<QActionEvent*>(e);
785
        QAction* action = a->action();
786

787
        if (!action->isSeparator()) {
788
            QList<QAction*> actions = this->actions();
789
            if (!actions.contains(action))
790
                this->addAction(action);
791
        }
792
    }
793

794
    return false;
795
}
796

797
void View3DInventor::keyPressEvent (QKeyEvent* e)
798
{
799
    // See StdViewDockUndockFullscreen::activated()
800
    // With Qt5 one cannot directly use 'setCurrentViewMode'
801
    // of an MDI view because it causes rendering problems.
802
    // The only reliable solution is to clone the MDI view,
803
    // set its view mode and close the original MDI view.
804

805
    QMainWindow::keyPressEvent(e);
806
}
807

808
void View3DInventor::keyReleaseEvent (QKeyEvent* e)
809
{
810
    QMainWindow::keyReleaseEvent(e);
811
}
812

813
void View3DInventor::focusInEvent (QFocusEvent *)
814
{
815
    _viewer->getGLWidget()->setFocus();
816
}
817

818
void View3DInventor::contextMenuEvent (QContextMenuEvent*e)
819
{
820
    MDIView::contextMenuEvent(e);
821
}
822

823
void View3DInventor::customEvent(QEvent * e)
824
{
825
    if (e->type() == QEvent::User) {
826
        auto se = static_cast<NavigationStyleEvent*>(e);
827
        ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
828
            ("User parameter:BaseApp/Preferences/View");
829
        if (hGrp->GetBool("SameStyleForAllViews", true))
830
            hGrp->SetASCII("NavigationStyle", se->style().getName());
831
        else
832
            _viewer->setNavigationType(se->style());
833
    }
834
}
835

836

837
#include "moc_View3DInventor.cpp"
838

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

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

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

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