1 | // Copyright (C) 2019 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qquick3dloader_p.h" |
5 | |
6 | #include "qquick3dobject_p.h" |
7 | |
8 | #include <QtQml/qqmlinfo.h> |
9 | |
10 | #include <private/qqmlengine_p.h> |
11 | #include <private/qqmlglobal_p.h> |
12 | |
13 | #include <private/qqmlcomponent_p.h> |
14 | #include <private/qqmlincubator_p.h> |
15 | |
16 | QT_BEGIN_NAMESPACE |
17 | |
18 | void QQuick3DLoaderIncubator::statusChanged(QQmlIncubator::Status status) |
19 | { |
20 | m_loader->incubatorStateChanged(status); |
21 | } |
22 | |
23 | void QQuick3DLoaderIncubator::setInitialState(QObject *o) |
24 | { |
25 | m_loader->setInitialState(o); |
26 | } |
27 | |
28 | /*! |
29 | \qmltype Loader3D |
30 | \inqmlmodule QtQuick3D |
31 | \inherits Node |
32 | |
33 | \brief Allows dynamic loading of a 3D subtree from a URL or Component. |
34 | |
35 | Loader3D is used to dynamically load QML components for Qt Quick 3D. |
36 | |
37 | Loader3D can load a |
38 | QML file (using the \l source property) or a \l Component object (using |
39 | the \l sourceComponent property). It is useful for delaying the creation |
40 | of a component until it is required: for example, when a component should |
41 | be created on demand, or when a component should not be created |
42 | unnecessarily for performance reasons. |
43 | |
44 | \note Loader3D works the same way as \l Loader. The difference between the |
45 | two is that \l Loader provides a way to dynamically load objects that inherit |
46 | \l Item, whereas Loader3D provides a way to load objects that inherit \l Object3D |
47 | and is part of a 3D scene. |
48 | */ |
49 | |
50 | QQuick3DLoader::QQuick3DLoader(QQuick3DNode *parent) |
51 | : QQuick3DNode(parent) |
52 | , m_item(nullptr) |
53 | , m_object(nullptr) |
54 | , m_itemContext(nullptr) |
55 | , m_incubator(nullptr) |
56 | , m_active(true) |
57 | , m_loadingFromSource(false) |
58 | , m_asynchronous(false) |
59 | { |
60 | } |
61 | |
62 | QQuick3DLoader::~QQuick3DLoader() |
63 | { |
64 | clear(); |
65 | delete m_incubator; |
66 | m_incubator = nullptr; |
67 | } |
68 | |
69 | /*! |
70 | \qmlproperty bool QtQuick3D::Loader3D::active |
71 | This property is \c true if the Loader3D is currently active. |
72 | The default value for this property is \c true. |
73 | |
74 | If the Loader3D is inactive, changing the \l source or \l sourceComponent |
75 | will not cause the item to be instantiated until the Loader3D is made active. |
76 | |
77 | Setting the value to inactive will cause any \l item loaded by the loader |
78 | to be released, but will not affect the \l source or \l sourceComponent. |
79 | |
80 | The \l status of an inactive loader is always \c Null. |
81 | |
82 | \sa source, sourceComponent |
83 | */ |
84 | |
85 | bool QQuick3DLoader::active() const |
86 | { |
87 | return m_active; |
88 | } |
89 | |
90 | void QQuick3DLoader::setActive(bool newVal) |
91 | { |
92 | if (m_active == newVal) |
93 | return; |
94 | |
95 | m_active = newVal; |
96 | if (newVal) { |
97 | if (m_loadingFromSource) { |
98 | loadFromSource(); |
99 | } else { |
100 | loadFromSourceComponent(); |
101 | } |
102 | } else { |
103 | // cancel any current incubation |
104 | if (m_incubator) { |
105 | m_incubator->clear(); |
106 | delete m_itemContext; |
107 | m_itemContext = nullptr; |
108 | } |
109 | |
110 | // Prevent any bindings from running while waiting for deletion. Without |
111 | // this we may get transient errors from use of 'parent', for example. |
112 | QQmlContext *context = qmlContext(m_object); |
113 | if (context) |
114 | QQmlContextData::get(context)->clearContextRecursively(); |
115 | |
116 | if (m_item) { |
117 | // We can't delete immediately because our item may have triggered |
118 | // the Loader to load a different item. |
119 | m_item->setParentItem(nullptr); |
120 | m_item->setVisible(false); |
121 | m_item = nullptr; |
122 | } |
123 | if (m_object) { |
124 | m_object->deleteLater(); |
125 | m_object = nullptr; |
126 | emit itemChanged(); |
127 | } |
128 | emit statusChanged(); |
129 | } |
130 | emit activeChanged(); |
131 | } |
132 | |
133 | void QQuick3DLoader::setSource(QQmlV4FunctionPtr args) |
134 | { |
135 | bool ipvError = false; |
136 | args->setReturnValue(QV4::Encode::undefined()); |
137 | QV4::Scope scope(args->v4engine()); |
138 | QV4::ScopedValue ipv(scope, extractInitialPropertyValues(args, error: &ipvError)); |
139 | if (ipvError) |
140 | return; |
141 | |
142 | clear(); |
143 | QUrl sourceUrl = resolveSourceUrl(args); |
144 | if (!ipv->isUndefined()) { |
145 | disposeInitialPropertyValues(); |
146 | m_initialPropertyValues.set(engine: args->v4engine(), value: ipv); |
147 | } |
148 | m_qmlCallingContext.set(engine: scope.engine, obj: scope.engine->qmlContext()); |
149 | |
150 | setSource(sourceUrl, needsClear: false); // already cleared and set ipv above. |
151 | } |
152 | |
153 | /*! |
154 | \qmlproperty url QtQuick3D::Loader3D::source |
155 | This property holds the URL of the QML component to instantiate. |
156 | |
157 | To unload the currently loaded object, set this property to an empty string, |
158 | or set \l sourceComponent to \c undefined. Setting \c source to a |
159 | new URL will also cause the item created by the previous URL to be unloaded. |
160 | |
161 | \sa sourceComponent, status, progress |
162 | */ |
163 | |
164 | QUrl QQuick3DLoader::source() const |
165 | { |
166 | return m_source; |
167 | } |
168 | |
169 | void QQuick3DLoader::setSource(const QUrl &url) |
170 | { |
171 | setSource(sourceUrl: url, needsClear: true); |
172 | } |
173 | |
174 | /*! |
175 | \qmlproperty Component QtQuick3D::Loader3D::sourceComponent |
176 | This property holds the \l{Component} to instantiate. |
177 | |
178 | \qml |
179 | Item { |
180 | Component { |
181 | id: redCube |
182 | Model { |
183 | source: "#Cube" |
184 | materials: DefaultMaterial { |
185 | diffuseColor: "red" |
186 | } |
187 | } |
188 | } |
189 | |
190 | Loader3D { sourceComponent: redCube } |
191 | Loader3D { sourceComponent: redCube; x: 10 } |
192 | } |
193 | \endqml |
194 | |
195 | To unload the currently loaded object, set this property to \c undefined. |
196 | |
197 | \sa source, progress |
198 | */ |
199 | |
200 | /*! |
201 | \qmlmethod object QtQuick3D::Loader3D::setSource(url source, object properties) |
202 | |
203 | Creates an object instance of the given \a source component that will have |
204 | the given \a properties. The \a properties argument is optional. The instance |
205 | will be accessible via the \l item property once loading and instantiation |
206 | is complete. |
207 | |
208 | If the \l active property is \c false at the time when this function is called, |
209 | the given \a source component will not be loaded but the \a source and initial |
210 | \a properties will be cached. When the loader is made \l active, an instance of |
211 | the \a source component will be created with the initial \a properties set. |
212 | |
213 | Setting the initial property values of an instance of a component in this manner |
214 | will \b{not} trigger any associated \l{Behavior}s. |
215 | |
216 | Note that the cached \a properties will be cleared if the \l source or \l sourceComponent |
217 | is changed after calling this function but prior to setting the loader \l active. |
218 | |
219 | \sa source, active |
220 | */ |
221 | |
222 | QQmlComponent *QQuick3DLoader::sourceComponent() const |
223 | { |
224 | return m_component; |
225 | } |
226 | |
227 | void QQuick3DLoader::setSourceComponent(QQmlComponent *comp) |
228 | { |
229 | if (comp == m_component) |
230 | return; |
231 | |
232 | clear(); |
233 | |
234 | m_component.setObject(obj: comp, parent: this); |
235 | m_loadingFromSource = false; |
236 | |
237 | if (m_active) |
238 | loadFromSourceComponent(); |
239 | else |
240 | emit sourceComponentChanged(); |
241 | } |
242 | |
243 | void QQuick3DLoader::resetSourceComponent() |
244 | { |
245 | setSourceComponent(nullptr); |
246 | } |
247 | |
248 | /*! |
249 | \qmlproperty enumeration QtQuick3D::Loader3D::status |
250 | \readonly |
251 | |
252 | This property holds the status of QML loading. It can be one of: |
253 | |
254 | \value Loader3D.Null The loader is inactive or no QML source has been set. |
255 | \value Loader3D.Ready The QML source has been loaded. |
256 | \value Loader3D.Loading The QML source is currently being loaded. |
257 | \value Loader3D.Error An error occurred while loading the QML source. |
258 | |
259 | Use this status to provide an update or respond to the status change in some way. |
260 | For example, you could: |
261 | |
262 | \list |
263 | \li Trigger a state change: |
264 | \qml |
265 | State { name: 'loaded'; when: loader.status == Loader3D.Ready } |
266 | \endqml |
267 | |
268 | \li Implement an \c onStatusChanged signal handler: |
269 | \qml |
270 | Loader3D { |
271 | id: loader |
272 | onStatusChanged: if (loader.status == Loader3D.Ready) console.log('Loaded') |
273 | } |
274 | \endqml |
275 | |
276 | \li Bind to the status value: |
277 | \qml |
278 | Text { text: loader.status == Loader3D.Ready ? 'Loaded' : 'Not loaded' } |
279 | \endqml |
280 | \endlist |
281 | |
282 | Note that if the source is a local file, the status will initially be Ready (or Error). While |
283 | there will be no onStatusChanged signal in that case, the onLoaded will still be invoked. |
284 | |
285 | \sa progress |
286 | */ |
287 | |
288 | QQuick3DLoader::Status QQuick3DLoader::status() const |
289 | { |
290 | if (!m_active) |
291 | return Null; |
292 | |
293 | if (m_component) { |
294 | switch (m_component->status()) { |
295 | case QQmlComponent::Loading: |
296 | return Loading; |
297 | case QQmlComponent::Error: |
298 | return Error; |
299 | case QQmlComponent::Null: |
300 | return Null; |
301 | default: |
302 | break; |
303 | } |
304 | } |
305 | |
306 | if (m_incubator) { |
307 | switch (m_incubator->status()) { |
308 | case QQmlIncubator::Loading: |
309 | return Loading; |
310 | case QQmlIncubator::Error: |
311 | return Error; |
312 | default: |
313 | break; |
314 | } |
315 | } |
316 | |
317 | if (m_object) |
318 | return Ready; |
319 | |
320 | return m_source.isEmpty() ? Null : Error; |
321 | } |
322 | |
323 | /*! |
324 | \qmlsignal QtQuick3D::Loader3D::loaded() |
325 | |
326 | This signal is emitted when the \l status becomes \c Loader3D.Ready, or on successful |
327 | initial load. |
328 | |
329 | The corresponding handler is \c onLoaded. |
330 | */ |
331 | |
332 | |
333 | /*! |
334 | \qmlproperty real QtQuick3D::Loader3D::progress |
335 | \readonly |
336 | |
337 | This property holds the progress of loading QML data from the network, from |
338 | 0.0 (nothing loaded) to 1.0 (finished). Most QML files are quite small, so |
339 | this value will rapidly change from 0 to 1. |
340 | |
341 | \sa status |
342 | */ |
343 | |
344 | qreal QQuick3DLoader::progress() const |
345 | { |
346 | |
347 | if (m_object) |
348 | return 1.0; |
349 | |
350 | if (m_component) |
351 | return m_component->progress(); |
352 | |
353 | return 0.0; |
354 | } |
355 | |
356 | /*! |
357 | \qmlproperty bool QtQuick3D::Loader3D::asynchronous |
358 | |
359 | This property holds whether the component will be instantiated asynchronously. |
360 | By default it is \c false. |
361 | |
362 | When used in conjunction with the \l source property, loading and compilation |
363 | will also be performed in a background thread. |
364 | |
365 | Loading asynchronously creates the objects declared by the component |
366 | across multiple frames, and reduces the |
367 | likelihood of glitches in animation. When loading asynchronously the status |
368 | will change to Loader3D.Loading. Once the entire component has been created, the |
369 | \l item will be available and the status will change to Loader.Ready. |
370 | |
371 | Changing the value of this property to \c false while an asynchronous load is in |
372 | progress will force immediate, synchronous completion. This allows beginning an |
373 | asynchronous load and then forcing completion if the Loader3D content must be |
374 | accessed before the asynchronous load has completed. |
375 | |
376 | To avoid seeing the items loading progressively set \c visible appropriately, e.g. |
377 | |
378 | \code |
379 | Loader3D { |
380 | source: "mycomponent.qml" |
381 | asynchronous: true |
382 | visible: status == Loader3D.Ready |
383 | } |
384 | \endcode |
385 | |
386 | Note that this property affects object instantiation only; it is unrelated to |
387 | loading a component asynchronously via a network. |
388 | */ |
389 | |
390 | bool QQuick3DLoader::asynchronous() const |
391 | { |
392 | return m_asynchronous; |
393 | } |
394 | |
395 | void QQuick3DLoader::setAsynchronous(bool a) |
396 | { |
397 | if (m_asynchronous == a) |
398 | return; |
399 | |
400 | m_asynchronous = a; |
401 | |
402 | if (!m_asynchronous && isComponentComplete() && m_active) { |
403 | if (m_loadingFromSource && m_component && m_component->isLoading()) { |
404 | // Force a synchronous component load |
405 | QUrl currentSource = m_source; |
406 | clear(); |
407 | m_source = currentSource; |
408 | loadFromSource(); |
409 | } else if (m_incubator && m_incubator->isLoading()) { |
410 | m_incubator->forceCompletion(); |
411 | } |
412 | } |
413 | |
414 | emit asynchronousChanged(); |
415 | } |
416 | |
417 | /*! |
418 | \qmlproperty object QtQuick3D::Loader3D::item |
419 | \readonly |
420 | This property holds the top-level object that is currently loaded. |
421 | */ |
422 | QObject *QQuick3DLoader::item() const |
423 | { |
424 | return m_object; |
425 | } |
426 | |
427 | void QQuick3DLoader::componentComplete() |
428 | { |
429 | QQuick3DNode::componentComplete(); |
430 | if (active()) { |
431 | if (m_loadingFromSource) |
432 | createComponent(); |
433 | load(); |
434 | } |
435 | } |
436 | |
437 | void QQuick3DLoader::sourceLoaded() |
438 | { |
439 | if (!m_component || !m_component->errors().isEmpty()) { |
440 | if (m_component) |
441 | QQmlEnginePrivate::warning(qmlEngine(this), m_component->errors()); |
442 | if (m_loadingFromSource) |
443 | emit sourceChanged(); |
444 | else |
445 | emit sourceComponentChanged(); |
446 | emit statusChanged(); |
447 | emit progressChanged(); |
448 | emit itemChanged(); //Like clearing source, emit itemChanged even if previous item was also null |
449 | disposeInitialPropertyValues(); // cleanup |
450 | return; |
451 | } |
452 | |
453 | QQmlContext *creationContext = m_component->creationContext(); |
454 | if (!creationContext) creationContext = qmlContext(this); |
455 | m_itemContext = new QQmlContext(creationContext); |
456 | m_itemContext->setContextObject(this); |
457 | |
458 | delete m_incubator; |
459 | m_incubator = new QQuick3DLoaderIncubator(this, m_asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested); |
460 | |
461 | m_component->create(*m_incubator, context: m_itemContext); |
462 | |
463 | if (m_incubator && m_incubator->status() == QQmlIncubator::Loading) |
464 | emit statusChanged(); |
465 | } |
466 | |
467 | void QQuick3DLoader::setSource(const QUrl &sourceUrl, bool needsClear) |
468 | { |
469 | if (m_source == sourceUrl) |
470 | return; |
471 | |
472 | if (needsClear) |
473 | clear(); |
474 | |
475 | m_source = sourceUrl; |
476 | m_loadingFromSource = true; |
477 | |
478 | if (m_active) |
479 | loadFromSource(); |
480 | else |
481 | emit sourceChanged(); |
482 | } |
483 | |
484 | void QQuick3DLoader::loadFromSource() |
485 | { |
486 | if (m_source.isEmpty()) { |
487 | emit sourceChanged(); |
488 | emit statusChanged(); |
489 | emit progressChanged(); |
490 | emit itemChanged(); |
491 | return; |
492 | } |
493 | |
494 | if (isComponentComplete()) { |
495 | if (!m_component) |
496 | createComponent(); |
497 | load(); |
498 | } |
499 | } |
500 | |
501 | void QQuick3DLoader::loadFromSourceComponent() |
502 | { |
503 | if (!m_component) { |
504 | emit sourceComponentChanged(); |
505 | emit statusChanged(); |
506 | emit progressChanged(); |
507 | emit itemChanged(); |
508 | return; |
509 | } |
510 | |
511 | if (isComponentComplete()) |
512 | load(); |
513 | } |
514 | |
515 | void QQuick3DLoader::clear() |
516 | { |
517 | disposeInitialPropertyValues(); |
518 | |
519 | if (m_incubator) |
520 | m_incubator->clear(); |
521 | |
522 | delete m_itemContext; |
523 | m_itemContext = nullptr; |
524 | |
525 | // Prevent any bindings from running while waiting for deletion. Without |
526 | // this we may get transient errors from use of 'parent', for example. |
527 | QQmlContext *context = qmlContext(m_object); |
528 | if (context) |
529 | QQmlContextData::get(context)->clearContextRecursively(); |
530 | |
531 | if (m_loadingFromSource && m_component) { |
532 | // disconnect since we deleteLater |
533 | QObject::disconnect(sender: m_component, SIGNAL(statusChanged(QQmlComponent::Status)), |
534 | receiver: this, SLOT(sourceLoaded())); |
535 | QObject::disconnect(sender: m_component, SIGNAL(progressChanged(qreal)), |
536 | receiver: this, SIGNAL(progressChanged())); |
537 | m_component->deleteLater(); |
538 | m_component.setObject(obj: nullptr, parent: this); |
539 | } else if (m_component) { |
540 | m_component.setObject(obj: nullptr, parent: this); |
541 | } |
542 | m_source = QUrl(); |
543 | |
544 | if (m_item) { |
545 | // We can't delete immediately because our item may have triggered |
546 | // the Loader to load a different item. |
547 | m_item->setParentItem(nullptr); |
548 | m_item->setVisible(false); |
549 | m_item = nullptr; |
550 | } |
551 | if (m_object) { |
552 | m_object->deleteLater(); |
553 | m_object = nullptr; |
554 | } |
555 | } |
556 | |
557 | void QQuick3DLoader::load() |
558 | { |
559 | |
560 | if (!isComponentComplete() || !m_component) |
561 | return; |
562 | |
563 | if (!m_component->isLoading()) { |
564 | sourceLoaded(); |
565 | } else { |
566 | QObject::connect(sender: m_component, SIGNAL(statusChanged(QQmlComponent::Status)), |
567 | receiver: this, SLOT(sourceLoaded())); |
568 | QObject::connect(sender: m_component, SIGNAL(progressChanged(qreal)), |
569 | receiver: this, SIGNAL(progressChanged())); |
570 | emit statusChanged(); |
571 | emit progressChanged(); |
572 | if (m_loadingFromSource) |
573 | emit sourceChanged(); |
574 | else |
575 | emit sourceComponentChanged(); |
576 | emit itemChanged(); |
577 | } |
578 | } |
579 | |
580 | void QQuick3DLoader::incubatorStateChanged(QQmlIncubator::Status status) |
581 | { |
582 | if (status == QQmlIncubator::Loading || status == QQmlIncubator::Null) |
583 | return; |
584 | |
585 | if (status == QQmlIncubator::Ready) { |
586 | m_object = m_incubator->object(); |
587 | m_item = qmlobject_cast<QQuick3DNode*>(object: m_object); |
588 | emit itemChanged(); |
589 | m_incubator->clear(); |
590 | } else if (status == QQmlIncubator::Error) { |
591 | if (!m_incubator->errors().isEmpty()) |
592 | QQmlEnginePrivate::warning(qmlEngine(this), m_incubator->errors()); |
593 | delete m_itemContext; |
594 | m_itemContext = nullptr; |
595 | delete m_incubator->object(); |
596 | m_source = QUrl(); |
597 | emit itemChanged(); |
598 | } |
599 | if (m_loadingFromSource) |
600 | emit sourceChanged(); |
601 | else |
602 | emit sourceComponentChanged(); |
603 | emit statusChanged(); |
604 | emit progressChanged(); |
605 | if (status == QQmlIncubator::Ready) |
606 | emit loaded(); |
607 | disposeInitialPropertyValues(); // cleanup |
608 | } |
609 | |
610 | void QQuick3DLoader::setInitialState(QObject *obj) |
611 | { |
612 | QQuick3DObject *item = qmlobject_cast<QQuick3DObject*>(object: obj); |
613 | if (item) { |
614 | item->setParentItem(this); |
615 | } |
616 | if (obj) { |
617 | QQml_setParent_noEvent(object: m_itemContext, parent: obj); |
618 | QQml_setParent_noEvent(object: obj, parent: this); |
619 | m_itemContext = nullptr; |
620 | } |
621 | |
622 | if (m_initialPropertyValues.isUndefined()) |
623 | return; |
624 | |
625 | QQmlComponentPrivate *d = QQmlComponentPrivate::get(c: m_component); |
626 | Q_ASSERT(d && d->engine); |
627 | QV4::ExecutionEngine *v4 = d->engine->handle(); |
628 | Q_ASSERT(v4); |
629 | QV4::Scope scope(v4); |
630 | QV4::ScopedValue ipv(scope, m_initialPropertyValues.value()); |
631 | QV4::Scoped<QV4::QmlContext> qmlContext(scope, m_qmlCallingContext.value()); |
632 | d->initializeObjectWithInitialProperties(qmlContext, valuemap: ipv, toCreate: obj, requiredProperties: QQmlIncubatorPrivate::get(incubator: m_incubator)->requiredProperties()); |
633 | } |
634 | |
635 | void QQuick3DLoader::disposeInitialPropertyValues() |
636 | { |
637 | |
638 | } |
639 | |
640 | QUrl QQuick3DLoader::resolveSourceUrl(QQmlV4FunctionPtr args) |
641 | { |
642 | QV4::Scope scope(args->v4engine()); |
643 | QV4::ScopedValue v(scope, (*args)[0]); |
644 | QString arg = v->toQString(); |
645 | if (arg.isEmpty()) |
646 | return QUrl(); |
647 | |
648 | auto context = scope.engine->callingQmlContext(); |
649 | Q_ASSERT(!context.isNull()); |
650 | return context->resolvedUrl(QUrl(arg)); |
651 | } |
652 | |
653 | QV4::ReturnedValue QQuick3DLoader::extractInitialPropertyValues(QQmlV4FunctionPtr args, bool *error) |
654 | { |
655 | QV4::Scope scope(args->v4engine()); |
656 | QV4::ScopedValue valuemap(scope, QV4::Encode::undefined()); |
657 | if (args->length() >= 2) { |
658 | QV4::ScopedValue v(scope, (*args)[1]); |
659 | if (!v->isObject() || v->as<QV4::ArrayObject>()) { |
660 | *error = true; |
661 | qmlWarning(me: this) << QQuick3DLoader::tr(s: "setSource: value is not an object"); |
662 | } else { |
663 | *error = false; |
664 | valuemap = v; |
665 | } |
666 | } |
667 | |
668 | return valuemap->asReturnedValue(); |
669 | } |
670 | |
671 | void QQuick3DLoader::createComponent() |
672 | { |
673 | const QQmlComponent::CompilationMode mode = m_asynchronous |
674 | ? QQmlComponent::Asynchronous |
675 | : QQmlComponent::PreferSynchronous; |
676 | QQmlContext *context = qmlContext(this); |
677 | m_component.setObject(obj: new QQmlComponent(context->engine(), |
678 | context->resolvedUrl(m_source), |
679 | mode, |
680 | this), |
681 | parent: this); |
682 | } |
683 | |
684 | QT_END_NAMESPACE |
685 | |
686 | #include "moc_qquick3dloader_p.cpp" |
687 |
Definitions
- statusChanged
- setInitialState
- QQuick3DLoader
- ~QQuick3DLoader
- active
- setActive
- setSource
- source
- setSource
- sourceComponent
- setSourceComponent
- resetSourceComponent
- status
- progress
- asynchronous
- setAsynchronous
- item
- componentComplete
- sourceLoaded
- setSource
- loadFromSource
- loadFromSourceComponent
- clear
- load
- incubatorStateChanged
- setInitialState
- disposeInitialPropertyValues
- resolveSourceUrl
- extractInitialPropertyValues
Learn Advanced QML with KDAB
Find out more