1
/***************************************************************************
2
* Copyright (c) 2004 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"
28
# include <QApplication>
32
# include <QDragEnterEvent>
34
# include <QMdiSubWindow>
35
# include <QMessageBox>
39
# include <QPrintDialog>
40
# include <QPrintPreviewDialog>
41
# include <QStackedWidget>
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>
52
#include <App/Document.h>
53
#include <Base/Builder3D.h>
54
#include <Base/Console.h>
55
#include <Base/Interpreter.h>
57
#include "View3DInventor.h"
58
#include "View3DSettings.h"
59
#include "Application.h"
60
#include "BitmapFactory.h"
63
#include "FileDialog.h"
64
#include "MainWindow.h"
66
#include "NavigationStyle.h"
68
#include "SoFCSelectionAction.h"
69
#include "SoFCVectorizeSVGAction.h"
70
#include "View3DInventorViewer.h"
72
#include "ViewProvider.h"
73
#include "WaitCursor.h"
78
void GLOverlayWidget::paintEvent(QPaintEvent*)
81
paint.drawImage(0,0,image);
85
/* TRANSLATOR Gui::View3DInventor */
87
TYPESYSTEM_SOURCE_ABSTRACT(Gui::View3DInventor,Gui::MDIView)
89
View3DInventor::View3DInventor(Gui::Document* pcDocument, QWidget* parent,
90
const QtGLWidget* sharewidget, Qt::WindowFlags wflags)
91
: MDIView(pcDocument, parent, wflags), _viewerPy(nullptr)
93
stack = new QStackedWidget(this);
94
// important for highlighting
95
setMouseTracking(true);
96
// accept drops on the window, get handled in dropEvent, dragEnterEvent
99
//anti-aliasing settings
100
bool smoothing = false;
101
bool glformat = false;
102
int samples = View3DInventorViewer::getNumSamples();
107
f.setSamples(samples);
109
else if (samples > 0) {
114
_viewer = new View3DInventorViewer(f, this, sharewidget);
116
_viewer = new View3DInventorViewer(this, sharewidget);
119
_viewer->getSoRenderManager()->getGLRenderAction()->setSmoothing(true);
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);
132
// apply the user settings
135
stopSpinTimer = new QTimer(this);
136
connect(stopSpinTimer, &QTimer::timeout, this, &View3DInventor::stopAnimating);
138
setWindowIcon(Gui::BitmapFactory().pixmap("Document"));
141
View3DInventor::~View3DInventor()
144
SoCamera * Cam = _viewer->getSoRenderManager()->getCamera();
146
_pcDocument->saveCameraSettings(SoFCDB::writeNodesToString(Cam).c_str());
149
viewSettings.reset();
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();
157
QWidget* par = foc->parentWidget();
160
foc->setFocusProxy(nullptr);
164
par = par->parentWidget();
169
Base::PyGILStateLocker lock;
170
Py_DECREF(_viewerPy);
173
// here is from time to time trouble!!!
177
void View3DInventor::deleteSelf()
179
_viewer->setSceneGraph(nullptr);
180
_viewer->setDocument(nullptr);
181
MDIView::deleteSelf();
184
PyObject *View3DInventor::getPyObject()
187
_viewerPy = new View3DInventorPy(this);
189
Py_INCREF(_viewerPy);
193
void View3DInventor::applySettings()
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();
203
void View3DInventor::onRename(Gui::Document *pDoc)
206
name.setValue(pDoc->getDocument()->getName());
207
SoFCDocumentAction cAct(name);
208
cAct.apply(_viewer->getSceneGraph());
211
void View3DInventor::onUpdate()
213
#ifdef FC_LOGUPDATECHAIN
214
Base::Console().Log("Acti: Gui::View3DInventor::onUpdate()");
220
void View3DInventor::viewAll()
225
const char *View3DInventor::getName() const
227
return "View3DInventor";
230
void View3DInventor::print()
232
QPrinter printer(QPrinter::ScreenResolution);
233
printer.setFullPage(true);
234
restorePrinterSettings(&printer);
236
QPrintDialog dlg(&printer, this);
237
if (dlg.exec() == QDialog::Accepted) {
240
savePrinterSettings(&printer);
244
void View3DInventor::printPdf()
246
QString filename = FileDialog::getSaveFileName(this, tr("Export PDF"), QString(),
247
QString::fromLatin1("%1 (*.pdf)").arg(tr("PDF file")));
248
if (!filename.isEmpty()) {
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);
260
void View3DInventor::printPreview()
262
QPrinter printer(QPrinter::ScreenResolution);
263
printer.setFullPage(true);
264
restorePrinterSettings(&printer);
266
QPrintPreviewDialog dlg(&printer, this);
267
connect(&dlg, &QPrintPreviewDialog::paintRequested,
268
this, qOverload<QPrinter*>(&View3DInventor::print));
270
savePrinterSettings(&printer);
273
void View3DInventor::print(QPrinter* 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();
285
QRect rect = printer->pageLayout().paintRectPixels(printer->resolution());
287
_viewer->imageFromFramebuffer(rect.width(), rect.height(), 8, QColor(255,255,255), img);
288
p.drawImage(0,0,img);
292
bool View3DInventor::containsViewProvider(const ViewProvider* vp) const
294
return _viewer->containsViewProvider(vp);
297
// **********************************************************************************
299
bool View3DInventor::onMsg(const char* pMsg, const char** ppReturn)
301
if (strcmp("ViewFit",pMsg) == 0) {
305
else if (strcmp("ViewVR",pMsg) == 0) {
306
// call the VR portion of the viewer
310
else if(strcmp("ViewSelection",pMsg) == 0) {
311
_viewer->viewSelection();
314
else if(strcmp("SetStereoRedGreen",pMsg) == 0 ) {
315
_viewer->setStereoMode(Quarter::SoQTQuarterAdaptor::ANAGLYPH);
318
else if(strcmp("SetStereoQuadBuff",pMsg) == 0 ) {
319
_viewer->setStereoMode(Quarter::SoQTQuarterAdaptor::QUAD_BUFFER );
322
else if(strcmp("SetStereoInterleavedRows",pMsg) == 0 ) {
323
_viewer->setStereoMode(Quarter::SoQTQuarterAdaptor::INTERLEAVED_ROWS );
326
else if(strcmp("SetStereoInterleavedColumns",pMsg) == 0 ) {
327
_viewer->setStereoMode(Quarter::SoQTQuarterAdaptor::INTERLEAVED_COLUMNS );
330
else if(strcmp("SetStereoOff",pMsg) == 0 ) {
331
_viewer->setStereoMode(Quarter::SoQTQuarterAdaptor::MONO );
334
else if(strcmp("GetCamera",pMsg) == 0 ) {
335
SoCamera * Cam = _viewer->getSoRenderManager()->getCamera();
338
*ppReturn = SoFCDB::writeNodesToString(Cam).c_str();
341
else if(strncmp("SetCamera",pMsg,9) == 0 ) {
342
return setCamera(pMsg+10);
344
else if(strncmp("Dump",pMsg,4) == 0 ) {
348
else if(strcmp("ViewBottom",pMsg) == 0 ) {
349
_viewer->setCameraOrientation(Camera::rotation(Camera::Bottom));
353
else if(strcmp("ViewFront",pMsg) == 0 ) {
354
_viewer->setCameraOrientation(Camera::rotation(Camera::Front));
358
else if(strcmp("ViewLeft",pMsg) == 0 ) {
359
_viewer->setCameraOrientation(Camera::rotation(Camera::Left));
363
else if(strcmp("ViewRear",pMsg) == 0 ) {
364
_viewer->setCameraOrientation(Camera::rotation(Camera::Rear));
368
else if(strcmp("ViewRight",pMsg) == 0 ) {
369
_viewer->setCameraOrientation(Camera::rotation(Camera::Right));
373
else if(strcmp("ViewTop",pMsg) == 0 ) {
374
_viewer->setCameraOrientation(Camera::rotation(Camera::Top));
378
else if(strcmp("ViewAxo",pMsg) == 0 ) {
379
_viewer->setCameraOrientation(Camera::rotation(Camera::Isometric));
383
else if(strcmp("OrthographicCamera",pMsg) == 0 ) {
384
_viewer->setCameraType(SoOrthographicCamera::getClassTypeId());
387
else if(strcmp("PerspectiveCamera",pMsg) == 0 ) {
388
_viewer->setCameraType(SoPerspectiveCamera::getClassTypeId());
391
else if(strcmp("Undo",pMsg) == 0 ) {
392
getGuiDocument()->undo(1);
395
else if(strcmp("Redo",pMsg) == 0 ) {
396
getGuiDocument()->redo(1);
399
else if (strcmp("Save",pMsg) == 0) {
400
getGuiDocument()->save();
403
else if (strcmp("SaveAs",pMsg) == 0) {
404
getGuiDocument()->saveAs();
407
else if (strcmp("SaveCopy",pMsg) == 0) {
408
getGuiDocument()->saveCopy();
411
else if (strcmp("AlignToSelection", pMsg) == 0) {
412
_viewer->alignToSelection();
415
else if (strcmp("ZoomIn", pMsg) == 0) {
416
View3DInventorViewer* viewer = getViewer();
417
viewer->navigationStyle()->zoomIn();
420
else if (strcmp("ZoomOut", pMsg) == 0) {
421
View3DInventorViewer* viewer = getViewer();
422
viewer->navigationStyle()->zoomOut();
429
bool View3DInventor::onHasMsg(const char* pMsg) const
431
if (strcmp("CanPan", pMsg) == 0) {
434
else if (strcmp("Save",pMsg) == 0) {
437
else if (strcmp("SaveAs",pMsg) == 0) {
440
else if (strcmp("SaveCopy",pMsg) == 0) {
443
else if (strcmp("Undo",pMsg) == 0) {
444
App::Document* doc = getAppDocument();
445
return doc && doc->getAvailableUndos() > 0;
447
else if (strcmp("Redo",pMsg) == 0) {
448
App::Document* doc = getAppDocument();
449
return doc && doc->getAvailableRedos() > 0;
451
else if (strcmp("Print",pMsg) == 0) {
454
else if (strcmp("PrintPreview",pMsg) == 0) {
457
else if (strcmp("PrintPdf",pMsg) == 0) {
460
else if(strcmp("SetStereoRedGreen",pMsg) == 0) {
463
else if(strcmp("SetStereoQuadBuff",pMsg) == 0) {
466
else if(strcmp("SetStereoInterleavedRows",pMsg) == 0) {
469
else if(strcmp("SetStereoInterleavedColumns",pMsg) == 0) {
472
else if(strcmp("SetStereoOff",pMsg) == 0) {
475
else if(strcmp("ViewFit",pMsg) == 0) {
478
else if(strcmp("ViewVR",pMsg) == 0) {
485
else if(strcmp("ViewSelection",pMsg) == 0) {
488
else if(strcmp("ViewBottom",pMsg) == 0) {
491
else if(strcmp("ViewFront",pMsg) == 0) {
494
else if(strcmp("ViewLeft",pMsg) == 0) {
497
else if(strcmp("ViewRear",pMsg) == 0) {
500
else if(strcmp("ViewRight",pMsg) == 0) {
503
else if(strcmp("ViewTop",pMsg) == 0) {
506
else if(strcmp("ViewAxo",pMsg) == 0) {
509
else if(strcmp("GetCamera",pMsg) == 0) {
512
else if(strncmp("SetCamera",pMsg,9) == 0) {
515
else if(strncmp("Dump",pMsg,4) == 0) {
518
else if (strcmp("AlignToSelection", pMsg) == 0) {
521
if (strcmp("ZoomIn", pMsg) == 0) {
524
if (strcmp("ZoomOut", pMsg) == 0) {
527
if (strcmp("AllowsOverlayOnHover", pMsg) == 0) {
534
bool View3DInventor::setCamera(const char* pCamera)
536
SoCamera * CamViewer = _viewer->getSoRenderManager()->getCamera();
538
throw Base::RuntimeError("No camera set so far...");
542
in.setBuffer((void*)pCamera,std::strlen(pCamera));
547
if (!Cam || !Cam->isOfType(SoCamera::getClassTypeId())) {
548
throw Base::RuntimeError("Camera settings failed to read");
551
// this is to make sure to reliably delete the node
552
CoinPtr<SoNode> camPtr(Cam, true);
554
// toggle between perspective and orthographic camera
555
if (Cam->getTypeId() != CamViewer->getTypeId()) {
556
_viewer->setCameraType(Cam->getTypeId());
557
CamViewer = _viewer->getSoRenderManager()->getCamera();
560
SoPerspectiveCamera * CamViewerP = nullptr;
561
SoOrthographicCamera * CamViewerO = nullptr;
563
if (CamViewer->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
564
CamViewerP = static_cast<SoPerspectiveCamera *>(CamViewer); // safe downward cast, knows the type
566
else if (CamViewer->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
567
CamViewerO = static_cast<SoOrthographicCamera *>(CamViewer); // safe downward cast, knows the type
570
if (Cam->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
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;
579
throw Base::TypeError("Camera type mismatch");
582
else if (Cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
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;
594
throw Base::TypeError("Camera type mismatch");
601
void View3DInventor::toggleClippingPlane()
603
_viewer->toggleClippingPlane();
606
bool View3DInventor::hasClippingPlane() const
608
return _viewer->hasClippingPlane();
611
void View3DInventor::setOverlayWidget(QWidget* widget)
613
removeOverlayWidget();
614
stack->addWidget(widget);
615
stack->setCurrentIndex(1);
618
void View3DInventor::removeOverlayWidget()
620
stack->setCurrentIndex(0);
621
QWidget* overlay = stack->widget(1);
622
if (overlay) stack->removeWidget(overlay);
625
void View3DInventor::setOverrideCursor(const QCursor& aCursor)
627
_viewer->getWidget()->setCursor(aCursor);
630
void View3DInventor::restoreOverrideCursor()
632
_viewer->getWidget()->setCursor(QCursor(Qt::ArrowCursor));
635
// defined in SoFCDB.cpp
636
extern SoNode* replaceSwitchesInSceneGraph(SoNode*);
638
void View3DInventor::dump(const char* filename, bool onlyVisible)
640
SoGetPrimitiveCountAction action;
641
action.setCanApproximate(true);
642
action.apply(_viewer->getSceneGraph());
644
SoNode* node = _viewer->getSceneGraph();
646
node = replaceSwitchesInSceneGraph(node);
650
if ( action.getTriangleCount() > 100000 || action.getPointCount() > 30000 || action.getLineCount() > 10000 )
651
_viewer->dumpToFile(node, filename, true);
653
_viewer->dumpToFile(node, filename, false);
660
void View3DInventor::windowStateChanged(QWidget* view)
662
bool canStartTimer = false;
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;
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);
680
} else if (stopSpinTimer->isActive()) {
681
// If this view may be visible again we can stop the timer
682
stopSpinTimer->stop();
686
void View3DInventor::stopAnimating()
688
_viewer->stopAnimating();
692
* Drops the event \a e and writes the right Python command.
694
void View3DInventor::dropEvent (QDropEvent * e)
696
const QMimeData* data = e->mimeData();
697
if (data->hasUrls()) {
698
getMainWindow()->loadUrls(getAppDocument(), data->urls());
701
MDIView::dropEvent(e);
705
void View3DInventor::dragEnterEvent (QDragEnterEvent * e)
707
// Here we must allow uri drags and check them in dropEvent
708
const QMimeData* data = e->mimeData();
715
void View3DInventor::setCurrentViewMode(ViewMode newmode)
717
ViewMode oldmode = MDIView::currentViewMode();
718
if (oldmode == newmode)
721
if (newmode == Child) {
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();
730
winHandle->destroy();
733
MDIView::setCurrentViewMode(newmode);
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()");
740
// _viewer->qt_metacall(QMetaObject::InvokeMetaMethod, index, 0);
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
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.
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);
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);
770
auto mdi = qobject_cast<QMdiSubWindow*>(parentWidget());
771
if (mdi && mdi->layout())
772
mdi->layout()->invalidate();
776
bool View3DInventor::eventFilter(QObject* watched, QEvent* e)
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();
787
if (!action->isSeparator()) {
788
QList<QAction*> actions = this->actions();
789
if (!actions.contains(action))
790
this->addAction(action);
797
void View3DInventor::keyPressEvent (QKeyEvent* e)
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.
805
QMainWindow::keyPressEvent(e);
808
void View3DInventor::keyReleaseEvent (QKeyEvent* e)
810
QMainWindow::keyReleaseEvent(e);
813
void View3DInventor::focusInEvent (QFocusEvent *)
815
_viewer->getGLWidget()->setFocus();
818
void View3DInventor::contextMenuEvent (QContextMenuEvent*e)
820
MDIView::contextMenuEvent(e);
823
void View3DInventor::customEvent(QEvent * e)
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());
832
_viewer->setNavigationType(se->style());
837
#include "moc_View3DInventor.cpp"