diff options
author | Adriano Rezende <adriano.1.rezende@nokia.com> | 2012-06-18 16:33:50 +0200 |
---|---|---|
committer | Jens Bache-Wiig <jens.bache-wiig@nokia.com> | 2012-06-29 15:12:58 +0200 |
commit | 84ad688dabbcde68e6b03f6859f9a89d72dc8faf (patch) | |
tree | 61f3942902970de2b299330ad8b8f4d27c80591f | |
parent | 14609c9fea9610a274cbe9814205c39991e6d7ba (diff) | |
download | qtquickcontrols-84ad688dabbcde68e6b03f6859f9a89d72dc8faf.tar.gz |
Add RowLayout and ColumnLayout components
These components provides a more powerful layout features necessary
for desktop applications.
Change-Id: Id41fc7dedeac46128775c56cc0c1d18515b67d54
Reviewed-by: Jens Bache-Wiig <jens.bache-wiig@nokia.com>
-rw-r--r-- | examples/Layout.qml | 456 | ||||
-rw-r--r-- | src/qquicklayout.cpp | 195 | ||||
-rw-r--r-- | src/qquicklayout.h | 128 | ||||
-rw-r--r-- | src/qquicklayoutengine.cpp | 290 | ||||
-rw-r--r-- | src/qquicklayoutengine_p.h | 83 | ||||
-rw-r--r-- | src/qquicklinearlayout.cpp | 232 | ||||
-rw-r--r-- | src/qquicklinearlayout.h | 110 | ||||
-rw-r--r-- | src/qstyleplugin.cpp | 6 | ||||
-rw-r--r-- | src/src.pro | 10 |
9 files changed, 1508 insertions, 2 deletions
diff --git a/examples/Layout.qml b/examples/Layout.qml new file mode 100644 index 00000000..d88eca87 --- /dev/null +++ b/examples/Layout.qml @@ -0,0 +1,456 @@ +import QtQuick 2.0 +import QtDesktop 0.2 + +Item { + width: 600 + height: 400 + + property real defaultWidth: 30 + property real defaultHeight: 30 + + TabFrame { + id:frame + anchors.fill: parent + + Tab { + title: "Horizontal" + + Column { + spacing: 4 + + anchors { + top: parent.top + left: parent.left + right: parent.right + margins: 10 + } + + // [1] + RowLayout { + height: defaultHeight + anchors.left: parent.left + anchors.right: parent.right + + Rectangle { + color: "red" + height: parent.height + } + Rectangle { + color: "green" + height: parent.height + } + Rectangle { + color: "blue" + height: parent.height + } + } + + // [2] + RowLayout { + height: defaultHeight + anchors.left: parent.left + anchors.right: parent.right + + spacing: 5 + + Rectangle { + color: "red" + height: parent.height + } + Rectangle { + color: "green" + height: parent.height + } + Item { + implicitWidth: 10 + } + Rectangle { + color: "blue" + height: parent.height + } + } + + // [3] + RowLayout { + height: defaultHeight + anchors.left: parent.left + anchors.right: parent.right + + Rectangle { + color: "red" + height: parent.height + Layout.minimumWidth: 50 + Layout.maximumWidth: 100 + Layout.horizontalSizePolicy: Layout.Expanding + } + Rectangle { + color: "green" + height: parent.height + Layout.minimumWidth: 100 + Layout.maximumWidth: 200 + Layout.horizontalSizePolicy: Layout.Expanding + } + Rectangle { + color: "blue" + height: parent.height + Layout.minimumWidth: 200 + Layout.maximumWidth: 400 + Layout.horizontalSizePolicy: Layout.Expanding + } + } + + // [4] + RowLayout { + spacing: 100 + height: defaultHeight + anchors.left: parent.left + anchors.right: parent.right + + Rectangle { + color: "red" + height: parent.height + Layout.minimumWidth: 100 + Layout.horizontalSizePolicy: Layout.Expanding + } + Rectangle { + color: "green" + height: parent.height + Layout.minimumWidth: 200 + Layout.horizontalSizePolicy: Layout.Expanding + } + Rectangle { + color: "blue" + height: parent.height + Layout.minimumWidth: 300 + Layout.horizontalSizePolicy: Layout.Expanding + } + } + + // [5] + RowLayout { + height: defaultHeight + anchors.left: parent.left + anchors.right: parent.right + + Rectangle { + color: "red" + height: parent.height + Layout.minimumWidth: 200 + Layout.maximumWidth: 500 + Layout.horizontalSizePolicy: Layout.Expanding + } + } + + // [6] + RowLayout { + spacing: 40 + height: defaultHeight + anchors.left: parent.left + anchors.right: parent.right + + RowLayout { + spacing: 10 + height: parent.height + + Rectangle { + color: "red" + height: parent.height + Layout.minimumWidth: 100 + Layout.horizontalSizePolicy: Layout.Expanding + } + Rectangle { + color: "blue" + height: parent.height + Layout.minimumWidth: 200 + Layout.horizontalSizePolicy: Layout.Expanding + } + } + + RowLayout { + spacing: 10 + height: parent.height + + Rectangle { + color: "green" + height: parent.height + Layout.maximumWidth: 300 + Layout.horizontalSizePolicy: Layout.Expanding + } + Rectangle { + color: "red" + height: parent.height + Layout.minimumWidth: 40 + Layout.maximumWidth: 100 + Layout.horizontalSizePolicy: Layout.Expanding + } + } + } + } + } + + + Tab { + title: "Vertical" + + Row { + spacing: 4 + + anchors { + top: parent.top + left: parent.left + bottom: parent.bottom + margins: 10 + } + + // [1] + ColumnLayout { + width: defaultWidth + anchors.top: parent.top + anchors.bottom: parent.bottom + + Rectangle { + color: "red" + width: parent.width + } + Rectangle { + color: "green" + width: parent.width + } + Rectangle { + color: "blue" + width: parent.width + } + } + + // [2] + ColumnLayout { + width: defaultWidth + anchors.top: parent.top + anchors.bottom: parent.bottom + + spacing: 5 + + Rectangle { + color: "red" + width: parent.width + } + Rectangle { + color: "green" + width: parent.width + } + Item { + implicitWidth: 10 + } + Rectangle { + color: "blue" + width: parent.width + } + } + + // [3] + ColumnLayout { + width: defaultWidth + anchors.top: parent.top + anchors.bottom: parent.bottom + + Rectangle { + color: "red" + width: parent.width + Layout.minimumHeight: 50 + Layout.maximumHeight: 100 + Layout.verticalSizePolicy: Layout.Expanding + } + Rectangle { + color: "green" + width: parent.width + Layout.minimumHeight: 100 + Layout.maximumHeight: 200 + Layout.verticalSizePolicy: Layout.Expanding + } + Rectangle { + color: "blue" + width: parent.width + Layout.minimumHeight: 200 + Layout.maximumHeight: 400 + Layout.verticalSizePolicy: Layout.Expanding + } + } + + // [4] + ColumnLayout { + spacing: 100 + width: defaultWidth + anchors.top: parent.top + anchors.bottom: parent.bottom + + Rectangle { + color: "red" + width: parent.width + Layout.minimumHeight: 100 + Layout.verticalSizePolicy: Layout.Expanding + } + Rectangle { + color: "green" + width: parent.width + Layout.minimumHeight: 200 + Layout.verticalSizePolicy: Layout.Expanding + } + Rectangle { + color: "blue" + width: parent.width + Layout.minimumHeight: 300 + Layout.verticalSizePolicy: Layout.Expanding + } + } + + // [5] + ColumnLayout { + width: defaultWidth + anchors.top: parent.top + anchors.bottom: parent.bottom + + Rectangle { + color: "red" + width: parent.width + Layout.minimumHeight: 200 + Layout.maximumHeight: 500 + Layout.verticalSizePolicy: Layout.Expanding + } + } + + // [6] + ColumnLayout { + spacing: 40 + width: defaultWidth + anchors.top: parent.top + anchors.bottom: parent.bottom + + ColumnLayout { + spacing: 10 + width: parent.width + + Rectangle { + color: "red" + width: parent.width + Layout.minimumHeight: 100 + Layout.verticalSizePolicy: Layout.Expanding + } + Rectangle { + color: "blue" + width: parent.width + Layout.minimumHeight: 200 + Layout.verticalSizePolicy: Layout.Expanding + } + } + + ColumnLayout { + spacing: 10 + width: parent.width + + Rectangle { + color: "green" + width: parent.width + Layout.maximumHeight: 300 + Layout.verticalSizePolicy: Layout.Expanding + } + Rectangle { + color: "red" + width: parent.width + Layout.minimumHeight: 40 + Layout.maximumHeight: 100 + Layout.verticalSizePolicy: Layout.Expanding + } + } + } + } + } + + + Tab { + title: "Horizontal and Vertical" + + ColumnLayout { + anchors.fill: parent + + // [1] + RowLayout { + height: defaultHeight + anchors.left: parent.left + anchors.right: parent.right + + Layout.minimumHeight: 100 + + Rectangle { + color: "red" + height: parent.height + Layout.horizontalSizePolicy: Layout.Expanding + } + Rectangle { + color: "green" + height: parent.height + implicitWidth: 100 + } + Rectangle { + color: "blue" + height: parent.height + Layout.horizontalSizePolicy: Layout.Expanding + } + } + + // [2] + Rectangle { + color: "yellow" + height: parent.height + anchors.left: parent.left + anchors.right: parent.right + Layout.minimumHeight: 10 + Layout.maximumHeight: 30 + Layout.horizontalSizePolicy: Layout.Expanding + Layout.verticalSizePolicy: Layout.Expanding + } + + // [3] + RowLayout { + height: defaultHeight + anchors.left: parent.left + anchors.right: parent.right + + Rectangle { + color: "red" + height: parent.height + Layout.maximumHeight: 200 + Layout.horizontalSizePolicy: Layout.Expanding + } + Rectangle { + color: "blue" + height: parent.height + + ColumnLayout { + anchors.fill: parent + spacing: 10 + opacity: 0.6 + + Rectangle { + color: "darkRed" + height: parent.height + anchors.left: parent.left + anchors.right: parent.right + Layout.minimumHeight: 100 + Layout.maximumHeight: 200 + Layout.verticalSizePolicy: Layout.Expanding + } + + Rectangle { + color: "darkGreen" + height: parent.height + anchors.left: parent.left + anchors.right: parent.right + Layout.verticalSizePolicy: Layout.Expanding + } + } + } + } + } + } + } +} diff --git a/src/qquicklayout.cpp b/src/qquicklayout.cpp new file mode 100644 index 00000000..918b307c --- /dev/null +++ b/src/qquicklayout.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicklayout.h" +#include <QEvent> +#include <QApplication> +#include <QtCore/qnumeric.h> + + +static const qreal q_declarativeLayoutMaxSize = 10e8; + + +QQuickComponentsLayoutAttached::QQuickComponentsLayoutAttached(QObject *parent) + : QObject(parent), + m_minimumWidth(0), + m_minimumHeight(0), + m_maximumWidth(q_declarativeLayoutMaxSize), + m_maximumHeight(q_declarativeLayoutMaxSize), + m_verticalSizePolicy(QQuickComponentsLayout::Fixed), + m_horizontalSizePolicy(QQuickComponentsLayout::Fixed) +{ + +} + +void QQuickComponentsLayoutAttached::setMinimumWidth(qreal width) +{ + if (qIsNaN(width) || m_minimumWidth == width) + return; + + m_minimumWidth = width; + updateLayout(); +} + +void QQuickComponentsLayoutAttached::setMinimumHeight(qreal height) +{ + if (qIsNaN(height) || m_minimumHeight == height) + return; + + m_minimumHeight = height; + updateLayout(); +} + +void QQuickComponentsLayoutAttached::setMaximumWidth(qreal width) +{ + if (qIsNaN(width) || m_maximumWidth == width) + return; + + m_maximumWidth = width; + updateLayout(); +} + +void QQuickComponentsLayoutAttached::setMaximumHeight(qreal height) +{ + if (qIsNaN(height) || m_maximumHeight == height) + return; + + m_maximumHeight = height; + updateLayout(); +} + +void QQuickComponentsLayoutAttached::setVerticalSizePolicy(QQuickComponentsLayout::SizePolicy policy) +{ + if (m_verticalSizePolicy != policy) { + m_verticalSizePolicy = policy; + updateLayout(); + } +} + +void QQuickComponentsLayoutAttached::setHorizontalSizePolicy(QQuickComponentsLayout::SizePolicy policy) +{ + if (m_horizontalSizePolicy != policy) { + m_horizontalSizePolicy = policy; + updateLayout(); + } +} + +void QQuickComponentsLayoutAttached::updateLayout() +{ + if (m_layout) + m_layout->invalidate(); +} + + + +QQuickComponentsLayout::QQuickComponentsLayout(QQuickItem *parent) + : QQuickItem(parent), + m_dirty(false) +{ + +} + +QQuickComponentsLayout::~QQuickComponentsLayout() +{ + +} + +void QQuickComponentsLayout::setupItemLayout(QQuickItem *item) +{ + QObject *attached = qmlAttachedPropertiesObject<QQuickComponentsLayout>(item); + QQuickComponentsLayoutAttached *info = static_cast<QQuickComponentsLayoutAttached *>(attached); + info->m_layout = this; +} + +QQuickComponentsLayoutAttached *QQuickComponentsLayout::qmlAttachedProperties(QObject *object) +{ + return new QQuickComponentsLayoutAttached(object); +} + +bool QQuickComponentsLayout::event(QEvent *e) +{ + if (e->type() == QEvent::LayoutRequest) + reconfigureTopDown(); + + return QQuickItem::event(e); +} + +void QQuickComponentsLayout::invalidate() +{ + if (m_dirty) + return; + + QQuickComponentsLayout *layout = this; + QQuickComponentsLayout *parentLayout = 0; + + while (!layout->m_dirty) { + layout->m_dirty = true; + parentLayout = qobject_cast<QQuickComponentsLayout *>(layout->parentItem()); + + if (!parentLayout) + break; + else + layout = parentLayout; + } + + // just post events for top level layouts + if (!parentLayout) + QApplication::postEvent(layout, new QEvent(QEvent::LayoutRequest)); +} + +void QQuickComponentsLayout::reconfigureTopDown() +{ + const QList<QQuickItem *> &children = childItems(); + + reconfigureLayout(); + + foreach (QQuickItem *child, children) { + QQuickComponentsLayout *layout = qobject_cast<QQuickComponentsLayout *>(child); + + if (layout && layout->m_dirty) + layout->reconfigureTopDown(); + } + + m_dirty = false; +} + +void QQuickComponentsLayout::reconfigureLayout() +{ + +} diff --git a/src/qquicklayout.h b/src/qquicklayout.h new file mode 100644 index 00000000..15aff606 --- /dev/null +++ b/src/qquicklayout.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELAYOUT_H +#define QDECLARATIVELAYOUT_H + +#include <QPointer> +#include <QQuickItem> + +class QQuickComponentsLayoutAttached; + + +class QQuickComponentsLayout : public QQuickItem +{ + Q_OBJECT + Q_ENUMS(SizePolicy) + +public: + enum SizePolicy { + Fixed, + Expanding + }; + + explicit QQuickComponentsLayout(QQuickItem *parent = 0); + ~QQuickComponentsLayout(); + + static QQuickComponentsLayoutAttached *qmlAttachedProperties(QObject *object); + +protected: + void invalidate(); + bool event(QEvent *e); + void reconfigureTopDown(); + virtual void reconfigureLayout(); + void setupItemLayout(QQuickItem *item); + +private: + bool m_dirty; + + friend class QQuickComponentsLayoutAttached; +}; + + +class QQuickComponentsLayoutAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal minimumWidth READ minimumWidth WRITE setMinimumWidth) + Q_PROPERTY(qreal minimumHeight READ minimumHeight WRITE setMinimumHeight) + Q_PROPERTY(qreal maximumWidth READ maximumWidth WRITE setMaximumWidth) + Q_PROPERTY(qreal maximumHeight READ maximumHeight WRITE setMaximumHeight) + Q_PROPERTY(QQuickComponentsLayout::SizePolicy verticalSizePolicy READ verticalSizePolicy WRITE setVerticalSizePolicy) + Q_PROPERTY(QQuickComponentsLayout::SizePolicy horizontalSizePolicy READ horizontalSizePolicy WRITE setHorizontalSizePolicy) + +public: + QQuickComponentsLayoutAttached(QObject *object); + + qreal minimumWidth() const { return m_minimumWidth; } + void setMinimumWidth(qreal width); + + qreal minimumHeight() const { return m_minimumHeight; } + void setMinimumHeight(qreal height); + + qreal maximumWidth() const { return m_maximumWidth; } + void setMaximumWidth(qreal width); + + qreal maximumHeight() const { return m_maximumHeight; } + void setMaximumHeight(qreal height); + + QQuickComponentsLayout::SizePolicy verticalSizePolicy() const { return m_verticalSizePolicy; } + void setVerticalSizePolicy(QQuickComponentsLayout::SizePolicy policy); + + QQuickComponentsLayout::SizePolicy horizontalSizePolicy() const { return m_horizontalSizePolicy; } + void setHorizontalSizePolicy(QQuickComponentsLayout::SizePolicy policy); + +protected: + void updateLayout(); + +private: + qreal m_minimumWidth; + qreal m_minimumHeight; + qreal m_maximumWidth; + qreal m_maximumHeight; + QQuickComponentsLayout::SizePolicy m_verticalSizePolicy; + QQuickComponentsLayout::SizePolicy m_horizontalSizePolicy; + QPointer<QQuickComponentsLayout> m_layout; + + friend class QQuickComponentsLayout; +}; + +QML_DECLARE_TYPE(QQuickComponentsLayout) +QML_DECLARE_TYPEINFO(QQuickComponentsLayout, QML_HAS_ATTACHED_PROPERTIES) + +#endif diff --git a/src/qquicklayoutengine.cpp b/src/qquicklayoutengine.cpp new file mode 100644 index 00000000..98cb95ce --- /dev/null +++ b/src/qquicklayoutengine.cpp @@ -0,0 +1,290 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicklayoutengine_p.h" + + +/* + This function is a modification of qGeomCalc() included in "QtCore/kernel/qlayoutengine_p.h". + It is used as a helper function to handle linear layout recalculations for QQuickItems. + + chain contains input and output parameters describing the geometry. + count is the count of items in the chain; pos and space give the + interval (relative to parentWidget topLeft). +*/ +void qDeclarativeLayoutCalculate(QVector<QQuickComponentsLayoutInfo> &chain, int start, + int count, qreal pos, qreal space, qreal spacer) +{ + if (chain.count() == 0) + return; + + bool wannaGrow = false; + qreal totalStretch = 0; + qreal totalSpacing = 0; + qreal totalSizeHint = 0; + qreal totalMinimumSize = 0; + + const int end = start + count; + const int spacerCount = chain.count() - 1; + + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + data->done = false; + + totalStretch += data->stretch; + totalSizeHint += data->smartSizeHint(); + totalMinimumSize += data->minimumSize; + + // don't count last spacing + if (i < end - 1) + totalSpacing += data->effectiveSpacer(spacer); + + wannaGrow = (wannaGrow || data->expansive || data->stretch > 0); + } + + qreal extraSpace = 0; + + if (space < totalMinimumSize + totalSpacing) { + // Less space than minimumSize; take from the biggest first + qreal minSize = totalMinimumSize + totalSpacing; + + // shrink the spacers proportionally + if (spacer >= 0) { + spacer = minSize > 0 ? spacer * space / minSize : 0; + totalSpacing = spacer * spacerCount; + } + + QList<qreal> list; + + for (int i = start; i < end; i++) + list << chain.at(i).minimumSize; + + qSort(list); + + qreal spaceLeft = space - totalSpacing; + + qreal sum = 0; + int idx = 0; + qreal spaceUsed = 0; + qreal current = 0; + + while (idx < count && spaceUsed < spaceLeft) { + current = list.at(idx); + spaceUsed = sum + current * (count - idx); + sum += current; + ++idx; + } + + --idx; + + int items = count - idx; + qreal deficit = spaceUsed - spaceLeft; + qreal deficitPerItem = deficit / items; + qreal maxval = current - deficitPerItem; + + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + data->done = true; + + if (data->minimumSize > 0) + data->size = data->minimumSize; + else + data->size = qMin<qreal>(data->minimumSize, maxval); + } + } else if (space < totalSizeHint + totalSpacing) { + /* + Less space than smartSizeHint(), but more than minimumSize. + Currently take space equally from each, as in Qt 2.x. + Commented-out lines will give more space to stretchier + items. + */ + int n = count; + qreal spaceLeft = space - totalSpacing; + qreal overdraft = totalSizeHint - spaceLeft; + + // first give to the fixed ones + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (!data->done && data->minimumSize >= data->smartSizeHint()) { + data->done = true; + data->size = data->smartSizeHint(); + spaceLeft -= data->smartSizeHint(); + n--; + } + } + + bool finished = (n == 0); + + while (!finished) { + finished = true; + + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (data->done) + continue; + + qreal w = overdraft / n; + data->size = data->smartSizeHint() - w; + + if (data->size < data->minimumSize) { + data->done = true; + data->size = data->minimumSize; + finished = false; + overdraft -= data->smartSizeHint() - data->minimumSize; + n--; + break; + } + } + } + } else { // extra space + int n = count; + qreal spaceLeft = space - totalSpacing; + + // first give to the fixed ones, and handle non-expansiveness + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (data->done) + continue; + + if (data->maximumSize <= data->smartSizeHint() + || (wannaGrow && !data->expansive && data->stretch == 0) + || (!data->expansive && data->stretch == 0)) { + data->done = true; + data->size = data->smartSizeHint(); + spaceLeft -= data->size; + totalStretch -= data->stretch; + n--; + } + } + + extraSpace = spaceLeft; + + /* + Do a trial distribution and calculate how much it is off. + If there are more deficit pixels than surplus pixels, give + the minimum size items what they need, and repeat. + Otherwise give to the maximum size items, and repeat. + + Paul Olav Tvete has a wonderful mathematical proof of the + correctness of this principle, but unfortunately this + comment is too small to contain it. + */ + qreal surplus, deficit; + + do { + surplus = deficit = 0; + + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (data->done) + continue; + + extraSpace = 0; + + qreal w; + + if (totalStretch <= 0) + w = (spaceLeft / n); + else + w = (spaceLeft * data->stretch) / totalStretch; + + data->size = w; + + if (w < data->smartSizeHint()) + deficit += data->smartSizeHint() - w; + else if (w > data->maximumSize) + surplus += w - data->maximumSize; + } + + if (deficit > 0 && surplus <= deficit) { + // give to the ones that have too little + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (!data->done && data->size < data->smartSizeHint()) { + data->done = true; + data->size = data->smartSizeHint(); + spaceLeft -= data->smartSizeHint(); + totalStretch -= data->stretch; + n--; + } + } + } + + if (surplus > 0 && surplus >= deficit) { + // take from the ones that have too much + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (!data->done && data->size > data->maximumSize) { + data->done = true; + data->size = data->maximumSize; + spaceLeft -= data->maximumSize; + totalStretch -= data->stretch; + n--; + } + } + } + } while (n > 0 && surplus != deficit); + + if (n == 0) + extraSpace = spaceLeft; + } + + /* + As a last resort, we distribute the unwanted space equally + among the spacers (counting the start and end of the chain). We + could, but don't, attempt a sub-pixel allocation of the extra + space. + */ + qreal extra = extraSpace / (spacerCount + 2); + qreal p = pos + extra; + + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + data->pos = p; + p += data->size; + p += data->effectiveSpacer(spacer) + extra; + } +} diff --git a/src/qquicklayoutengine_p.h b/src/qquicklayoutengine_p.h new file mode 100644 index 00000000..52284ade --- /dev/null +++ b/src/qquicklayoutengine_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELAYOUTENGINE_H +#define QDECLARATIVELAYOUTENGINE_H + +#include <QVector> + +struct QQuickComponentsLayoutInfo +{ + QQuickComponentsLayoutInfo() + : stretch(1), + sizeHint(0), + spacing(0), + minimumSize(0), + maximumSize(0), + expansive(true), + done(false), + pos(0), + size(0) + { } + + inline qreal smartSizeHint() { + return (stretch > 0) ? minimumSize : sizeHint; + } + + inline qreal effectiveSpacer(qreal value) const { + return value + spacing; + } + + qreal stretch; + qreal sizeHint; + qreal spacing; + qreal minimumSize; + qreal maximumSize; + bool expansive; + + // result + bool done; + qreal pos; + qreal size; +}; + +void qDeclarativeLayoutCalculate(QVector<QQuickComponentsLayoutInfo> &chain, int start, + int count, qreal pos, qreal space, qreal spacer); + +#endif diff --git a/src/qquicklinearlayout.cpp b/src/qquicklinearlayout.cpp new file mode 100644 index 00000000..702369bc --- /dev/null +++ b/src/qquicklinearlayout.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicklinearlayout.h" +#include "qquicklayoutengine_p.h" +#include <QtCore/qnumeric.h> + +static const qreal q_declarativeLayoutDefaultSpacing = 4.0; + + +QQuickComponentsLinearLayout::QQuickComponentsLinearLayout(Orientation orientation, + QQuickItem *parent) + : QQuickComponentsLayout(parent), + m_spacing(q_declarativeLayoutDefaultSpacing), + m_orientation(orientation) +{ + +} + +qreal QQuickComponentsLinearLayout::spacing() const +{ + return m_spacing; +} + +void QQuickComponentsLinearLayout::setSpacing(qreal spacing) +{ + if (qIsNaN(spacing) || m_spacing == spacing) + return; + + m_spacing = spacing; + invalidate(); +} + +QQuickComponentsLinearLayout::Orientation QQuickComponentsLinearLayout::orientation() const +{ + return m_orientation; +} + +void QQuickComponentsLinearLayout::setOrientation(Orientation orientation) +{ + if (m_orientation == orientation) + return; + + m_orientation = orientation; + invalidate(); + + emit orientationChanged(); +} + +void QQuickComponentsLinearLayout::componentComplete() +{ + QQuickComponentsLayout::componentComplete(); + updateLayoutItems(); + invalidate(); +} + +void QQuickComponentsLinearLayout::updateLayoutItems() +{ + const QList<QQuickItem *> &children = childItems(); + + foreach (QQuickItem *child, children) + insertLayoutItem(child); +} + +void QQuickComponentsLinearLayout::itemChange(ItemChange change, const ItemChangeData &value) +{ + if (isComponentComplete()) { + if (change == ItemChildAddedChange) + insertLayoutItem(value.item); + else if (change == ItemChildRemovedChange) + removeLayoutItem(value.item); + } + + QQuickComponentsLayout::itemChange(change, value); +} + +void QQuickComponentsLinearLayout::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + QQuickComponentsLayout::geometryChanged(newGeometry, oldGeometry); + invalidate(); +} + +void QQuickComponentsLinearLayout::insertLayoutItem(QQuickItem *item) +{ + m_items.append(item); + setupItemLayout(item); + + invalidate(); + QObject::connect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed())); +} + +void QQuickComponentsLinearLayout::removeLayoutItem(QQuickItem *item) +{ + if (!m_items.removeOne(item)) + return; + + invalidate(); + QObject::disconnect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed())); +} + +void QQuickComponentsLinearLayout::onItemDestroyed() +{ + if (!m_items.removeOne(static_cast<QQuickItem *>(sender()))) + return; + + invalidate(); +} + +void QQuickComponentsLinearLayout::reconfigureLayout() +{ + if (!isComponentComplete()) + return; + + const int count = m_items.count(); + + if (count == 0) + return; + + qreal totalSpacing = 0; + qreal totalSizeHint = 0; + qreal totalMinimumSize = 0; + qreal totalMaximumSize = 0; + + QVector<QQuickComponentsLayoutInfo> itemData; + + for (int i = 0; i < count; i++) { + QQuickItem *item = m_items.at(i); + QObject *attached = qmlAttachedPropertiesObject<QQuickComponentsLayout>(item); + QQuickComponentsLayoutAttached *info = static_cast<QQuickComponentsLayoutAttached *>(attached); + + QQuickComponentsLayoutInfo data; + + if (m_orientation == Horizontal) { + data.sizeHint = item->implicitWidth(); + data.minimumSize = info->minimumWidth(); + data.maximumSize = info->maximumWidth(); + data.expansive = (info->horizontalSizePolicy() == QQuickComponentsLayout::Expanding); + //data.stretch = info->horizontalSizePolicy() == Expanding ? 1.0 : 0; + } else { + data.sizeHint = item->implicitHeight(); + data.minimumSize = info->minimumHeight(); + data.maximumSize = info->maximumHeight(); + data.expansive = (info->verticalSizePolicy() == QQuickComponentsLayout::Expanding); + //data.stretch = info->verticalSizePolicy() == Expanding ? 1.0 : 0; + } + + itemData.append(data); + + // sum + totalSizeHint += data.sizeHint; + totalMinimumSize += data.minimumSize; + totalMaximumSize += data.maximumSize; + + // don't count last spacing + if (i < count - 1) + totalSpacing += data.spacing + m_spacing; + } + + if (m_orientation == Horizontal) { + qDeclarativeLayoutCalculate(itemData, 0, count, 0, width(), m_spacing); + + for (int i = 0; i < count; i++) { + QQuickItem *item = m_items.at(i); + const QQuickComponentsLayoutInfo &data = itemData.at(i); + + item->setX(data.pos); + item->setY(height()/2 - item->height()/2); + item->setWidth(data.size); + } + } else { + qDeclarativeLayoutCalculate(itemData, 0, count, 0, height(), m_spacing); + + for (int i = 0; i < count; i++) { + QQuickItem *item = m_items.at(i); + const QQuickComponentsLayoutInfo &data = itemData.at(i); + + item->setY(data.pos); + item->setX(width()/2 - item->width()/2); + item->setHeight(data.size); + } + } + + // propagate hints to upper levels + QObject *attached = qmlAttachedPropertiesObject<QQuickComponentsLayout>(this); + QQuickComponentsLayoutAttached *info = static_cast<QQuickComponentsLayoutAttached *>(attached); + + if (m_orientation == Horizontal) { + setImplicitWidth(totalSizeHint); + info->setMinimumWidth(totalMinimumSize + totalSpacing); + info->setMaximumWidth(totalMaximumSize + totalSpacing); + } else { + setImplicitHeight(totalSizeHint); + info->setMinimumHeight(totalMinimumSize + totalSpacing); + info->setMaximumHeight(totalMaximumSize + totalSpacing); + } +} diff --git a/src/qquicklinearlayout.h b/src/qquicklinearlayout.h new file mode 100644 index 00000000..1044b199 --- /dev/null +++ b/src/qquicklinearlayout.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELINEARLAYOUT_H +#define QDECLARATIVELINEARLAYOUT_H + +#include "qquicklayout.h" + + +class QQuickComponentsLinearLayout : public QQuickComponentsLayout +{ + Q_OBJECT + Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged) + +public: + enum Orientation { + Vertical, + Horizontal + }; + + explicit QQuickComponentsLinearLayout(Orientation orientation, + QQuickItem *parent = 0); + ~QQuickComponentsLinearLayout() {} + + qreal spacing() const; + void setSpacing(qreal spacing); + + Orientation orientation() const; + void setOrientation(Orientation orientation); + + void componentComplete(); + +signals: + void spacingChanged(); + void orientationChanged(); + +protected: + void updateLayoutItems(); + void reconfigureLayout(); + void insertLayoutItem(QQuickItem *item); + void removeLayoutItem(QQuickItem *item); + void itemChange(ItemChange change, const ItemChangeData &data); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); + +protected slots: + void onItemDestroyed(); + +private: + qreal m_spacing; + Orientation m_orientation; + QList<QQuickItem *> m_items; +}; + + +class QQuickComponentsRowLayout : public QQuickComponentsLinearLayout +{ + Q_OBJECT + +public: + explicit QQuickComponentsRowLayout(QQuickItem *parent = 0) + : QQuickComponentsLinearLayout(Horizontal, parent) {} +}; + + +class QQuickComponentsColumnLayout : public QQuickComponentsLinearLayout +{ + Q_OBJECT + +public: + explicit QQuickComponentsColumnLayout(QQuickItem *parent = 0) + : QQuickComponentsLinearLayout(Vertical, parent) {} +}; + +#endif diff --git a/src/qstyleplugin.cpp b/src/qstyleplugin.cpp index 054aff2a..e375d253 100644 --- a/src/qstyleplugin.cpp +++ b/src/qstyleplugin.cpp @@ -51,6 +51,7 @@ #include "qcursorarea.h" #include "qtooltiparea.h" #include "qtsplitterbase.h" +#include "qquicklinearlayout.h" #include <qqmlextensionplugin.h> #include <qqmlengine.h> @@ -92,6 +93,11 @@ void StylePlugin::registerTypes(const char *uri) qmlRegisterType<QtMenuItem>(uri, 0, 2, "MenuItem"); qmlRegisterType<QtMenuSeparator>(uri, 0, 2, "Separator"); + qmlRegisterType<QQuickComponentsRowLayout>(uri, 0, 2, "RowLayout"); + qmlRegisterType<QQuickComponentsColumnLayout>(uri, 0, 2, "ColumnLayout"); + qmlRegisterUncreatableType<QQuickComponentsLayout>(uri, 0, 2, "Layout", + QLatin1String("Do not create objects of type Layout")); + qmlRegisterType<QFileSystemModel>(uri, 0, 2, "FileSystemModel"); qmlRegisterType<QtSplitterBase>(uri, 0, 2, "Splitter"); qmlRegisterType<QWindowItem>("QtQuick", 2, 0, "Window"); // override built-in Window diff --git a/src/src.pro b/src/src.pro index abaedd5f..b1c34ca6 100644 --- a/src/src.pro +++ b/src/src.pro @@ -23,8 +23,11 @@ HEADERS += qtmenu.h \ qdesktopitem.h \ qtoplevelwindow.h \ qcursorarea.h \ + qquicklayoutengine_p.h \ + qquicklayout.h \ + qquicklinearlayout.h \ qtooltiparea.h \ - qtsplitterbase.h + qtsplitterbase.h SOURCES += qtmenu.cpp \ qtmenubar.cpp \ @@ -39,7 +42,10 @@ SOURCES += qtmenu.cpp \ qtoplevelwindow.cpp \ qcursorarea.cpp \ qtooltiparea.cpp \ - qtsplitterbase.cpp + qquicklayout.cpp \ + qquicklayoutengine.cpp \ + qquicklinearlayout.cpp \ + qtsplitterbase.cpp TARGETPATH = QtDesktop/plugin |