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 = reinterpret_cast<EnableTouch>(
437 QFunctionPointer(QGuiApplication::platformNativeInterface()
438 ->nativeResourceFunctionForIntegration("registertouchwindow")));
439 if (enableTouch)
440 enableTouch(window, true);
441 window->setVisible(previousVisibility);
442#endif
443
444 connect(sender: window, signal: &QObject::destroyed, context: this, slot: &AbstractDeclarative::windowDestroyed);
445
446 int oldWindowSamples = m_windowSamples;
447 m_windowSamples = window->format().samples();
448 if (m_windowSamples < 0)
449 m_windowSamples = 0;
450
451 connect(sender: window, signal: &QQuickWindow::beforeSynchronizing,
452 context: this, slot: &AbstractDeclarative::synchDataToRenderer,
453 type: Qt::DirectConnection);
454
455 if (m_renderMode == RenderDirectToBackground_NoClear
456 || m_renderMode == RenderDirectToBackground) {
457 connect(sender: window, signal: &QQuickWindow::beforeRenderPassRecording, context: this, slot: &AbstractDeclarative::render,
458 type: Qt::DirectConnection);
459 setAntialiasing(m_windowSamples > 0);
460 if (m_windowSamples != oldWindowSamples)
461 emit msaaSamplesChanged(samples: m_windowSamples);
462 }
463
464 connect(sender: m_controller.data(), signal: &Abstract3DController::needRender, context: window, slot: &QQuickWindow::update);
465
466 updateWindowParameters();
467
468#if defined(Q_OS_IOS)
469 // Scenegraph render cycle in iOS sometimes misses update after beforeSynchronizing signal.
470 // This ensures we don't end up displaying the graph without any data, in case update is
471 // skipped after synchDataToRenderer.
472 QTimer::singleShot(0, window, SLOT(update()));
473#endif
474}
475
476void AbstractDeclarative::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
477{
478 QQuickItem::geometryChange(newGeometry, oldGeometry);
479
480 m_cachedGeometry = newGeometry;
481
482 updateWindowParameters();
483}
484
485void AbstractDeclarative::itemChange(ItemChange change, const ItemChangeData & value)
486{
487 QQuickItem::itemChange(change, value);
488 updateWindowParameters();
489}
490
491void AbstractDeclarative::updateWindowParameters()
492{
493 const QMutexLocker locker(&m_mutex);
494
495 // Update the device pixel ratio, window size and bounding box
496 QQuickWindow *win = window();
497 if (win && !m_controller.isNull()) {
498 Q3DScene *scene = m_controller->scene();
499 if (win->devicePixelRatio() != scene->devicePixelRatio()) {
500 scene->setDevicePixelRatio(win->devicePixelRatio());
501 win->update();
502 }
503
504 bool directRender = m_renderMode == RenderDirectToBackground
505 || m_renderMode == RenderDirectToBackground_NoClear;
506 QSize windowSize;
507
508 if (directRender)
509 windowSize = win->size();
510 else
511 windowSize = m_cachedGeometry.size().toSize();
512
513 if (windowSize != scene->d_ptr->windowSize()) {
514 scene->d_ptr->setWindowSize(windowSize);
515 win->update();
516 }
517
518 if (directRender) {
519 // Origin mapping is needed when rendering directly to background
520 QPointF point = QQuickItem::mapToScene(point: QPointF(0.0, 0.0));
521 scene->d_ptr->setViewport(QRect(point.x() + 0.5f, point.y() + 0.5f,
522 m_cachedGeometry.width() + 0.5f,
523 m_cachedGeometry.height() + 0.5f));
524 } else {
525 // No translation needed when rendering to FBO
526 scene->d_ptr->setViewport(QRect(0.0, 0.0, m_cachedGeometry.width() + 0.5f,
527 m_cachedGeometry.height() + 0.5f));
528 }
529 }
530}
531
532void AbstractDeclarative::handleSelectionModeChange(QAbstract3DGraph::SelectionFlags mode)
533{
534 int intmode = int(mode);
535 emit selectionModeChanged(mode: SelectionFlags(intmode));
536}
537
538void AbstractDeclarative::handleShadowQualityChange(QAbstract3DGraph::ShadowQuality quality)
539{
540 emit shadowQualityChanged(quality: ShadowQuality(quality));
541}
542
543void AbstractDeclarative::handleSelectedElementChange(QAbstract3DGraph::ElementType type)
544{
545 emit selectedElementChanged(type: ElementType(type));
546}
547
548void AbstractDeclarative::handleOptimizationHintChange(QAbstract3DGraph::OptimizationHints hints)
549{
550 int intHints = int(hints);
551 emit optimizationHintsChanged(hints: OptimizationHints(intHints));
552}
553
554void AbstractDeclarative::render()
555{
556 updateWindowParameters();
557
558 // If we're not rendering directly to the background, return
559 if (m_renderMode != RenderDirectToBackground && m_renderMode != RenderDirectToBackground_NoClear)
560 return;
561
562 // Clear the background once per window as that is not done by default
563 QQuickWindow *win = window();
564 win->beginExternalCommands();
565 activateOpenGLContext(window: win);
566
567 QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
568
569 if (funcs && isVisible()) {
570 funcs->glDepthMask(GL_TRUE);
571 funcs->glEnable(GL_DEPTH_TEST);
572 funcs->glDepthFunc(GL_LESS);
573 funcs->glEnable(GL_CULL_FACE);
574 funcs->glCullFace(GL_BACK);
575 funcs->glDisable(GL_BLEND);
576
577 m_controller->render();
578
579 funcs->glEnable(GL_BLEND);
580 }
581
582 doneOpenGLContext(window: win);
583 win->endExternalCommands();
584}
585
586QAbstract3DInputHandler* AbstractDeclarative::inputHandler() const
587{
588 return m_controller->activeInputHandler();
589}
590
591void AbstractDeclarative::setInputHandler(QAbstract3DInputHandler *inputHandler)
592{
593 m_controller->setActiveInputHandler(inputHandler);
594}
595
596void AbstractDeclarative::mouseDoubleClickEvent(QMouseEvent *event)
597{
598 m_controller->mouseDoubleClickEvent(event);
599}
600
601void AbstractDeclarative::touchEvent(QTouchEvent *event)
602{
603 m_controller->touchEvent(event);
604 window()->update();
605}
606
607void AbstractDeclarative::mousePressEvent(QMouseEvent *event)
608{
609 QPoint mousePos = event->pos();
610 m_controller->mousePressEvent(event, mousePos);
611}
612
613void AbstractDeclarative::mouseReleaseEvent(QMouseEvent *event)
614{
615 QPoint mousePos = event->pos();
616 m_controller->mouseReleaseEvent(event, mousePos);
617}
618
619void AbstractDeclarative::mouseMoveEvent(QMouseEvent *event)
620{
621 QPoint mousePos = event->pos();
622 m_controller->mouseMoveEvent(event, mousePos);
623}
624
625#if QT_CONFIG(wheelevent)
626void AbstractDeclarative::wheelEvent(QWheelEvent *event)
627{
628 m_controller->wheelEvent(event);
629}
630#endif
631
632void AbstractDeclarative::checkWindowList(QQuickWindow *window)
633{
634 QQuickWindow *oldWindow = graphWindowList.value(key: this);
635 graphWindowList[this] = window;
636
637 if (oldWindow != window && oldWindow) {
638 QObject::disconnect(sender: oldWindow, signal: &QObject::destroyed, receiver: this,
639 slot: &AbstractDeclarative::windowDestroyed);
640 QObject::disconnect(sender: oldWindow, signal: &QQuickWindow::beforeSynchronizing, receiver: this,
641 slot: &AbstractDeclarative::synchDataToRenderer);
642 QObject::disconnect(sender: oldWindow, signal: &QQuickWindow::beforeRenderPassRecording, receiver: this,
643 slot: &AbstractDeclarative::render);
644 if (!m_controller.isNull()) {
645 QObject::disconnect(sender: m_controller.data(), signal: &Abstract3DController::needRender,
646 receiver: oldWindow, slot: &QQuickWindow::update);
647 }
648 }
649
650 QList<QQuickWindow *> windowList;
651 const auto graphs = graphWindowList.keys();
652 for (AbstractDeclarative *graph : graphs) {
653 if (graph->m_renderMode == RenderDirectToBackground
654 || graph->m_renderMode == RenderDirectToBackground_NoClear) {
655 windowList.append(t: graphWindowList.value(key: graph));
656 }
657 }
658
659 if (!window) {
660 graphWindowList.remove(key: this);
661 return;
662 }
663}
664
665void AbstractDeclarative::setMeasureFps(bool enable)
666{
667 m_controller->setMeasureFps(enable);
668}
669
670bool AbstractDeclarative::measureFps() const
671{
672 return m_controller->measureFps();
673}
674
675qreal AbstractDeclarative::currentFps() const
676{
677 return m_controller->currentFps();
678}
679
680void AbstractDeclarative::setOrthoProjection(bool enable)
681{
682 m_controller->setOrthoProjection(enable);
683}
684
685bool AbstractDeclarative::isOrthoProjection() const
686{
687 return m_controller->isOrthoProjection();
688}
689
690AbstractDeclarative::ElementType AbstractDeclarative::selectedElement() const
691{
692 return ElementType(m_controller->selectedElement());
693}
694
695void AbstractDeclarative::setAspectRatio(qreal ratio)
696{
697 m_controller->setAspectRatio(ratio);
698}
699
700qreal AbstractDeclarative::aspectRatio() const
701{
702 return m_controller->aspectRatio();
703}
704
705void AbstractDeclarative::setOptimizationHints(OptimizationHints hints)
706{
707 int intmode = int(hints);
708 m_controller->setOptimizationHints(QAbstract3DGraph::OptimizationHints(intmode));
709}
710
711AbstractDeclarative::OptimizationHints AbstractDeclarative::optimizationHints() const
712{
713 int intmode = int(m_controller->optimizationHints());
714 return OptimizationHints(intmode);
715}
716
717void AbstractDeclarative::setPolar(bool enable)
718{
719 m_controller->setPolar(enable);
720}
721
722bool AbstractDeclarative::isPolar() const
723{
724 return m_controller->isPolar();
725}
726
727void AbstractDeclarative::setRadialLabelOffset(float offset)
728{
729 m_controller->setRadialLabelOffset(offset);
730}
731
732float AbstractDeclarative::radialLabelOffset() const
733{
734 return m_controller->radialLabelOffset();
735}
736
737void AbstractDeclarative::setHorizontalAspectRatio(qreal ratio)
738{
739 m_controller->setHorizontalAspectRatio(ratio);
740}
741
742qreal AbstractDeclarative::horizontalAspectRatio() const
743{
744 return m_controller->horizontalAspectRatio();
745}
746
747void AbstractDeclarative::setReflection(bool enable)
748{
749 m_controller->setReflection(enable);
750}
751
752bool AbstractDeclarative::isReflection() const
753{
754 return m_controller->reflection();
755}
756
757void AbstractDeclarative::setReflectivity(qreal reflectivity)
758{
759 m_controller->setReflectivity(reflectivity);
760}
761
762qreal AbstractDeclarative::reflectivity() const
763{
764 return m_controller->reflectivity();
765}
766
767void AbstractDeclarative::setLocale(const QLocale &locale)
768{
769 m_controller->setLocale(locale);
770}
771
772QLocale AbstractDeclarative::locale() const
773{
774 return m_controller->locale();
775}
776
777QVector3D AbstractDeclarative::queriedGraphPosition() const
778{
779 return m_controller->queriedGraphPosition();
780}
781
782void AbstractDeclarative::setMargin(qreal margin)
783{
784 m_controller->setMargin(margin);
785}
786
787qreal AbstractDeclarative::margin() const
788{
789 return m_controller->margin();
790}
791
792void AbstractDeclarative::windowDestroyed(QObject *obj)
793{
794 // Remove destroyed window from window lists
795 QQuickWindow *win = static_cast<QQuickWindow *>(obj);
796 QQuickWindow *oldWindow = graphWindowList.value(key: this);
797
798 if (win == oldWindow)
799 graphWindowList.remove(key: this);
800}
801
802void AbstractDeclarative::destroyContext()
803{
804 if (m_contextThread && m_contextThread != m_mainThread) {
805 if (m_contextOrStateStore)
806 m_contextOrStateStore->deleteLater();
807 } else {
808 delete m_contextOrStateStore;
809 }
810 m_contextOrStateStore = 0;
811
812 if (m_contextThread) {
813 QObject::disconnect(sender: m_contextThread, signal: &QThread::finished, receiver: this,
814 slot: &AbstractDeclarative::destroyContext);
815 m_contextThread = 0;
816 }
817}
818
819QT_END_NAMESPACE
820

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