1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "abstractdeclarative_p.h"
5#include "declarativetheme_p.h"
6#include "declarativerendernode_p.h"
7#include <QtGui/QGuiApplication>
8#if defined(Q_OS_IOS)
9#include <QtCore/QTimer>
10#endif
11#if defined(Q_OS_MACOS)
12#include <qpa/qplatformnativeinterface.h>
13#endif
14
15#if !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT)
16#define USE_SHARED_CONTEXT
17#else
18#include "glstatestore_p.h"
19#endif
20
21QT_BEGIN_NAMESPACE
22
23static QHash<AbstractDeclarative *, QQuickWindow *> graphWindowList;
24
25AbstractDeclarative::AbstractDeclarative(QQuickItem *parent) :
26 QQuickItem(parent),
27 AbstractDeclarativeInterface(),
28 m_controller(0),
29 m_contextWindow(0),
30 m_renderMode(RenderIndirect),
31 m_samples(0),
32 m_windowSamples(0),
33 m_initialisedSize(0, 0),
34 m_contextOrStateStore(0),
35 m_qtContext(0),
36 m_mainThread(QThread::currentThread()),
37 m_contextThread(0)
38{
39 m_nodeMutex = QSharedPointer<QMutex>::create();
40
41 connect(sender: this, signal: &QQuickItem::windowChanged, context: this, slot: &AbstractDeclarative::handleWindowChanged);
42
43 // Set contents to false in case we are in qml designer to make component look nice
44 m_runningInDesigner = QGuiApplication::applicationDisplayName() == QLatin1String("Qml2Puppet");
45 setFlag(flag: ItemHasContents, enabled: !m_runningInDesigner);
46
47 // Accept touchevents
48 setAcceptTouchEvents(true);
49}
50
51AbstractDeclarative::~AbstractDeclarative()
52{
53 destroyContext();
54
55 disconnect(sender: this, signal: 0, receiver: this, member: 0);
56 checkWindowList(window: 0);
57
58 // Make sure not deleting locked mutex
59 QMutexLocker locker(&m_mutex);
60 locker.unlock();
61
62 m_nodeMutex.clear();
63}
64
65void AbstractDeclarative::setRenderingMode(AbstractDeclarative::RenderingMode mode)
66{
67 if (mode == m_renderMode
68 || mode <= AbstractDeclarative::RenderingMode::RenderDirectToBackground
69 || mode >= AbstractDeclarative::RenderingMode::RenderIndirect) {
70 return;
71 }
72
73 RenderingMode previousMode = m_renderMode;
74
75 m_renderMode = mode;
76
77 QQuickWindow *win = window();
78
79 switch (mode) {
80 case RenderDirectToBackground:
81 // Intentional flowthrough
82 case RenderDirectToBackground_NoClear:
83 m_initialisedSize = QSize(0, 0);
84 if (previousMode == RenderIndirect) {
85 update();
86 setFlag(flag: ItemHasContents, enabled: false);
87 if (win) {
88 QObject::connect(sender: win, signal: &QQuickWindow::beforeRenderPassRecording, context: this,
89 slot: &AbstractDeclarative::render, type: Qt::DirectConnection);
90 checkWindowList(window: win);
91 setAntialiasing(m_windowSamples > 0);
92 if (m_windowSamples != m_samples)
93 emit msaaSamplesChanged(samples: m_windowSamples);
94 }
95 }
96 break;
97 case RenderIndirect:
98 m_initialisedSize = QSize(0, 0);
99 setFlag(flag: ItemHasContents, enabled: !m_runningInDesigner);
100 update();
101 if (win) {
102 QObject::disconnect(sender: win, signal: &QQuickWindow::beforeRenderPassRecording, receiver: this,
103 slot: &AbstractDeclarative::render);
104 checkWindowList(window: win);
105 }
106 setAntialiasing(m_samples > 0);
107 if (m_windowSamples != m_samples)
108 emit msaaSamplesChanged(samples: m_samples);
109 break;
110 }
111
112 updateWindowParameters();
113
114 emit renderingModeChanged(mode);
115}
116
117AbstractDeclarative::RenderingMode AbstractDeclarative::renderingMode() const
118{
119 return m_renderMode;
120}
121
122QSGNode *AbstractDeclarative::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
123{
124 QSize boundingSize = boundingRect().size().toSize() * m_controller->scene()->devicePixelRatio();
125 if (m_runningInDesigner || boundingSize.width() <= 0 || boundingSize.height() <= 0
126 || m_controller.isNull() || !window()) {
127 delete oldNode;
128 return 0;
129 }
130 DeclarativeRenderNode *node = static_cast<DeclarativeRenderNode *>(oldNode);
131
132 if (!node) {
133 node = new DeclarativeRenderNode(this, m_nodeMutex);
134 node->setController(m_controller.data());
135 node->setQuickWindow(window());
136 }
137
138 node->setSize(boundingSize);
139 node->setSamples(m_samples);
140 node->update();
141 node->markDirty(bits: QSGNode::DirtyMaterial);
142
143 return node;
144}
145
146Declarative3DScene* AbstractDeclarative::scene() const
147{
148 return static_cast<Declarative3DScene *>(m_controller->scene());
149}
150
151void AbstractDeclarative::setTheme(Q3DTheme *theme)
152{
153 m_controller->setActiveTheme(theme, force: isComponentComplete());
154}
155
156Q3DTheme *AbstractDeclarative::theme() const
157{
158 return m_controller->activeTheme();
159}
160
161void AbstractDeclarative::clearSelection()
162{
163 m_controller->clearSelection();
164}
165
166bool AbstractDeclarative::hasSeries(QAbstract3DSeries *series)
167{
168 return m_controller->hasSeries(series);
169}
170
171void AbstractDeclarative::setSelectionMode(SelectionFlags mode)
172{
173 int intmode = int(mode);
174 m_controller->setSelectionMode(QAbstract3DGraph::SelectionFlags(intmode));
175}
176
177AbstractDeclarative::SelectionFlags AbstractDeclarative::selectionMode() const
178{
179 int intmode = int(m_controller->selectionMode());
180 return SelectionFlags(intmode);
181}
182
183void AbstractDeclarative::setShadowQuality(ShadowQuality quality)
184{
185 m_controller->setShadowQuality(QAbstract3DGraph::ShadowQuality(quality));
186}
187
188AbstractDeclarative::ShadowQuality AbstractDeclarative::shadowQuality() const
189{
190 return ShadowQuality(m_controller->shadowQuality());
191}
192
193bool AbstractDeclarative::shadowsSupported() const
194{
195 return m_controller->shadowsSupported();
196}
197
198int AbstractDeclarative::addCustomItem(QCustom3DItem *item)
199{
200 return m_controller->addCustomItem(item);
201}
202
203void AbstractDeclarative::removeCustomItems()
204{
205 m_controller->deleteCustomItems();
206}
207
208void AbstractDeclarative::removeCustomItem(QCustom3DItem *item)
209{
210 m_controller->deleteCustomItem(item);
211}
212
213void AbstractDeclarative::removeCustomItemAt(const QVector3D &position)
214{
215 m_controller->deleteCustomItem(position);
216}
217
218void AbstractDeclarative::releaseCustomItem(QCustom3DItem *item)
219{
220 m_controller->releaseCustomItem(item);
221}
222
223int AbstractDeclarative::selectedLabelIndex() const
224{
225 return m_controller->selectedLabelIndex();
226}
227
228QAbstract3DAxis *AbstractDeclarative::selectedAxis() const
229{
230 return m_controller->selectedAxis();
231}
232
233int AbstractDeclarative::selectedCustomItemIndex() const
234{
235 return m_controller->selectedCustomItemIndex();
236}
237
238QCustom3DItem *AbstractDeclarative::selectedCustomItem() const
239{
240 return m_controller->selectedCustomItem();
241}
242
243QQmlListProperty<QCustom3DItem> AbstractDeclarative::customItemList()
244{
245 return QQmlListProperty<QCustom3DItem>(this, this,
246 &AbstractDeclarative::appendCustomItemFunc,
247 &AbstractDeclarative::countCustomItemFunc,
248 &AbstractDeclarative::atCustomItemFunc,
249 &AbstractDeclarative::clearCustomItemFunc);
250}
251
252void AbstractDeclarative::appendCustomItemFunc(QQmlListProperty<QCustom3DItem> *list,
253 QCustom3DItem *item)
254{
255 AbstractDeclarative *decl = reinterpret_cast<AbstractDeclarative *>(list->data);
256 decl->addCustomItem(item);
257}
258
259qsizetype AbstractDeclarative::countCustomItemFunc(QQmlListProperty<QCustom3DItem> *list)
260{
261 return reinterpret_cast<AbstractDeclarative *>(list->data)->m_controller->m_customItems.size();
262}
263
264QCustom3DItem *AbstractDeclarative::atCustomItemFunc(QQmlListProperty<QCustom3DItem> *list,
265 qsizetype index)
266{
267 return reinterpret_cast<AbstractDeclarative *>(list->data)->m_controller->m_customItems.at(i: index);
268}
269
270void AbstractDeclarative::clearCustomItemFunc(QQmlListProperty<QCustom3DItem> *list)
271{
272 AbstractDeclarative *decl = reinterpret_cast<AbstractDeclarative *>(list->data);
273 decl->removeCustomItems();
274}
275
276void AbstractDeclarative::setSharedController(Abstract3DController *controller)
277{
278 Q_ASSERT(controller);
279 m_controller = controller;
280 m_controller->m_qml = this;
281
282 if (!m_controller->isOpenGLES())
283 m_samples = 4;
284 setAntialiasing(m_samples > 0);
285
286 // Reset default theme, as the default C++ theme is Q3DTheme, not DeclarativeTheme3D.
287 DeclarativeTheme3D *defaultTheme = new DeclarativeTheme3D;
288 defaultTheme->d_ptr->setDefaultTheme(true);
289 defaultTheme->setType(Q3DTheme::ThemeQt);
290 m_controller->setActiveTheme(theme: defaultTheme);
291
292 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::shadowQualityChanged, context: this,
293 slot: &AbstractDeclarative::handleShadowQualityChange);
294 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::activeInputHandlerChanged, context: this,
295 slot: &AbstractDeclarative::inputHandlerChanged);
296 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::activeThemeChanged, context: this,
297 slot: &AbstractDeclarative::themeChanged);
298 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::selectionModeChanged, context: this,
299 slot: &AbstractDeclarative::handleSelectionModeChange);
300 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::elementSelected, context: this,
301 slot: &AbstractDeclarative::handleSelectedElementChange);
302
303 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::axisXChanged, context: this,
304 slot: &AbstractDeclarative::handleAxisXChanged);
305 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::axisYChanged, context: this,
306 slot: &AbstractDeclarative::handleAxisYChanged);
307 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::axisZChanged, context: this,
308 slot: &AbstractDeclarative::handleAxisZChanged);
309
310 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::measureFpsChanged, context: this,
311 slot: &AbstractDeclarative::measureFpsChanged);
312 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::currentFpsChanged, context: this,
313 slot: &AbstractDeclarative::currentFpsChanged);
314
315 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::orthoProjectionChanged, context: this,
316 slot: &AbstractDeclarative::orthoProjectionChanged);
317
318 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::aspectRatioChanged, context: this,
319 slot: &AbstractDeclarative::aspectRatioChanged);
320 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::optimizationHintsChanged, context: this,
321 slot: &AbstractDeclarative::handleOptimizationHintChange);
322 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::polarChanged, context: this,
323 slot: &AbstractDeclarative::polarChanged);
324 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::radialLabelOffsetChanged, context: this,
325 slot: &AbstractDeclarative::radialLabelOffsetChanged);
326 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::horizontalAspectRatioChanged, context: this,
327 slot: &AbstractDeclarative::horizontalAspectRatioChanged);
328 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::reflectionChanged, context: this,
329 slot: &AbstractDeclarative::reflectionChanged);
330 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::reflectivityChanged, context: this,
331 slot: &AbstractDeclarative::reflectivityChanged);
332 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::localeChanged, context: this,
333 slot: &AbstractDeclarative::localeChanged);
334 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::queriedGraphPositionChanged, context: this,
335 slot: &AbstractDeclarative::queriedGraphPositionChanged);
336 QObject::connect(sender: m_controller.data(), signal: &Abstract3DController::marginChanged, context: this,
337 slot: &AbstractDeclarative::marginChanged);
338}
339
340void AbstractDeclarative::activateOpenGLContext(QQuickWindow *window)
341{
342 // We can assume we are not in middle of AbstractDeclarative destructor when we are here,
343 // since m_context creation is always done when this function is called from
344 // synchDataToRenderer(), which blocks main thread -> no need to mutex.
345 if (!m_contextOrStateStore || !m_qtContext || m_contextWindow != window) {
346 QOpenGLContext *currentContext = QOpenGLContext::currentContext();
347
348 // Note: Changing graph to different window when using multithreaded renderer will break!
349
350 delete m_contextOrStateStore;
351
352 m_contextThread = QThread::currentThread();
353 m_contextWindow = window;
354 m_qtContext = currentContext;
355
356#ifdef USE_SHARED_CONTEXT
357 m_context = new QOpenGLContext();
358 m_context->setFormat(m_qtContext->format());
359 m_context->setShareContext(m_qtContext);
360 m_context->create();
361 m_context->makeCurrent(surface: window);
362#else
363 // Shared contexts don't work properly in some platforms, so just store the
364 // context state on those
365 m_stateStore = new GLStateStore(QOpenGLContext::currentContext());
366 m_stateStore->storeGLState();
367#endif
368 m_controller->initializeOpenGL();
369
370 // Make sure context / state store gets deleted.
371 QObject::connect(sender: m_contextThread, signal: &QThread::finished, context: this,
372 slot: &AbstractDeclarative::destroyContext, type: Qt::DirectConnection);
373 } else {
374#ifdef USE_SHARED_CONTEXT
375 m_context->makeCurrent(surface: window);
376#else
377 m_stateStore->storeGLState();
378#endif
379 }
380}
381
382void AbstractDeclarative::doneOpenGLContext(QQuickWindow *window)
383{
384#ifdef USE_SHARED_CONTEXT
385 m_qtContext->makeCurrent(surface: window);
386#else
387 Q_UNUSED(window);
388 m_stateStore->restoreGLState();
389#endif
390}
391
392void AbstractDeclarative::synchDataToRenderer()
393{
394 QQuickWindow *win = window();
395 activateOpenGLContext(window: win);
396 m_controller->synchDataToRenderer();
397 doneOpenGLContext(window: win);
398}
399
400int AbstractDeclarative::msaaSamples() const
401{
402 if (m_renderMode == RenderIndirect)
403 return m_samples;
404 else
405 return m_windowSamples;
406}
407
408void AbstractDeclarative::setMsaaSamples(int samples)
409{
410 if (m_renderMode != RenderIndirect) {
411 qWarning(msg: "Multisampling cannot be adjusted in this render mode");
412 } else {
413 if (m_controller->isOpenGLES()) {
414 if (samples > 0)
415 qWarning(msg: "Multisampling is not supported in OpenGL ES2");
416 } else if (m_samples != samples) {
417 m_samples = samples;
418 setAntialiasing(m_samples > 0);
419 emit msaaSamplesChanged(samples);
420 update();
421 }
422 }
423}
424
425void AbstractDeclarative::handleWindowChanged(QQuickWindow *window)
426{
427 checkWindowList(window);
428 if (!window)
429 return;
430
431#if defined(Q_OS_MACOS)
432 bool previousVisibility = window->isVisible();
433 // Enable touch events for Mac touchpads
434 window->setVisible(true);
435 typedef void * (*EnableTouch)(QWindow*, bool);
436 EnableTouch enableTouch =
437 (EnableTouch)QGuiApplication::platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow");
438 if (enableTouch)
439 enableTouch(window, true);
440 window->setVisible(previousVisibility);
441#endif
442
443 connect(sender: window, signal: &QObject::destroyed, context: this, slot: &AbstractDeclarative::windowDestroyed);
444
445 int oldWindowSamples = m_windowSamples;
446 m_windowSamples = window->format().samples();
447 if (m_windowSamples < 0)
448 m_windowSamples = 0;
449
450 connect(sender: window, signal: &QQuickWindow::beforeSynchronizing,
451 context: this, slot: &AbstractDeclarative::synchDataToRenderer,
452 type: Qt::DirectConnection);
453
454 if (m_renderMode == RenderDirectToBackground_NoClear
455 || m_renderMode == RenderDirectToBackground) {
456 connect(sender: window, signal: &QQuickWindow::beforeRenderPassRecording, context: this, slot: &AbstractDeclarative::render,
457 type: Qt::DirectConnection);
458 setAntialiasing(m_windowSamples > 0);
459 if (m_windowSamples != oldWindowSamples)
460 emit msaaSamplesChanged(samples: m_windowSamples);
461 }
462
463 connect(sender: m_controller.data(), signal: &Abstract3DController::needRender, context: window, slot: &QQuickWindow::update);
464
465 updateWindowParameters();
466
467#if defined(Q_OS_IOS)
468 // Scenegraph render cycle in iOS sometimes misses update after beforeSynchronizing signal.
469 // This ensures we don't end up displaying the graph without any data, in case update is
470 // skipped after synchDataToRenderer.
471 QTimer::singleShot(0, window, SLOT(update()));
472#endif
473}
474
475void AbstractDeclarative::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
476{
477 QQuickItem::geometryChange(newGeometry, oldGeometry);
478
479 m_cachedGeometry = newGeometry;
480
481 updateWindowParameters();
482}
483
484void AbstractDeclarative::itemChange(ItemChange change, const ItemChangeData & value)
485{
486 QQuickItem::itemChange(change, value);
487 updateWindowParameters();
488}
489
490void AbstractDeclarative::updateWindowParameters()
491{
492 const QMutexLocker locker(&m_mutex);
493
494 // Update the device pixel ratio, window size and bounding box
495 QQuickWindow *win = window();
496 if (win && !m_controller.isNull()) {
497 Q3DScene *scene = m_controller->scene();
498 if (win->devicePixelRatio() != scene->devicePixelRatio()) {
499 scene->setDevicePixelRatio(win->devicePixelRatio());
500 win->update();
501 }
502
503 bool directRender = m_renderMode == RenderDirectToBackground
504 || m_renderMode == RenderDirectToBackground_NoClear;
505 QSize windowSize;
506
507 if (directRender)
508 windowSize = win->size();
509 else
510 windowSize = m_cachedGeometry.size().toSize();
511
512 if (windowSize != scene->d_ptr->windowSize()) {
513 scene->d_ptr->setWindowSize(windowSize);
514 win->update();
515 }
516
517 if (directRender) {
518 // Origin mapping is needed when rendering directly to background
519 QPointF point = QQuickItem::mapToScene(point: QPointF(0.0, 0.0));
520 scene->d_ptr->setViewport(QRect(point.x() + 0.5f, point.y() + 0.5f,
521 m_cachedGeometry.width() + 0.5f,
522 m_cachedGeometry.height() + 0.5f));
523 } else {
524 // No translation needed when rendering to FBO
525 scene->d_ptr->setViewport(QRect(0.0, 0.0, m_cachedGeometry.width() + 0.5f,
526 m_cachedGeometry.height() + 0.5f));
527 }
528 }
529}
530
531void AbstractDeclarative::handleSelectionModeChange(QAbstract3DGraph::SelectionFlags mode)
532{
533 int intmode = int(mode);
534 emit selectionModeChanged(mode: SelectionFlags(intmode));
535}
536
537void AbstractDeclarative::handleShadowQualityChange(QAbstract3DGraph::ShadowQuality quality)
538{
539 emit shadowQualityChanged(quality: ShadowQuality(quality));
540}
541
542void AbstractDeclarative::handleSelectedElementChange(QAbstract3DGraph::ElementType type)
543{
544 emit selectedElementChanged(type: ElementType(type));
545}
546
547void AbstractDeclarative::handleOptimizationHintChange(QAbstract3DGraph::OptimizationHints hints)
548{
549 int intHints = int(hints);
550 emit optimizationHintsChanged(hints: OptimizationHints(intHints));
551}
552
553void AbstractDeclarative::render()
554{
555 updateWindowParameters();
556
557 // If we're not rendering directly to the background, return
558 if (m_renderMode != RenderDirectToBackground && m_renderMode != RenderDirectToBackground_NoClear)
559 return;
560
561 // Clear the background once per window as that is not done by default
562 QQuickWindow *win = window();
563 win->beginExternalCommands();
564 activateOpenGLContext(window: win);
565
566 QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
567
568 if (funcs && isVisible()) {
569 funcs->glDepthMask(GL_TRUE);
570 funcs->glEnable(GL_DEPTH_TEST);
571 funcs->glDepthFunc(GL_LESS);
572 funcs->glEnable(GL_CULL_FACE);
573 funcs->glCullFace(GL_BACK);
574 funcs->glDisable(GL_BLEND);
575
576 m_controller->render();
577
578 funcs->glEnable(GL_BLEND);
579 }
580
581 doneOpenGLContext(window: win);
582 win->endExternalCommands();
583}
584
585QAbstract3DInputHandler* AbstractDeclarative::inputHandler() const
586{
587 return m_controller->activeInputHandler();
588}
589
590void AbstractDeclarative::setInputHandler(QAbstract3DInputHandler *inputHandler)
591{
592 m_controller->setActiveInputHandler(inputHandler);
593}
594
595void AbstractDeclarative::mouseDoubleClickEvent(QMouseEvent *event)
596{
597 m_controller->mouseDoubleClickEvent(event);
598}
599
600void AbstractDeclarative::touchEvent(QTouchEvent *event)
601{
602 m_controller->touchEvent(event);
603 window()->update();
604}
605
606void AbstractDeclarative::mousePressEvent(QMouseEvent *event)
607{
608 QPoint mousePos = event->pos();
609 m_controller->mousePressEvent(event, mousePos);
610}
611
612void AbstractDeclarative::mouseReleaseEvent(QMouseEvent *event)
613{
614 QPoint mousePos = event->pos();
615 m_controller->mouseReleaseEvent(event, mousePos);
616}
617
618void AbstractDeclarative::mouseMoveEvent(QMouseEvent *event)
619{
620 QPoint mousePos = event->pos();
621 m_controller->mouseMoveEvent(event, mousePos);
622}
623
624#if QT_CONFIG(wheelevent)
625void AbstractDeclarative::wheelEvent(QWheelEvent *event)
626{
627 m_controller->wheelEvent(event);
628}
629#endif
630
631void AbstractDeclarative::checkWindowList(QQuickWindow *window)
632{
633 QQuickWindow *oldWindow = graphWindowList.value(key: this);
634 graphWindowList[this] = window;
635
636 if (oldWindow != window && oldWindow) {
637 QObject::disconnect(sender: oldWindow, signal: &QObject::destroyed, receiver: this,
638 slot: &AbstractDeclarative::windowDestroyed);
639 QObject::disconnect(sender: oldWindow, signal: &QQuickWindow::beforeSynchronizing, receiver: this,
640 slot: &AbstractDeclarative::synchDataToRenderer);
641 QObject::disconnect(sender: oldWindow, signal: &QQuickWindow::beforeRenderPassRecording, receiver: this,
642 slot: &AbstractDeclarative::render);
643 if (!m_controller.isNull()) {
644 QObject::disconnect(sender: m_controller.data(), signal: &Abstract3DController::needRender,
645 receiver: oldWindow, slot: &QQuickWindow::update);
646 }
647 }
648
649 QList<QQuickWindow *> windowList;
650 const auto graphs = graphWindowList.keys();
651 for (AbstractDeclarative *graph : graphs) {
652 if (graph->m_renderMode == RenderDirectToBackground
653 || graph->m_renderMode == RenderDirectToBackground_NoClear) {
654 windowList.append(t: graphWindowList.value(key: graph));
655 }
656 }
657
658 if (!window) {
659 graphWindowList.remove(key: this);
660 return;
661 }
662}
663
664void AbstractDeclarative::setMeasureFps(bool enable)
665{
666 m_controller->setMeasureFps(enable);
667}
668
669bool AbstractDeclarative::measureFps() const
670{
671 return m_controller->measureFps();
672}
673
674qreal AbstractDeclarative::currentFps() const
675{
676 return m_controller->currentFps();
677}
678
679void AbstractDeclarative::setOrthoProjection(bool enable)
680{
681 m_controller->setOrthoProjection(enable);
682}
683
684bool AbstractDeclarative::isOrthoProjection() const
685{
686 return m_controller->isOrthoProjection();
687}
688
689AbstractDeclarative::ElementType AbstractDeclarative::selectedElement() const
690{
691 return ElementType(m_controller->selectedElement());
692}
693
694void AbstractDeclarative::setAspectRatio(qreal ratio)
695{
696 m_controller->setAspectRatio(ratio);
697}
698
699qreal AbstractDeclarative::aspectRatio() const
700{
701 return m_controller->aspectRatio();
702}
703
704void AbstractDeclarative::setOptimizationHints(OptimizationHints hints)
705{
706 int intmode = int(hints);
707 m_controller->setOptimizationHints(QAbstract3DGraph::OptimizationHints(intmode));
708}
709
710AbstractDeclarative::OptimizationHints AbstractDeclarative::optimizationHints() const
711{
712 int intmode = int(m_controller->optimizationHints());
713 return OptimizationHints(intmode);
714}
715
716void AbstractDeclarative::setPolar(bool enable)
717{
718 m_controller->setPolar(enable);
719}
720
721bool AbstractDeclarative::isPolar() const
722{
723 return m_controller->isPolar();
724}
725
726void AbstractDeclarative::setRadialLabelOffset(float offset)
727{
728 m_controller->setRadialLabelOffset(offset);
729}
730
731float AbstractDeclarative::radialLabelOffset() const
732{
733 return m_controller->radialLabelOffset();
734}
735
736void AbstractDeclarative::setHorizontalAspectRatio(qreal ratio)
737{
738 m_controller->setHorizontalAspectRatio(ratio);
739}
740
741qreal AbstractDeclarative::horizontalAspectRatio() const
742{
743 return m_controller->horizontalAspectRatio();
744}
745
746void AbstractDeclarative::setReflection(bool enable)
747{
748 m_controller->setReflection(enable);
749}
750
751bool AbstractDeclarative::isReflection() const
752{
753 return m_controller->reflection();
754}
755
756void AbstractDeclarative::setReflectivity(qreal reflectivity)
757{
758 m_controller->setReflectivity(reflectivity);
759}
760
761qreal AbstractDeclarative::reflectivity() const
762{
763 return m_controller->reflectivity();
764}
765
766void AbstractDeclarative::setLocale(const QLocale &locale)
767{
768 m_controller->setLocale(locale);
769}
770
771QLocale AbstractDeclarative::locale() const
772{
773 return m_controller->locale();
774}
775
776QVector3D AbstractDeclarative::queriedGraphPosition() const
777{
778 return m_controller->queriedGraphPosition();
779}
780
781void AbstractDeclarative::setMargin(qreal margin)
782{
783 m_controller->setMargin(margin);
784}
785
786qreal AbstractDeclarative::margin() const
787{
788 return m_controller->margin();
789}
790
791void AbstractDeclarative::windowDestroyed(QObject *obj)
792{
793 // Remove destroyed window from window lists
794 QQuickWindow *win = static_cast<QQuickWindow *>(obj);
795 QQuickWindow *oldWindow = graphWindowList.value(key: this);
796
797 if (win == oldWindow)
798 graphWindowList.remove(key: this);
799}
800
801void AbstractDeclarative::destroyContext()
802{
803 if (m_contextThread && m_contextThread != m_mainThread) {
804 if (m_contextOrStateStore)
805 m_contextOrStateStore->deleteLater();
806 } else {
807 delete m_contextOrStateStore;
808 }
809 m_contextOrStateStore = 0;
810
811 if (m_contextThread) {
812 QObject::disconnect(sender: m_contextThread, signal: &QThread::finished, receiver: this,
813 slot: &AbstractDeclarative::destroyContext);
814 m_contextThread = 0;
815 }
816}
817
818QT_END_NAMESPACE
819

source code of qtdatavis3d/src/datavisualizationqml/abstractdeclarative.cpp