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
25{
26 Q_DECLARE_PUBLIC(QQuickStateGroup)
27public:
29 : nullState(nullptr), componentComplete(true),
30 ignoreTrans(false), applyingState(false), unnamedCount(0) {}
31
34
35 static void append_state(QQmlListProperty<QQuickState> *list, QQuickState *state);
36 static qsizetype count_state(QQmlListProperty<QQuickState> *list);
37 static QQuickState *at_state(QQmlListProperty<QQuickState> *list, qsizetype index);
38 static void clear_states(QQmlListProperty<QQuickState> *list);
39 static void replace_states(QQmlListProperty<QQuickState> *list, qsizetype index, QQuickState *state);
40 static void removeLast_states(QQmlListProperty<QQuickState> *list);
41
42 static void append_transition(QQmlListProperty<QQuickTransition> *list, QQuickTransition *state);
43 static qsizetype count_transitions(QQmlListProperty<QQuickTransition> *list);
44 static QQuickTransition *at_transition(QQmlListProperty<QQuickTransition> *list, qsizetype index);
45 static void clear_transitions(QQmlListProperty<QQuickTransition> *list);
46
47 QList<QQuickState *> states;
48 QList<QQuickTransition *> transitions;
49
54
55 QQuickTransition *findTransition(const QString &from, const QString &to);
56 void setCurrentStateInternal(const QString &state, bool = false);
57 bool updateAutoState();
58};
59
95
97{
98 Q_D(const QQuickStateGroup);
99 for (QQuickState *state : std::as_const(d->states)) {
100 if (state)
101 state->setStateGroup(nullptr);
102 }
103 if (d->nullState)
104 d->nullState->setStateGroup(nullptr);
105}
106
107QList<QQuickState *> QQuickStateGroup::states() const
108{
109 Q_D(const QQuickStateGroup);
110 return d->states;
111}
112
144
145void QQuickStateGroupPrivate::append_state(QQmlListProperty<QQuickState> *list, QQuickState *state)
146{
147 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
148 _this->d_func()->states.append(state);
149 if (state)
150 state->setStateGroup(_this);
151}
152
154{
155 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
156 return _this->d_func()->states.size();
157}
158
160{
161 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
162 return _this->d_func()->states.at(index);
163}
164
165void QQuickStateGroupPrivate::clear_states(QQmlListProperty<QQuickState> *list)
166{
167 QQuickStateGroupPrivate *d = static_cast<QQuickStateGroup *>(list->object)->d_func();
168 d->setCurrentStateInternal(QString(), true);
169 for (QQuickState *state : std::as_const(d->states)) {
170 if (state)
171 state->setStateGroup(nullptr);
172 }
173 d->states.clear();
174}
175
177{
178 auto *self = static_cast<QQuickStateGroup *>(list->object);
179 auto *d = self->d_func();
180 auto *oldState = d->states.at(index);
181 if (oldState != state) {
182 if (oldState)
183 oldState->setStateGroup(nullptr);
184
185 if (state)
186 state->setStateGroup(self);
187 d->states.replace(index, state);
188 if (!oldState || d->currentState == oldState->name())
189 d->setCurrentStateInternal(state ? state->name() : QString(), true);
190 }
191}
192
193void QQuickStateGroupPrivate::removeLast_states(QQmlListProperty<QQuickState> *list)
194{
195 auto *d = static_cast<QQuickStateGroup *>(list->object)->d_func();
196 if (QQuickState *last = d->states.last()) {
197 if (d->currentState == last->name()) {
198 QQuickState *first = d->states.size() > 1 ? d->states.first() : nullptr;
199 d->setCurrentStateInternal(first ? first->name() : QString(), true);
200 }
201 last->setStateGroup(nullptr);
202 }
203 d->states.removeLast();
204}
205
226QQmlListProperty<QQuickTransition> QQuickStateGroup::transitionsProperty()
227{
228 Q_D(QQuickStateGroup);
229 return QQmlListProperty<QQuickTransition>(this, &d->transitions, &QQuickStateGroupPrivate::append_transition,
233}
234
235void QQuickStateGroupPrivate::append_transition(QQmlListProperty<QQuickTransition> *list, QQuickTransition *trans)
236{
237 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
238 if (trans)
239 _this->d_func()->transitions.append(trans);
240}
241
243{
244 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
245 return _this->d_func()->transitions.size();
246}
247
249{
250 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
251 return _this->d_func()->transitions.at(index);
252}
253
254void QQuickStateGroupPrivate::clear_transitions(QQmlListProperty<QQuickTransition> *list)
255{
256 QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
257 _this->d_func()->transitions.clear();
258}
259
284{
285 Q_D(const QQuickStateGroup);
286 return d->currentState;
287}
288
290{
291 Q_D(QQuickStateGroup);
292 if (d->currentState == state)
293 return;
294
295 d->setCurrentStateInternal(state);
296}
297
299{
300 Q_D(QQuickStateGroup);
301 d->componentComplete = false;
302}
303
305{
306 Q_D(QQuickStateGroup);
307 d->componentComplete = true;
308
309 QVarLengthArray<QString, 4> names;
310 names.reserve(d->states.size());
311 for (QQuickState *state : std::as_const(d->states)) {
312 if (!state)
313 continue;
314
315 if (!state->isNamed())
316 state->setName(QLatin1String("anonymousState") + QString::number(++d->unnamedCount));
317
318 QString stateName = state->name();
319 if (names.contains(stateName))
320 qmlWarning(state->parent()) << "Found duplicate state name: " << stateName;
321 else
322 names.append(std::move(stateName));
323 }
324
325 if (d->updateAutoState()) {
326 return;
327 } else if (!d->currentState.isEmpty()) {
328 QString cs = d->currentState;
329 d->currentState.clear();
330 d->setCurrentStateInternal(cs, true);
331 }
332}
333
337bool QQuickStateGroup::updateAutoState()
338{
339 Q_D(QQuickStateGroup);
340 return d->updateAutoState();
341}
342
344{
345 Q_Q(QQuickStateGroup);
347 return false;
348
349 bool revert = false;
350 for (QQuickState *state : std::as_const(states)) {
351 if (!state || !state->isWhenKnown() || !state->isNamed())
352 continue;
353
354 bool whenValue = state->when();
355 const QQmlPropertyIndex whenIndex(state->metaObject()->indexOfProperty("when"));
356 const auto potentialWhenBinding = QQmlAnyBinding::ofProperty(state, whenIndex);
357 Q_ASSERT(!potentialWhenBinding.isUntypedPropertyBinding());
358
359 // if there is a binding, the value in when might not be up-to-date at this point
360 // so we manually re-evaluate the binding
361 QQmlAbstractBinding *abstractBinding = potentialWhenBinding.asAbstractBinding();
362 if (abstractBinding && abstractBinding->kind() == QQmlAbstractBinding::QmlBinding) {
363 QQmlBinding *binding = static_cast<QQmlBinding *>(abstractBinding);
364 if (binding->hasValidContext()) {
365 const auto boolType = QMetaType::fromType<bool>();
366 const bool isUndefined = !binding->evaluate(&whenValue, boolType);
367 if (isUndefined)
368 whenValue = false;
369 }
370 }
371
372 if (whenValue) {
373 qCDebug(lcStates) << "Setting auto state due to expression";
374 if (currentState != state->name()) {
375 q->setState(state->name());
376 return true;
377 } else {
378 return false;
379 }
380 } else if (state->name() == currentState) {
381 revert = true;
382 }
383 }
384 if (revert) {
385 bool rv = !currentState.isEmpty();
386 q->setState(QString());
387 return rv;
388 } else {
389 return false;
390 }
391}
392
394{
395 QQuickTransition *highest = nullptr;
396 int score = 0;
397 bool reversed = false;
398 bool done = false;
399
400 for (int ii = 0; !done && ii < transitions.size(); ++ii) {
402 if (!t->enabled())
403 continue;
404 for (int ii = 0; ii < 2; ++ii)
405 {
406 if (ii && (!t->reversible() ||
407 (t->fromState() == QLatin1String("*") &&
408 t->toState() == QLatin1String("*"))))
409 break;
410 const QString fromStateStr = t->fromState();
411 const QString toStateStr = t->toState();
412
413 auto fromState = QStringView{fromStateStr}.split(QLatin1Char(','));
414 for (int jj = 0; jj < fromState.size(); ++jj)
415 fromState[jj] = fromState.at(jj).trimmed();
416 auto toState = QStringView{toStateStr}.split(QLatin1Char(','));
417 for (int jj = 0; jj < toState.size(); ++jj)
418 toState[jj] = toState.at(jj).trimmed();
419 if (ii == 1)
420 qSwap(fromState, toState);
421 int tScore = 0;
422 const QString asterisk = QStringLiteral("*");
423 if (fromState.contains(QStringView(from)))
424 tScore += 2;
425 else if (fromState.contains(QStringView(asterisk)))
426 tScore += 1;
427 else
428 continue;
429
430 if (toState.contains(QStringView(to)))
431 tScore += 2;
432 else if (toState.contains(QStringView(asterisk)))
433 tScore += 1;
434 else
435 continue;
436
437 if (ii == 1)
438 reversed = true;
439 else
440 reversed = false;
441
442 if (tScore == 4) {
443 highest = t;
444 done = true;
445 break;
446 } else if (tScore > score) {
447 score = tScore;
448 highest = t;
449 }
450 }
451 }
452
453 if (highest)
454 highest->setReversed(reversed);
455
456 return highest;
457}
458
460 bool ignoreTrans)
461{
462 Q_Q(QQuickStateGroup);
463 if (!componentComplete) {
465 return;
466 }
467
468 if (applyingState) {
469 qmlWarning(q) << "Can't apply a state change as part of a state definition.";
470 return;
471 }
472
473 applyingState = true;
474
476 if (lcStates().isDebugEnabled()) {
477 qCDebug(lcStates) << this << "changing state from:" << currentState << "to:" << state;
478 if (transition)
479 qCDebug(lcStates) << " using transition" << transition->fromState()
480 << transition->toState();
481 }
482
483 QQuickState *oldState = nullptr;
484 if (!currentState.isEmpty()) {
485 for (QQuickState *state : std::as_const(states)) {
486 if (state && state->name() == currentState) {
487 oldState = state;
488 break;
489 }
490 }
491 }
492
494 emit q->stateChanged(currentState);
495
496 QQuickState *newState = nullptr;
497 for (QQuickState *state : std::as_const(states)) {
498 if (state && state->name() == currentState) {
499 newState = state;
500 break;
501 }
502 }
503
504 if (oldState == nullptr || newState == nullptr) {
505 if (!nullState) {
509 }
510 if (!oldState) oldState = nullState;
512 }
513
514 newState->apply(transition, oldState);
515 applyingState = false; //### consider removing this (don't allow state changes in transition)
516}
517
519{
520 Q_D(const QQuickStateGroup);
521 for (QQuickState *state : std::as_const(d->states)) {
522 if (state && state->name() == name)
523 return state;
524 }
525
526 return nullptr;
527}
528
530{
531 Q_D(QQuickStateGroup);
532 d->states.removeOne(state);
533}
534
535void QQuickStateGroup::stateAboutToComplete()
536{
537 Q_D(QQuickStateGroup);
538 d->applyingState = false;
539}
540
542
543
544#include "moc_qquickstategroup_p.cpp"
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
\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:8249
\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:8084
QString & append(QChar c)
Definition qstring.cpp:3252
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,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
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