Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickstategroup.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
7
8#include <private/qqmlbinding_p.h>
9#include <private/qqmlglobal_p.h>
10
11#include <QtCore/qstringlist.h>
12#include <QtCore/qdebug.h>
13#include <QtCore/qvector.h>
14
15#include <private/qobject_p.h>
16#include <qqmlinfo.h>
17
19
20using namespace Qt::StringLiterals;
21
23{
24 Q_DECLARE_PUBLIC(QQuickStateGroup)
25public:
29
32
33 static void append_state(QQmlListProperty<QQuickState> *list, QQuickState *state);
34 static qsizetype count_state(QQmlListProperty<QQuickState> *list);
35 static QQuickState *at_state(QQmlListProperty<QQuickState> *list, qsizetype index);
36 static void clear_states(QQmlListProperty<QQuickState> *list);
37 static void replace_states(QQmlListProperty<QQuickState> *list, qsizetype index, QQuickState *state);
38 static void removeLast_states(QQmlListProperty<QQuickState> *list);
39
40 static void append_transition(QQmlListProperty<QQuickTransition> *list, QQuickTransition *state);
41 static qsizetype count_transitions(QQmlListProperty<QQuickTransition> *list);
42 static QQuickTransition *at_transition(QQmlListProperty<QQuickTransition> *list, qsizetype index);
43 static void clear_transitions(QQmlListProperty<QQuickTransition> *list);
44
45 QList<QQuickState *> states;
46 QList<QQuickTransition *> transitions;
47
52
53 QQuickTransition *findTransition(const QString &from, const QString &to);
54 void setCurrentStateInternal(const QString &state, bool = false);
55 bool updateAutoState();
56};
57
93
95{
96 Q_D(const QQuickStateGroup);
97 for (QQuickState *state : std::as_const(d->states)) {
98 if (state)
99 state->setStateGroup(nullptr);
100 }
101 if (d->nullState)
102 d->nullState->setStateGroup(nullptr);
103}
104
105QList<QQuickState *> QQuickStateGroup::states() const
106{
107 Q_D(const QQuickStateGroup);
108 return d->states;
109}
110
142
143void QQuickStateGroupPrivate::append_state(QQmlListProperty<QQuickState> *list, QQuickState *state)
144{
145 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
146 _this->d_func()->states.append(state);
147 if (state)
148 state->setStateGroup(_this);
149}
150
152{
153 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
154 return _this->d_func()->states.size();
155}
156
158{
159 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
160 return _this->d_func()->states.at(index);
161}
162
163void QQuickStateGroupPrivate::clear_states(QQmlListProperty<QQuickState> *list)
164{
165 QQuickStateGroupPrivate *d = static_cast<QQuickStateGroup *>(list->object)->d_func();
166 d->setCurrentStateInternal(QString(), true);
167 for (QQuickState *state : std::as_const(d->states)) {
168 if (state)
169 state->setStateGroup(nullptr);
170 }
171 d->states.clear();
172}
173
175{
176 auto *self = static_cast<QQuickStateGroup *>(list->object);
177 auto *d = self->d_func();
178 auto *oldState = d->states.at(index);
179 if (oldState != state) {
180 if (oldState)
181 oldState->setStateGroup(nullptr);
182
183 if (state)
184 state->setStateGroup(self);
185 d->states.replace(index, state);
186 if (!oldState || d->currentState == oldState->name())
187 d->setCurrentStateInternal(state ? state->name() : QString(), true);
188 }
189}
190
191void QQuickStateGroupPrivate::removeLast_states(QQmlListProperty<QQuickState> *list)
192{
193 auto *d = static_cast<QQuickStateGroup *>(list->object)->d_func();
194 if (QQuickState *last = d->states.last()) {
195 if (d->currentState == last->name()) {
196 QQuickState *first = d->states.size() > 1 ? d->states.first() : nullptr;
197 d->setCurrentStateInternal(first ? first->name() : QString(), true);
198 }
199 last->setStateGroup(nullptr);
200 }
201 d->states.removeLast();
202}
203
224QQmlListProperty<QQuickTransition> QQuickStateGroup::transitionsProperty()
225{
226 Q_D(QQuickStateGroup);
227 return QQmlListProperty<QQuickTransition>(this, &d->transitions, &QQuickStateGroupPrivate::append_transition,
231}
232
233void QQuickStateGroupPrivate::append_transition(QQmlListProperty<QQuickTransition> *list, QQuickTransition *trans)
234{
235 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
236 if (trans)
237 _this->d_func()->transitions.append(trans);
238}
239
241{
242 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
243 return _this->d_func()->transitions.size();
244}
245
247{
248 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
249 return _this->d_func()->transitions.at(index);
250}
251
252void QQuickStateGroupPrivate::clear_transitions(QQmlListProperty<QQuickTransition> *list)
253{
254 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
255 _this->d_func()->transitions.clear();
256}
257
282{
283 Q_D(const QQuickStateGroup);
284 return d->currentState;
285}
286
288{
289 Q_D(QQuickStateGroup);
290 if (d->currentState == state)
291 return;
292
293 d->setCurrentStateInternal(state);
294}
295
297{
298 Q_D(QQuickStateGroup);
299 d->componentComplete = false;
300}
301
303{
304 Q_D(QQuickStateGroup);
305 d->componentComplete = true;
306
307 QVarLengthArray<QString, 4> names;
308 names.reserve(d->states.size());
309 for (QQuickState *state : std::as_const(d->states)) {
310 if (!state)
311 continue;
312
313 if (!state->isNamed())
314 state->setName(QLatin1String("anonymousState") + QString::number(++d->unnamedCount));
315
316 QString stateName = state->name();
317 if (names.contains(stateName))
318 qmlWarning(state->parent()) << "Found duplicate state name: " << stateName;
319 else
320 names.append(std::move(stateName));
321 }
322
323 if (d->updateAutoState()) {
324 return;
325 } else if (!d->currentState.isEmpty()) {
326 QString cs = d->currentState;
327 d->currentState.clear();
328 d->setCurrentStateInternal(cs, true);
329 }
330}
331
335bool QQuickStateGroup::updateAutoState()
336{
337 Q_D(QQuickStateGroup);
338 return d->updateAutoState();
339}
340
342{
343 Q_Q(QQuickStateGroup);
345 return false;
346
347 bool revert = false;
348 for (QQuickState *state : std::as_const(states)) {
349 if (!state || !state->isWhenKnown() || !state->isNamed())
350 continue;
351
352 bool whenValue = state->when();
353 const QQmlPropertyIndex whenIndex(state->metaObject()->indexOfProperty("when"));
354 const auto potentialWhenBinding = QQmlAnyBinding::ofProperty(state, whenIndex);
355 Q_ASSERT(!potentialWhenBinding.isUntypedPropertyBinding());
356
357 // if there is a binding, the value in when might not be up-to-date at this point
358 // so we manually re-evaluate the binding
359 QQmlAbstractBinding *abstractBinding = potentialWhenBinding.asAbstractBinding();
360 if (abstractBinding && abstractBinding->kind() == QQmlAbstractBinding::QmlBinding) {
361 QQmlBinding *binding = static_cast<QQmlBinding *>(abstractBinding);
362 if (binding->hasValidContext()) {
363 const auto boolType = QMetaType::fromType<bool>();
364 const bool isUndefined = !binding->evaluate(&whenValue, boolType);
365 if (isUndefined)
366 whenValue = false;
367 }
368 }
369
370 if (whenValue) {
371 qCDebug(lcStates) << "Setting auto state due to expression";
372 if (currentState != state->name()) {
373 q->setState(state->name());
374 return true;
375 } else {
376 return false;
377 }
378 } else if (state->name() == currentState) {
379 revert = true;
380 }
381 }
382 if (revert) {
383 bool rv = !currentState.isEmpty();
384 q->setState(QString());
385 return rv;
386 } else {
387 return false;
388 }
389}
390
392{
393 QQuickTransition *highest = nullptr;
394 int score = 0;
395 bool reversed = false;
396 bool done = false;
397
398 for (int ii = 0; !done && ii < transitions.size(); ++ii) {
400 if (!t->enabled())
401 continue;
402 for (int ii = 0; ii < 2; ++ii)
403 {
404 if (ii && (!t->reversible() ||
405 (t->fromState() == QLatin1String("*") &&
406 t->toState() == QLatin1String("*"))))
407 break;
408 const QString fromStateStr = t->fromState();
409 const QString toStateStr = t->toState();
410
411 auto fromState = QStringView{fromStateStr}.split(QLatin1Char(','));
412 for (int jj = 0; jj < fromState.size(); ++jj)
413 fromState[jj] = fromState.at(jj).trimmed();
414 auto toState = QStringView{toStateStr}.split(QLatin1Char(','));
415 for (int jj = 0; jj < toState.size(); ++jj)
416 toState[jj] = toState.at(jj).trimmed();
417 if (ii == 1)
418 qSwap(fromState, toState);
419 int tScore = 0;
420 const QString asterisk = QStringLiteral("*");
421 if (fromState.contains(QStringView(from)))
422 tScore += 2;
423 else if (fromState.contains(QStringView(asterisk)))
424 tScore += 1;
425 else
426 continue;
427
428 if (toState.contains(QStringView(to)))
429 tScore += 2;
430 else if (toState.contains(QStringView(asterisk)))
431 tScore += 1;
432 else
433 continue;
434
435 if (ii == 1)
436 reversed = true;
437 else
438 reversed = false;
439
440 if (tScore == 4) {
441 highest = t;
442 done = true;
443 break;
444 } else if (tScore > score) {
445 score = tScore;
446 highest = t;
447 }
448 }
449 }
450
451 if (highest)
452 highest->setReversed(reversed);
453
454 return highest;
455}
456
458 bool ignoreTrans)
459{
460 Q_Q(QQuickStateGroup);
461 if (!componentComplete) {
463 return;
464 }
465
466 if (applyingState) {
467 qmlWarning(q) << "Can't apply a state change as part of a state definition.";
468 return;
469 }
470
471 applyingState = true;
472
474 if (lcStates().isDebugEnabled()) {
475 qCDebug(lcStates) << this << "changing state from:" << currentState << "to:" << state;
476 if (transition)
477 qCDebug(lcStates) << " using transition" << transition->fromState()
478 << transition->toState();
479 }
480
481 QQuickState *oldState = nullptr;
482 if (!currentState.isEmpty()) {
483 for (QQuickState *state : std::as_const(states)) {
484 if (state && state->name() == currentState) {
485 oldState = state;
486 break;
487 }
488 }
489 }
490
492 emit q->stateChanged(currentState);
493
494 QQuickState *newState = nullptr;
495 for (QQuickState *state : std::as_const(states)) {
496 if (state && state->name() == currentState) {
497 newState = state;
498 break;
499 }
500 }
501
502 if (oldState == nullptr || newState == nullptr) {
503 if (!nullState) {
507 }
508 if (!oldState) oldState = nullState;
510 }
511
512 newState->apply(transition, oldState);
513 applyingState = false; //### consider removing this (don't allow state changes in transition)
514}
515
517{
518 Q_D(const QQuickStateGroup);
519 for (QQuickState *state : std::as_const(d->states)) {
520 if (state && state->name() == name)
521 return state;
522 }
523
524 return nullptr;
525}
526
528{
529 Q_D(QQuickStateGroup);
530 d->states.removeOne(state);
531}
532
533void QQuickStateGroup::stateAboutToComplete()
534{
535 Q_D(QQuickStateGroup);
536 d->applyingState = false;
537}
538
540
541
542#include "moc_qquickstategroup_p.cpp"
qsizetype size() const noexcept
Definition qlist.h:398
const_reference at(qsizetype i) const noexcept
Definition qlist.h:447
\inmodule QtCore
Definition qobject.h:103
static QQmlAnyBinding ofProperty(const QQmlProperty &prop)
QVariant evaluate()
static qsizetype count_transitions(QQmlListProperty< QQuickTransition > *list)
QList< QQuickTransition * > transitions
static void clear_states(QQmlListProperty< QQuickState > *list)
static void replace_states(QQmlListProperty< QQuickState > *list, qsizetype index, QQuickState *state)
static void removeLast_states(QQmlListProperty< QQuickState > *list)
void setCurrentStateInternal(const QString &state, bool=false)
static QQuickTransition * at_transition(QQmlListProperty< QQuickTransition > *list, qsizetype index)
static QQuickState * at_state(QQmlListProperty< QQuickState > *list, qsizetype index)
static void clear_transitions(QQmlListProperty< QQuickTransition > *list)
static void append_transition(QQmlListProperty< QQuickTransition > *list, QQuickTransition *state)
QQuickTransition * findTransition(const QString &from, const QString &to)
static qsizetype count_state(QQmlListProperty< QQuickState > *list)
static void append_state(QQmlListProperty< QQuickState > *list, QQuickState *state)
QList< QQuickState * > states
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void removeState(QQuickState *state)
QQmlListProperty< QQuickTransition > transitionsProperty()
\qmlproperty list<Transition> QtQuick::StateGroup::transitions This property holds a list of transiti...
QQuickStateGroup(QObject *=nullptr)
\qmltype StateGroup \instantiates QQuickStateGroup \inqmlmodule QtQuick
QQuickState * findState(const QString &name) const
QQmlListProperty< QQuickState > states
void setState(const QString &)
QQmlListProperty< QQuickState > statesProperty()
\qmlproperty list<State> QtQuick::StateGroup::states This property holds a list of states defined by ...
void classBegin() override
Invoked after class creation, but before any properties have been set.
QQmlListProperty< QQuickTransition > transitions
void apply(QQuickTransition *, QQuickState *revert)
void setStateGroup(QQuickStateGroup *)
QString fromState() const
\qmlproperty string QtQuick::Transition::from \qmlproperty string QtQuick::Transition::to
QString toState() const
\inmodule QtCore
Definition qstringview.h:78
Q_CORE_EXPORT QList< QStringView > split(QStringView sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the view into substring views wherever sep occurs, and returns the list of those string views.
Definition qstring.cpp:8260
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8095
QString & append(QChar c)
Definition qstring.cpp:3254
else opt state
[0]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
Combined button and popup list for selecting options.
#define qCDebug(category,...)
GLuint index
[2]
GLuint name
GLint first
GLuint GLuint * names
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint * states
void QQml_setParent_noEvent(QObject *object, QObject *parent)
Makes the object a child of parent.
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
Definition qswap.h:20
#define emit
ptrdiff_t qsizetype
Definition qtypes.h:165
QList< int > list
[14]
QObject::connect nullptr
\inmodule QtCore \reentrant
Definition qchar.h:18