aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicktemplates/qquickstackview_p.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quicktemplates/qquickstackview_p.cpp')
-rw-r--r--src/quicktemplates/qquickstackview_p.cpp123
1 files changed, 121 insertions, 2 deletions
diff --git a/src/quicktemplates/qquickstackview_p.cpp b/src/quicktemplates/qquickstackview_p.cpp
index 99127d84b6..0288ff1f4b 100644
--- a/src/quicktemplates/qquickstackview_p.cpp
+++ b/src/quicktemplates/qquickstackview_p.cpp
@@ -3,8 +3,11 @@
#include "qquickstackview_p_p.h"
#include "qquickstackelement_p_p.h"
+#if QT_CONFIG(quick_viewtransitions)
#include "qquickstacktransition_p_p.h"
+#endif
+#include <QtCore/qscopedvaluerollback.h>
#include <QtQml/qqmlinfo.h>
#include <QtQml/qqmllist.h>
#include <QtQml/private/qv4qmlcontext_p.h>
@@ -46,7 +49,7 @@ void QQuickStackViewPrivate::setCurrentItem(QQuickStackElement *element)
emit q->currentItemChanged();
}
-static bool initProperties(QQuickStackElement *element, const QV4::Value &props, QQmlV4Function *args)
+static bool initProperties(QQuickStackElement *element, const QV4::Value &props, QQmlV4FunctionPtr args)
{
if (props.isObject()) {
const QV4::QObjectWrapper *wrapper = props.as<QV4::QObjectWrapper>();
@@ -60,7 +63,7 @@ static bool initProperties(QQuickStackElement *element, const QV4::Value &props,
return false;
}
-QList<QQuickStackElement *> QQuickStackViewPrivate::parseElements(int from, QQmlV4Function *args, QStringList *errors)
+QList<QQuickStackElement *> QQuickStackViewPrivate::parseElements(int from, QQmlV4FunctionPtr args, QStringList *errors)
{
QV4::ExecutionEngine *v4 = args->v4engine();
auto context = v4->callingQmlContext();
@@ -106,6 +109,47 @@ QList<QQuickStackElement *> QQuickStackViewPrivate::parseElements(int from, QQml
return elements;
}
+QList<QQuickStackElement *> QQuickStackViewPrivate::parseElements(const QList<QQuickStackViewArg> &args)
+{
+ Q_Q(QQuickStackView);
+ QList<QQuickStackElement *> stackElements;
+ for (int i = 0; i < args.size(); ++i) {
+ const QQuickStackViewArg &arg = args.at(i);
+ QVariantMap properties;
+ // Look ahead at the next arg in case it contains properties for this
+ // Item/Component/URL.
+ if (i < args.size() - 1) {
+ const QQuickStackViewArg &nextArg = args.at(i + 1);
+ // If mProperties isn't empty, the user passed properties.
+ // If it is empty, but mItem, mComponent and mUrl also are,
+ // then they passed an empty property map.
+ if (!nextArg.mProperties.isEmpty()
+ || (!nextArg.mItem && !nextArg.mComponent && !nextArg.mUrl.isValid())) {
+ properties = nextArg.mProperties;
+ ++i;
+ }
+ }
+
+ // Remove any items that are already in the stack, as they can't be in two places at once.
+ if (findElement(arg.mItem))
+ continue;
+
+ // We look ahead one index for each Item/Component/URL, so if this arg is
+ // a property map, the user has passed two or more in a row.
+ if (!arg.mProperties.isEmpty()) {
+ qmlWarning(q) << "Properties must come after an Item, Component or URL";
+ return {};
+ }
+
+ QQuickStackElement *element = QQuickStackElement::fromStackViewArg(q, arg);
+ QV4::ExecutionEngine *v4Engine = qmlEngine(q)->handle();
+ element->properties.set(v4Engine, v4Engine->fromVariant(properties));
+ element->qmlCallingContext.set(v4Engine, v4Engine->qmlContext());
+ stackElements.append(element);
+ }
+ return stackElements;
+}
+
QQuickStackElement *QQuickStackViewPrivate::findElement(QQuickItem *item) const
{
if (item) {
@@ -204,6 +248,80 @@ bool QQuickStackViewPrivate::replaceElements(QQuickStackElement *target, const Q
return pushElements(elems);
}
+QQuickItem *QQuickStackViewPrivate::popToItem(QQuickItem *item, QQuickStackView::Operation operation, CurrentItemPolicy currentItemPolicy)
+{
+ const QString operationName = QStringLiteral("pop");
+ if (modifyingElements) {
+ warnOfInterruption(operationName);
+ return nullptr;
+ }
+
+ QScopedValueRollback<bool> modifyingElementsRollback(modifyingElements, true);
+ QScopedValueRollback<QString> operationNameRollback(this->operation, operationName);
+ if (elements.isEmpty()) {
+ warn(QStringLiteral("no items to pop"));
+ return nullptr;
+ }
+
+ if (!item) {
+ warn(QStringLiteral("item cannot be null"));
+ return nullptr;
+ }
+
+ const int oldDepth = elements.size();
+ QQuickStackElement *exit = elements.pop();
+ // top() here will be the item below the previously current item, since we just popped above.
+ QQuickStackElement *enter = elements.top();
+
+ bool nothingToDo = false;
+ if (item != currentItem) {
+ if (!item) {
+ // Popping down to the first item.
+ enter = elements.value(0);
+ } else {
+ // Popping down to an arbitrary item.
+ enter = findElement(item);
+ if (!enter) {
+ warn(QStringLiteral("can't find item to pop: ") + QDebug::toString(item));
+ nothingToDo = true;
+ }
+ }
+ } else {
+ if (currentItemPolicy == CurrentItemPolicy::DoNotPop) {
+ // popToItem was called with the currentItem, which means there are no items
+ // to pop because it's already at the top.
+ nothingToDo = true;
+ }
+ // else: popToItem was called by popCurrentItem, and so we _should_ pop.
+ }
+ if (nothingToDo) {
+ // Restore the element we popped earlier.
+ elements.push(exit);
+ return nullptr;
+ }
+
+ QQuickItem *previousItem = nullptr;
+ if (popElements(enter)) {
+ if (exit) {
+ exit->removal = true;
+ removing.insert(exit);
+ previousItem = exit->item;
+ }
+ depthChange(elements.size(), oldDepth);
+#if QT_CONFIG(quick_viewtransitions)
+ Q_Q(QQuickStackView);
+ startTransition(QQuickStackTransition::popExit(operation, exit, q),
+ QQuickStackTransition::popEnter(operation, enter, q),
+ operation == QQuickStackView::Immediate);
+#else
+ Q_UNUSED(operation);
+#endif
+ setCurrentItem(enter);
+ }
+ return previousItem;
+}
+
+#if QT_CONFIG(quick_viewtransitions)
void QQuickStackViewPrivate::ensureTransitioner()
{
if (!transitioner) {
@@ -301,6 +419,7 @@ void QQuickStackViewPrivate::viewItemTransitionFinished(QQuickItemViewTransition
removing.remove(element);
}
+#endif
void QQuickStackViewPrivate::setBusy(bool b)
{