From a60c8e60d508117ddf48876b44d31e6d5ab98da6 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 13 Apr 2016 15:59:53 +0200 Subject: Templates: rename the C++ module to qtquicktemplates2 Change-Id: I146da903b46f5c2caf865e37291c25376b49021a Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickabstractbutton.cpp | 621 +++++++ src/quicktemplates2/qquickabstractbutton_p.h | 146 ++ src/quicktemplates2/qquickabstractbutton_p_p.h | 100 ++ src/quicktemplates2/qquickapplicationwindow.cpp | 747 ++++++++ src/quicktemplates2/qquickapplicationwindow_p.h | 166 ++ src/quicktemplates2/qquickbusyindicator.cpp | 115 ++ src/quicktemplates2/qquickbusyindicator_p.h | 85 + src/quicktemplates2/qquickbutton.cpp | 115 ++ src/quicktemplates2/qquickbutton_p.h | 76 + src/quicktemplates2/qquickbuttongroup.cpp | 383 ++++ src/quicktemplates2/qquickbuttongroup_p.h | 116 ++ src/quicktemplates2/qquickcheckbox.cpp | 201 +++ src/quicktemplates2/qquickcheckbox_p.h | 95 + src/quicktemplates2/qquickcheckdelegate.cpp | 181 ++ src/quicktemplates2/qquickcheckdelegate_p.h | 93 + src/quicktemplates2/qquickcombobox.cpp | 872 +++++++++ src/quicktemplates2/qquickcombobox_p.h | 153 ++ src/quicktemplates2/qquickcontainer.cpp | 527 ++++++ src/quicktemplates2/qquickcontainer_p.h | 116 ++ src/quicktemplates2/qquickcontainer_p_p.h | 97 + src/quicktemplates2/qquickcontrol.cpp | 1102 ++++++++++++ src/quicktemplates2/qquickcontrol_p.h | 214 +++ src/quicktemplates2/qquickcontrol_p_p.h | 137 ++ src/quicktemplates2/qquickdial.cpp | 566 ++++++ src/quicktemplates2/qquickdial_p.h | 147 ++ src/quicktemplates2/qquickdrawer.cpp | 460 +++++ src/quicktemplates2/qquickdrawer_p.h | 95 + src/quicktemplates2/qquickframe.cpp | 82 + src/quicktemplates2/qquickframe_p.h | 76 + src/quicktemplates2/qquickframe_p_p.h | 63 + src/quicktemplates2/qquickgroupbox.cpp | 153 ++ src/quicktemplates2/qquickgroupbox_p.h | 88 + src/quicktemplates2/qquickitemdelegate.cpp | 88 + src/quicktemplates2/qquickitemdelegate_p.h | 77 + src/quicktemplates2/qquicklabel.cpp | 251 +++ src/quicktemplates2/qquicklabel_p.h | 93 + src/quicktemplates2/qquicklabel_p_p.h | 93 + src/quicktemplates2/qquickmenu.cpp | 489 ++++++ src/quicktemplates2/qquickmenu_p.h | 107 ++ src/quicktemplates2/qquickmenu_p_p.h | 102 ++ src/quicktemplates2/qquickmenuitem.cpp | 118 ++ src/quicktemplates2/qquickmenuitem_p.h | 86 + src/quicktemplates2/qquickoverlay.cpp | 274 +++ src/quicktemplates2/qquickoverlay_p.h | 90 + src/quicktemplates2/qquickpage.cpp | 321 ++++ src/quicktemplates2/qquickpage_p.h | 102 ++ src/quicktemplates2/qquickpageindicator.cpp | 302 ++++ src/quicktemplates2/qquickpageindicator_p.h | 108 ++ src/quicktemplates2/qquickpane.cpp | 192 ++ src/quicktemplates2/qquickpane_p.h | 102 ++ src/quicktemplates2/qquickpane_p_p.h | 70 + src/quicktemplates2/qquickpopup.cpp | 1851 ++++++++++++++++++++ src/quicktemplates2/qquickpopup_p.h | 368 ++++ src/quicktemplates2/qquickpopup_p_p.h | 209 +++ src/quicktemplates2/qquickpresshandler.cpp | 114 ++ src/quicktemplates2/qquickpresshandler_p_p.h | 82 + src/quicktemplates2/qquickprogressbar.cpp | 259 +++ src/quicktemplates2/qquickprogressbar_p.h | 110 ++ src/quicktemplates2/qquickradiobutton.cpp | 111 ++ src/quicktemplates2/qquickradiobutton_p.h | 74 + src/quicktemplates2/qquickradiodelegate.cpp | 95 + src/quicktemplates2/qquickradiodelegate_p.h | 74 + src/quicktemplates2/qquickrangeslider.cpp | 927 ++++++++++ src/quicktemplates2/qquickrangeslider_p.h | 175 ++ src/quicktemplates2/qquickscrollbar.cpp | 620 +++++++ src/quicktemplates2/qquickscrollbar_p.h | 150 ++ src/quicktemplates2/qquickscrollindicator.cpp | 429 +++++ src/quicktemplates2/qquickscrollindicator_p.h | 133 ++ src/quicktemplates2/qquickslider.cpp | 585 +++++++ src/quicktemplates2/qquickslider_p.h | 150 ++ src/quicktemplates2/qquickspinbox.cpp | 724 ++++++++ src/quicktemplates2/qquickspinbox_p.h | 172 ++ src/quicktemplates2/qquickstackview.cpp | 989 +++++++++++ src/quicktemplates2/qquickstackview_p.cpp | 549 ++++++ src/quicktemplates2/qquickstackview_p.h | 189 ++ src/quicktemplates2/qquickstackview_p_p.h | 162 ++ src/quicktemplates2/qquickswipedelegate.cpp | 855 +++++++++ src/quicktemplates2/qquickswipedelegate_p.h | 145 ++ src/quicktemplates2/qquickswipeview.cpp | 348 ++++ src/quicktemplates2/qquickswipeview_p.h | 108 ++ src/quicktemplates2/qquickswitch.cpp | 242 +++ src/quicktemplates2/qquickswitch_p.h | 88 + src/quicktemplates2/qquickswitchdelegate.cpp | 157 ++ src/quicktemplates2/qquickswitchdelegate_p.h | 87 + src/quicktemplates2/qquicktabbar.cpp | 214 +++ src/quicktemplates2/qquicktabbar_p.h | 98 ++ src/quicktemplates2/qquicktabbutton.cpp | 82 + src/quicktemplates2/qquicktabbutton_p.h | 74 + src/quicktemplates2/qquicktextarea.cpp | 425 +++++ src/quicktemplates2/qquicktextarea_p.h | 118 ++ src/quicktemplates2/qquicktextarea_p_p.h | 105 ++ src/quicktemplates2/qquicktextfield.cpp | 450 +++++ src/quicktemplates2/qquicktextfield_p.h | 118 ++ src/quicktemplates2/qquicktextfield_p_p.h | 106 ++ src/quicktemplates2/qquicktoolbar.cpp | 147 ++ src/quicktemplates2/qquicktoolbar_p.h | 91 + src/quicktemplates2/qquicktoolbutton.cpp | 91 + src/quicktemplates2/qquicktoolbutton_p.h | 70 + src/quicktemplates2/qquicktooltip.cpp | 560 ++++++ src/quicktemplates2/qquicktooltip_p.h | 148 ++ src/quicktemplates2/qquicktumbler.cpp | 548 ++++++ src/quicktemplates2/qquicktumbler_p.h | 143 ++ src/quicktemplates2/qquickvelocitycalculator.cpp | 108 ++ src/quicktemplates2/qquickvelocitycalculator_p_p.h | 78 + src/quicktemplates2/qtquicktemplates2global_p.h | 67 + src/quicktemplates2/quicktemplates2.pri | 109 ++ src/quicktemplates2/quicktemplates2.pro | 14 + 107 files changed, 26548 insertions(+) create mode 100644 src/quicktemplates2/qquickabstractbutton.cpp create mode 100644 src/quicktemplates2/qquickabstractbutton_p.h create mode 100644 src/quicktemplates2/qquickabstractbutton_p_p.h create mode 100644 src/quicktemplates2/qquickapplicationwindow.cpp create mode 100644 src/quicktemplates2/qquickapplicationwindow_p.h create mode 100644 src/quicktemplates2/qquickbusyindicator.cpp create mode 100644 src/quicktemplates2/qquickbusyindicator_p.h create mode 100644 src/quicktemplates2/qquickbutton.cpp create mode 100644 src/quicktemplates2/qquickbutton_p.h create mode 100644 src/quicktemplates2/qquickbuttongroup.cpp create mode 100644 src/quicktemplates2/qquickbuttongroup_p.h create mode 100644 src/quicktemplates2/qquickcheckbox.cpp create mode 100644 src/quicktemplates2/qquickcheckbox_p.h create mode 100644 src/quicktemplates2/qquickcheckdelegate.cpp create mode 100644 src/quicktemplates2/qquickcheckdelegate_p.h create mode 100644 src/quicktemplates2/qquickcombobox.cpp create mode 100644 src/quicktemplates2/qquickcombobox_p.h create mode 100644 src/quicktemplates2/qquickcontainer.cpp create mode 100644 src/quicktemplates2/qquickcontainer_p.h create mode 100644 src/quicktemplates2/qquickcontainer_p_p.h create mode 100644 src/quicktemplates2/qquickcontrol.cpp create mode 100644 src/quicktemplates2/qquickcontrol_p.h create mode 100644 src/quicktemplates2/qquickcontrol_p_p.h create mode 100644 src/quicktemplates2/qquickdial.cpp create mode 100644 src/quicktemplates2/qquickdial_p.h create mode 100644 src/quicktemplates2/qquickdrawer.cpp create mode 100644 src/quicktemplates2/qquickdrawer_p.h create mode 100644 src/quicktemplates2/qquickframe.cpp create mode 100644 src/quicktemplates2/qquickframe_p.h create mode 100644 src/quicktemplates2/qquickframe_p_p.h create mode 100644 src/quicktemplates2/qquickgroupbox.cpp create mode 100644 src/quicktemplates2/qquickgroupbox_p.h create mode 100644 src/quicktemplates2/qquickitemdelegate.cpp create mode 100644 src/quicktemplates2/qquickitemdelegate_p.h create mode 100644 src/quicktemplates2/qquicklabel.cpp create mode 100644 src/quicktemplates2/qquicklabel_p.h create mode 100644 src/quicktemplates2/qquicklabel_p_p.h create mode 100644 src/quicktemplates2/qquickmenu.cpp create mode 100644 src/quicktemplates2/qquickmenu_p.h create mode 100644 src/quicktemplates2/qquickmenu_p_p.h create mode 100644 src/quicktemplates2/qquickmenuitem.cpp create mode 100644 src/quicktemplates2/qquickmenuitem_p.h create mode 100644 src/quicktemplates2/qquickoverlay.cpp create mode 100644 src/quicktemplates2/qquickoverlay_p.h create mode 100644 src/quicktemplates2/qquickpage.cpp create mode 100644 src/quicktemplates2/qquickpage_p.h create mode 100644 src/quicktemplates2/qquickpageindicator.cpp create mode 100644 src/quicktemplates2/qquickpageindicator_p.h create mode 100644 src/quicktemplates2/qquickpane.cpp create mode 100644 src/quicktemplates2/qquickpane_p.h create mode 100644 src/quicktemplates2/qquickpane_p_p.h create mode 100644 src/quicktemplates2/qquickpopup.cpp create mode 100644 src/quicktemplates2/qquickpopup_p.h create mode 100644 src/quicktemplates2/qquickpopup_p_p.h create mode 100644 src/quicktemplates2/qquickpresshandler.cpp create mode 100644 src/quicktemplates2/qquickpresshandler_p_p.h create mode 100644 src/quicktemplates2/qquickprogressbar.cpp create mode 100644 src/quicktemplates2/qquickprogressbar_p.h create mode 100644 src/quicktemplates2/qquickradiobutton.cpp create mode 100644 src/quicktemplates2/qquickradiobutton_p.h create mode 100644 src/quicktemplates2/qquickradiodelegate.cpp create mode 100644 src/quicktemplates2/qquickradiodelegate_p.h create mode 100644 src/quicktemplates2/qquickrangeslider.cpp create mode 100644 src/quicktemplates2/qquickrangeslider_p.h create mode 100644 src/quicktemplates2/qquickscrollbar.cpp create mode 100644 src/quicktemplates2/qquickscrollbar_p.h create mode 100644 src/quicktemplates2/qquickscrollindicator.cpp create mode 100644 src/quicktemplates2/qquickscrollindicator_p.h create mode 100644 src/quicktemplates2/qquickslider.cpp create mode 100644 src/quicktemplates2/qquickslider_p.h create mode 100644 src/quicktemplates2/qquickspinbox.cpp create mode 100644 src/quicktemplates2/qquickspinbox_p.h create mode 100644 src/quicktemplates2/qquickstackview.cpp create mode 100644 src/quicktemplates2/qquickstackview_p.cpp create mode 100644 src/quicktemplates2/qquickstackview_p.h create mode 100644 src/quicktemplates2/qquickstackview_p_p.h create mode 100644 src/quicktemplates2/qquickswipedelegate.cpp create mode 100644 src/quicktemplates2/qquickswipedelegate_p.h create mode 100644 src/quicktemplates2/qquickswipeview.cpp create mode 100644 src/quicktemplates2/qquickswipeview_p.h create mode 100644 src/quicktemplates2/qquickswitch.cpp create mode 100644 src/quicktemplates2/qquickswitch_p.h create mode 100644 src/quicktemplates2/qquickswitchdelegate.cpp create mode 100644 src/quicktemplates2/qquickswitchdelegate_p.h create mode 100644 src/quicktemplates2/qquicktabbar.cpp create mode 100644 src/quicktemplates2/qquicktabbar_p.h create mode 100644 src/quicktemplates2/qquicktabbutton.cpp create mode 100644 src/quicktemplates2/qquicktabbutton_p.h create mode 100644 src/quicktemplates2/qquicktextarea.cpp create mode 100644 src/quicktemplates2/qquicktextarea_p.h create mode 100644 src/quicktemplates2/qquicktextarea_p_p.h create mode 100644 src/quicktemplates2/qquicktextfield.cpp create mode 100644 src/quicktemplates2/qquicktextfield_p.h create mode 100644 src/quicktemplates2/qquicktextfield_p_p.h create mode 100644 src/quicktemplates2/qquicktoolbar.cpp create mode 100644 src/quicktemplates2/qquicktoolbar_p.h create mode 100644 src/quicktemplates2/qquicktoolbutton.cpp create mode 100644 src/quicktemplates2/qquicktoolbutton_p.h create mode 100644 src/quicktemplates2/qquicktooltip.cpp create mode 100644 src/quicktemplates2/qquicktooltip_p.h create mode 100644 src/quicktemplates2/qquicktumbler.cpp create mode 100644 src/quicktemplates2/qquicktumbler_p.h create mode 100644 src/quicktemplates2/qquickvelocitycalculator.cpp create mode 100644 src/quicktemplates2/qquickvelocitycalculator_p_p.h create mode 100644 src/quicktemplates2/qtquicktemplates2global_p.h create mode 100644 src/quicktemplates2/quicktemplates2.pri create mode 100644 src/quicktemplates2/quicktemplates2.pro (limited to 'src/quicktemplates2') diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp new file mode 100644 index 00000000..2a462c03 --- /dev/null +++ b/src/quicktemplates2/qquickabstractbutton.cpp @@ -0,0 +1,621 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickabstractbutton_p.h" +#include "qquickabstractbutton_p_p.h" +#include "qquickbuttongroup_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// copied from qabstractbutton.cpp +static const int AUTO_REPEAT_DELAY = 300; +static const int AUTO_REPEAT_INTERVAL = 100; + +/*! + \qmltype AbstractButton + \inherits Control + \instantiates QQuickAbstractButton + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-buttons + \brief Base type of all button controls. + + AbstractButton provides the interface for controls with button-like + behavior; for example, push buttons and checkable controls like + radio buttons and check boxes. As an abstract control, it has no delegate + implementations, leaving them to the types that derive from it. + + TODO: ButtonGroup usage + + \labs +*/ + +/*! + \qmlsignal Qt.labs.controls::AbstractButton::pressed() + + This signal is emitted when the button is interactively pressed by the user. +*/ + +/*! + \qmlsignal Qt.labs.controls::AbstractButton::released() + + This signal is emitted when the button is interactively released by the user. +*/ + +/*! + \qmlsignal Qt.labs.controls::AbstractButton::canceled() + + This signal is emitted when the button loses mouse grab + while being pressed, or when it would emit the \l released + signal but the mouse cursor is not inside the button. +*/ + +/*! + \qmlsignal Qt.labs.controls::AbstractButton::clicked() + + This signal is emitted when the button is interactively clicked by the user. +*/ + +/*! + \qmlsignal Qt.labs.controls::AbstractButton::pressAndHold() + + This signal is emitted when the button is interactively perssed and held down by the user. +*/ + +/*! + \qmlsignal Qt.labs.controls::AbstractButton::doubleClicked() + + This signal is emitted when the button is interactively double clicked by the user. +*/ + +QQuickAbstractButtonPrivate::QQuickAbstractButtonPrivate() : + pressed(false), checked(false), checkable(false), highlighted(false), autoExclusive(false), autoRepeat(false), wasHeld(false), + holdTimer(0), delayTimer(0), repeatTimer(0), repeatButton(Qt::NoButton), indicator(nullptr), group(nullptr) +{ +} + +bool QQuickAbstractButtonPrivate::isPressAndHoldConnected() +{ + Q_Q(QQuickAbstractButton); + IS_SIGNAL_CONNECTED(q, QQuickAbstractButton, pressAndHold, ()); +} + +void QQuickAbstractButtonPrivate::startPressAndHold() +{ + Q_Q(QQuickAbstractButton); + wasHeld = false; + stopPressAndHold(); + if (isPressAndHoldConnected()) + holdTimer = q->startTimer(QGuiApplication::styleHints()->mousePressAndHoldInterval()); +} + +void QQuickAbstractButtonPrivate::stopPressAndHold() +{ + Q_Q(QQuickAbstractButton); + if (holdTimer > 0) { + q->killTimer(holdTimer); + holdTimer = 0; + } +} + +void QQuickAbstractButtonPrivate::startRepeatDelay() +{ + Q_Q(QQuickAbstractButton); + stopPressRepeat(); + delayTimer = q->startTimer(AUTO_REPEAT_DELAY); +} + +void QQuickAbstractButtonPrivate::startPressRepeat() +{ + Q_Q(QQuickAbstractButton); + stopPressRepeat(); + repeatTimer = q->startTimer(AUTO_REPEAT_INTERVAL); +} + +void QQuickAbstractButtonPrivate::stopPressRepeat() +{ + Q_Q(QQuickAbstractButton); + if (delayTimer > 0) { + q->killTimer(delayTimer); + delayTimer = 0; + } + if (repeatTimer > 0) { + q->killTimer(repeatTimer); + repeatTimer = 0; + } +} + +QQuickAbstractButton *QQuickAbstractButtonPrivate::findCheckedButton() const +{ + Q_Q(const QQuickAbstractButton); + if (group) + return qobject_cast(group->checkedButton()); + + const QList buttons = findExclusiveButtons(); + // TODO: A singular QRadioButton can be unchecked, which seems logical, + // because there's nothing to be exclusive with. However, a RadioButton + // from QtQuick.Controls 1.x can never be unchecked, which is the behavior + // that QQuickRadioButton adopted. Uncommenting the following count check + // gives the QRadioButton behavior. Notice that tst_radiobutton.qml needs + // to be updated. + if (!autoExclusive /*|| buttons.count() == 1*/) + return nullptr; + + for (QQuickAbstractButton *button : buttons) { + if (button->isChecked() && button != q) + return button; + } + return checked ? const_cast(q) : nullptr; +} + +QList QQuickAbstractButtonPrivate::findExclusiveButtons() const +{ + QList buttons; + if (group) { + QQmlListProperty groupButtons = group->buttons(); + int count = groupButtons.count(&groupButtons); + for (int i = 0; i < count; ++i) { + QQuickAbstractButton *button = qobject_cast(groupButtons.at(&groupButtons, i)); + if (button) + buttons += button; + } + } else if (parentItem) { + const auto childItems = parentItem->childItems(); + for (QQuickItem *child : childItems) { + QQuickAbstractButton *button = qobject_cast(child); + if (button && button->autoExclusive() && !QQuickAbstractButtonPrivate::get(button)->group) + buttons += button; + } + } + return buttons; +} + +QQuickAbstractButton::QQuickAbstractButton(QQuickItem *parent) : + QQuickControl(*(new QQuickAbstractButtonPrivate), parent) +{ + setActiveFocusOnTab(true); + setAcceptedMouseButtons(Qt::LeftButton); +} + +QQuickAbstractButton::QQuickAbstractButton(QQuickAbstractButtonPrivate &dd, QQuickItem *parent) : + QQuickControl(dd, parent) +{ + setActiveFocusOnTab(true); + setAcceptedMouseButtons(Qt::LeftButton); +} + +QQuickAbstractButton::~QQuickAbstractButton() +{ + Q_D(QQuickAbstractButton); + if (d->group) + d->group->removeButton(this); +} + +/*! + \qmlproperty string Qt.labs.controls::AbstractButton::text + + This property holds a textual description of the button. + + \note The text is used for accessibility purposes, so it makes sense to + set a textual description even if the content item is an image. + + \sa {Control::contentItem}{contentItem} +*/ +QString QQuickAbstractButton::text() const +{ + Q_D(const QQuickAbstractButton); + return d->text; +} + +void QQuickAbstractButton::setText(const QString &text) +{ + Q_D(QQuickAbstractButton); + if (d->text == text) + return; + + d->text = text; + setAccessibleName(text); + emit textChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::AbstractButton::pressed + + This property holds whether the button is pressed. +*/ +bool QQuickAbstractButton::isPressed() const +{ + Q_D(const QQuickAbstractButton); + return d->pressed; +} + +void QQuickAbstractButton::setPressed(bool isPressed) +{ + Q_D(QQuickAbstractButton); + if (d->pressed == isPressed) + return; + + d->pressed = isPressed; + setAccessibleProperty("pressed", isPressed); + emit pressedChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::AbstractButton::checked + + This property holds whether the button is checked. +*/ +bool QQuickAbstractButton::isChecked() const +{ + Q_D(const QQuickAbstractButton); + return d->checked; +} + +void QQuickAbstractButton::setChecked(bool checked) +{ + Q_D(QQuickAbstractButton); + if (d->checked == checked) + return; + + if (checked && !d->checkable) + setCheckable(true); + + d->checked = checked; + setAccessibleProperty("checked", checked); + checkStateSet(); + emit checkedChanged(); +} + +// We define these in QQuickAbstractButton without exposing checkable as a +// property, and instead expose it as a property in QQuickButton. +// QQuickRadioButton, QQuickSwitch and QQuickCheckBox are checkable by default, +// but if we removed the checkable code from here, they'd each have to +// duplicate it. +bool QQuickAbstractButton::isCheckable() const +{ + Q_D(const QQuickAbstractButton); + return d->checkable; +} + +void QQuickAbstractButton::setCheckable(bool checkable) +{ + Q_D(QQuickAbstractButton); + if (d->checkable == checkable) + return; + + d->checkable = checkable; + setAccessibleProperty("checkable", checkable); + checkableChange(); +} + +/*! + \qmlproperty bool Qt.labs.controls::AbstractButton::highlighted + + This property holds whether the button is highlighted. + + A button can be highlighted in order to draw the user's attention towards + it. It has no effect on keyboard interaction. + + The default value is \c false. +*/ +bool QQuickAbstractButton::isHighlighted() const +{ + Q_D(const QQuickAbstractButton); + return d->highlighted; +} + +void QQuickAbstractButton::setHighlighted(bool highlighted) +{ + Q_D(QQuickAbstractButton); + if (highlighted == d->highlighted) + return; + + d->highlighted = highlighted; + emit highlightedChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::AbstractButton::autoExclusive + + This property holds whether auto-exclusivity is enabled. + + If auto-exclusivity is enabled, checkable buttons that belong to the same + parent item behave as if they were part of the same ButtonGroup. Only + one button can be checked at any time; checking another button automatically + unchecks the previously checked one. + + \note The property has no effect on buttons that belong to an ButtonGroup. + + RadioButton and TabButton are auto-exclusive by default. +*/ +bool QQuickAbstractButton::autoExclusive() const +{ + Q_D(const QQuickAbstractButton); + return d->autoExclusive; +} + +void QQuickAbstractButton::setAutoExclusive(bool exclusive) +{ + Q_D(QQuickAbstractButton); + if (d->autoExclusive == exclusive) + return; + + d->autoExclusive = exclusive; + emit autoExclusiveChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::AbstractButton::autoRepeat + + This property holds whether the button repeats pressed(), released() + and clicked() signals while the button is pressed and held down. + + The default value is \c false. +*/ +bool QQuickAbstractButton::autoRepeat() const +{ + Q_D(const QQuickAbstractButton); + return d->autoRepeat; +} + +void QQuickAbstractButton::setAutoRepeat(bool repeat) +{ + Q_D(QQuickAbstractButton); + if (d->autoRepeat == repeat) + return; + + d->stopPressRepeat(); + d->autoRepeat = repeat; + emit autoRepeatChanged(); +} + +/*! + \qmlproperty Item Qt.labs.controls::AbstractButton::indicator + + This property holds the indicator item. +*/ +QQuickItem *QQuickAbstractButton::indicator() const +{ + Q_D(const QQuickAbstractButton); + return d->indicator; +} + +void QQuickAbstractButton::setIndicator(QQuickItem *indicator) +{ + Q_D(QQuickAbstractButton); + if (d->indicator == indicator) + return; + + delete d->indicator; + d->indicator = indicator; + if (indicator) { + if (!indicator->parentItem()) + indicator->setParentItem(this); + indicator->setAcceptedMouseButtons(Qt::LeftButton); + } + emit indicatorChanged(); +} + +/*! + \qmlmethod void Qt.labs.controls::Button::toggle() + + Toggles the checked state of the button. +*/ +void QQuickAbstractButton::toggle() +{ + Q_D(QQuickAbstractButton); + setChecked(!d->checked); +} + +void QQuickAbstractButton::focusOutEvent(QFocusEvent *event) +{ + Q_D(QQuickAbstractButton); + QQuickControl::focusOutEvent(event); + if (d->pressed) { + setPressed(false); + emit canceled(); + } +} + +void QQuickAbstractButton::keyPressEvent(QKeyEvent *event) +{ + Q_D(QQuickAbstractButton); + QQuickControl::keyPressEvent(event); + if (event->key() == Qt::Key_Space) { + setPressed(true); + d->pressPoint = QPoint(qRound(width() / 2), qRound(height() / 2)); + + if (d->autoRepeat) { + d->startRepeatDelay(); + d->repeatButton = Qt::NoButton; + } + + emit pressed(); + } +} + +void QQuickAbstractButton::keyReleaseEvent(QKeyEvent *event) +{ + Q_D(QQuickAbstractButton); + QQuickControl::keyReleaseEvent(event); + if (event->key() == Qt::Key_Space) { + setPressed(false); + + nextCheckState(); + emit released(); + emit clicked(); + + if (d->autoRepeat) + d->stopPressRepeat(); + } +} + +void QQuickAbstractButton::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickAbstractButton); + QQuickControl::mousePressEvent(event); + setPressed(true); + d->pressPoint = event->pos(); + + emit pressed(); + + if (d->autoRepeat) { + d->startRepeatDelay(); + d->repeatButton = event->button(); + } else if (Qt::LeftButton == (event->buttons() & Qt::LeftButton)) { + d->startPressAndHold(); + } else { + d->stopPressAndHold(); + } +} + +void QQuickAbstractButton::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickAbstractButton); + QQuickControl::mouseMoveEvent(event); + setPressed(contains(event->pos())); + + if (d->autoRepeat) + d->stopPressRepeat(); + else if (d->holdTimer > 0 && (!d->pressed || QLineF(d->pressPoint, event->localPos()).length() > QGuiApplication::styleHints()->startDragDistance())) + d->stopPressAndHold(); +} + +void QQuickAbstractButton::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickAbstractButton); + QQuickControl::mouseReleaseEvent(event); + bool wasPressed = d->pressed; + setPressed(false); + + if (contains(event->pos())) + nextCheckState(); + + if (wasPressed) { + emit released(); + if (!d->wasHeld) + emit clicked(); + } else { + emit canceled(); + } + + if (d->autoRepeat) + d->stopPressRepeat(); + else + d->stopPressAndHold(); +} + +void QQuickAbstractButton::mouseDoubleClickEvent(QMouseEvent *event) +{ + QQuickControl::mouseDoubleClickEvent(event); + emit doubleClicked(); +} + +void QQuickAbstractButton::mouseUngrabEvent() +{ + Q_D(QQuickAbstractButton); + QQuickControl::mouseUngrabEvent(); + if (d->pressed) { + setPressed(false); + d->stopPressRepeat(); + d->stopPressAndHold(); + emit canceled(); + } +} + +void QQuickAbstractButton::timerEvent(QTimerEvent *event) +{ + Q_D(QQuickAbstractButton); + QQuickControl::timerEvent(event); + if (event->timerId() == d->holdTimer) { + d->stopPressAndHold(); + d->wasHeld = true; + emit pressAndHold(); + } else if (event->timerId() == d->delayTimer) { + d->startPressRepeat(); + } else if (event->timerId() == d->repeatTimer) { + emit released(); + emit clicked(); + emit pressed(); + } +} + +void QQuickAbstractButton::checkStateSet() +{ + Q_D(QQuickAbstractButton); + if (d->checked) { + QQuickAbstractButton *button = d->findCheckedButton(); + if (button && button != this) + button->setChecked(false); + } +} + +void QQuickAbstractButton::nextCheckState() +{ + Q_D(QQuickAbstractButton); + if (d->checkable && (!d->checked || d->findCheckedButton() != this)) + setChecked(!d->checked); +} + +void QQuickAbstractButton::checkableChange() +{ +} + +#ifndef QT_NO_ACCESSIBILITY +void QQuickAbstractButton::accessibilityActiveChanged(bool active) +{ + QQuickControl::accessibilityActiveChanged(active); + + Q_D(QQuickAbstractButton); + if (active) { + setAccessibleName(d->text); + setAccessibleProperty("pressed", d->pressed); + setAccessibleProperty("checked", d->checked); + setAccessibleProperty("checkable", d->checkable); + } +} + +QAccessible::Role QQuickAbstractButton::accessibleRole() const +{ + return QAccessible::Button; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickabstractbutton_p.h b/src/quicktemplates2/qquickabstractbutton_p.h new file mode 100644 index 00000000..79f9b92e --- /dev/null +++ b/src/quicktemplates2/qquickabstractbutton_p.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKABSTRACTBUTTON_P_H +#define QQUICKABSTRACTBUTTON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickAbstractButtonPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickAbstractButton : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL) + Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL) + Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY checkedChanged FINAL) + Q_PROPERTY(bool highlighted READ isHighlighted WRITE setHighlighted NOTIFY highlightedChanged FINAL) + Q_PROPERTY(bool autoExclusive READ autoExclusive WRITE setAutoExclusive NOTIFY autoExclusiveChanged FINAL) + Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY autoRepeatChanged FINAL) + Q_PROPERTY(QQuickItem *indicator READ indicator WRITE setIndicator NOTIFY indicatorChanged FINAL) + +public: + explicit QQuickAbstractButton(QQuickItem *parent = nullptr); + ~QQuickAbstractButton(); + + QString text() const; + void setText(const QString &text); + + bool isPressed() const; + void setPressed(bool pressed); + + bool isChecked() const; + void setChecked(bool checked); + + bool isCheckable() const; + void setCheckable(bool checkable); + + bool isHighlighted() const; + void setHighlighted(bool highlighted); + + bool autoExclusive() const; + void setAutoExclusive(bool exclusive); + + bool autoRepeat() const; + void setAutoRepeat(bool repeat); + + QQuickItem *indicator() const; + void setIndicator(QQuickItem *indicator); + +public Q_SLOTS: + void toggle(); + +Q_SIGNALS: + void pressed(); + void released(); + void canceled(); + void clicked(); + void pressAndHold(); + void doubleClicked(); + void textChanged(); + void pressedChanged(); + void checkedChanged(); + void highlightedChanged(); + void autoExclusiveChanged(); + void autoRepeatChanged(); + void indicatorChanged(); + +protected: + QQuickAbstractButton(QQuickAbstractButtonPrivate &dd, QQuickItem *parent); + + void focusOutEvent(QFocusEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + void mouseUngrabEvent() override; + void timerEvent(QTimerEvent *event) override; + + virtual void checkStateSet(); + virtual void nextCheckState(); + + virtual void checkableChange(); + +#ifndef QT_NO_ACCESSIBILITY + void accessibilityActiveChanged(bool active) override; + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickAbstractButton) + Q_DECLARE_PRIVATE(QQuickAbstractButton) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickAbstractButton) + +#endif // QQUICKABSTRACTBUTTON_P_H diff --git a/src/quicktemplates2/qquickabstractbutton_p_p.h b/src/quicktemplates2/qquickabstractbutton_p_p.h new file mode 100644 index 00000000..62112e07 --- /dev/null +++ b/src/quicktemplates2/qquickabstractbutton_p_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKABSTRACTBUTTON_P_P_H +#define QQUICKABSTRACTBUTTON_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickButtonGroup; + +class QQuickAbstractButtonPrivate : public QQuickControlPrivate +{ + Q_DECLARE_PUBLIC(QQuickAbstractButton) + +public: + QQuickAbstractButtonPrivate(); + + static QQuickAbstractButtonPrivate *get(QQuickAbstractButton *button) + { + return button->d_func(); + } + + bool isPressAndHoldConnected(); + void startPressAndHold(); + void stopPressAndHold(); + + void startRepeatDelay(); + void startPressRepeat(); + void stopPressRepeat(); + + QQuickAbstractButton *findCheckedButton() const; + QList findExclusiveButtons() const; + + QString text; + bool pressed; + bool checked; + bool checkable; + bool highlighted; + bool autoExclusive; + bool autoRepeat; + bool wasHeld; + int holdTimer; + int delayTimer; + int repeatTimer; + QPointF pressPoint; + Qt::MouseButton repeatButton; + QQuickItem *indicator; + QQuickButtonGroup *group; +}; + +QT_END_NAMESPACE + +#endif // QQUICKABSTRACTBUTTON_P_P_H diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp b/src/quicktemplates2/qquickapplicationwindow.cpp new file mode 100644 index 00000000..d9a0097b --- /dev/null +++ b/src/quicktemplates2/qquickapplicationwindow.cpp @@ -0,0 +1,747 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickapplicationwindow_p.h" +#include "qquickoverlay_p.h" +#include "qquickpopup_p.h" +#include "qquickcontrol_p_p.h" +#include "qquicktextarea_p.h" +#include "qquicktextfield_p.h" +#include "qquicktoolbar_p.h" +#include "qquicktabbar_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ApplicationWindow + \inherits Window + \instantiates QQuickApplicationWindow + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-containers + \brief Provides a top-level application window. + + ApplicationWindow is a \l Window which makes it convenient to add + a \l header and \l footer item to the window. + + You can declare ApplicationWindow as the root item of your application, + and run it by using \l QQmlApplicationEngine. In this way you can control + the window's properties, appearance and layout from QML. + + \image qtquickcontrols-applicationwindow-wireframe.png + + \qml + import Qt.labs.controls 1.0 + + ApplicationWindow { + visible: true + + header: ToolBar { + // ... + } + + footer: TabBar { + // ... + } + + StackView { + anchors.fill: parent + } + } + \endqml + + ApplicationWindow supports popups via its \l overlay property, which + ensures that popups are displayed above other content and that the + background is dimmed when a modal popup is visible. + + \note By default, an ApplicationWindow is not visible. + + \labs + + \sa Page, {Container Controls} +*/ + +class QQuickApplicationWindowPrivate : public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickApplicationWindow) + +public: + QQuickApplicationWindowPrivate() + : complete(false) + , background(nullptr) + , contentItem(nullptr) + , header(nullptr) + , footer(nullptr) + , overlay(nullptr) + , activeFocusControl(nullptr) + { } + + void relayout(); + + void itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect) override; + void itemVisibilityChanged(QQuickItem *item) override; + void itemImplicitWidthChanged(QQuickItem *item) override; + void itemImplicitHeightChanged(QQuickItem *item) override; + + void updateFont(const QFont &f); + inline void setFont_helper(const QFont &f) { + if (font.resolve() == f.resolve() && font == f) + return; + updateFont(f); + } + void resolveFont(); + + void _q_updateActiveFocus(); + void setActiveFocusControl(QQuickItem *item); + + bool complete; + QQuickItem *background; + QQuickItem *contentItem; + QQuickItem *header; + QQuickItem *footer; + QQuickOverlay *overlay; + QFont font; + QLocale locale; + QQuickItem *activeFocusControl; + QQuickApplicationWindow *q_ptr; +}; + +void QQuickApplicationWindowPrivate::relayout() +{ + Q_Q(QQuickApplicationWindow); + QQuickItem *content = q->contentItem(); + qreal hh = header ? header->height() : 0; + qreal fh = footer ? footer->height() : 0; + + content->setY(hh); + content->setWidth(q->width()); + content->setHeight(q->height() - hh - fh); + + if (overlay) { + overlay->setWidth(q->width()); + overlay->setHeight(q->height()); + overlay->stackAfter(content); + } + + if (header) { + header->setY(-hh); + QQuickItemPrivate *p = QQuickItemPrivate::get(header); + if (!p->widthValid) { + header->setWidth(q->width()); + p->widthValid = false; + } + } + + if (footer) { + footer->setY(content->height()); + QQuickItemPrivate *p = QQuickItemPrivate::get(footer); + if (!p->widthValid) { + footer->setWidth(q->width()); + p->widthValid = false; + } + } + + if (background) { + QQuickItemPrivate *p = QQuickItemPrivate::get(background); + if (!p->widthValid && qFuzzyIsNull(background->x())) { + background->setWidth(q->width()); + p->widthValid = false; + } + if (!p->heightValid && qFuzzyIsNull(background->y())) { + background->setHeight(q->height()); + p->heightValid = false; + } + } +} + +void QQuickApplicationWindowPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect) +{ + Q_UNUSED(item) + Q_UNUSED(newRect) + Q_UNUSED(oldRect) + relayout(); +} + +void QQuickApplicationWindowPrivate::itemVisibilityChanged(QQuickItem *item) +{ + Q_UNUSED(item); + relayout(); +} + +void QQuickApplicationWindowPrivate::itemImplicitWidthChanged(QQuickItem *item) +{ + Q_UNUSED(item); + relayout(); +} + +void QQuickApplicationWindowPrivate::itemImplicitHeightChanged(QQuickItem *item) +{ + Q_UNUSED(item); + relayout(); +} + +void QQuickApplicationWindowPrivate::_q_updateActiveFocus() +{ + Q_Q(QQuickApplicationWindow); + QQuickItem *item = q->activeFocusItem(); + while (item) { + QQuickControl *control = qobject_cast(item); + if (control) { + setActiveFocusControl(control); + break; + } + QQuickTextField *textField = qobject_cast(item); + if (textField) { + setActiveFocusControl(textField); + break; + } + QQuickTextArea *textArea = qobject_cast(item); + if (textArea) { + setActiveFocusControl(textArea); + break; + } + item = item->parentItem(); + } +} + +void QQuickApplicationWindowPrivate::setActiveFocusControl(QQuickItem *control) +{ + Q_Q(QQuickApplicationWindow); + if (activeFocusControl != control) { + activeFocusControl = control; + emit q->activeFocusControlChanged(); + } +} + +QQuickApplicationWindow::QQuickApplicationWindow(QWindow *parent) : + QQuickWindowQmlImpl(parent), d_ptr(new QQuickApplicationWindowPrivate) +{ + d_ptr->q_ptr = this; + connect(this, SIGNAL(activeFocusItemChanged()), this, SLOT(_q_updateActiveFocus())); +} + +QQuickApplicationWindow::~QQuickApplicationWindow() +{ + Q_D(QQuickApplicationWindow); + if (d->header) + QQuickItemPrivate::get(d->header)->removeItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | + QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight); + if (d->footer) + QQuickItemPrivate::get(d->footer)->removeItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | + QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight); +} + +/*! + \qmlproperty Item Qt.labs.controls::ApplicationWindow::background + + This property holds the background item. + + The background item is stacked under the \l {contentItem}{content item}, + but above the \l {Window::color}{background color} of the window. + + \note If the background item has no explicit size specified, it automatically + follows the control's size. In most cases, there is no need to specify + width or height for a background item. +*/ +QQuickItem *QQuickApplicationWindow::background() const +{ + Q_D(const QQuickApplicationWindow); + return d->background; +} + +void QQuickApplicationWindow::setBackground(QQuickItem *background) +{ + Q_D(QQuickApplicationWindow); + if (d->background == background) + return; + + delete d->background; + d->background = background; + if (background) { + background->setParentItem(QQuickWindow::contentItem()); + if (qFuzzyIsNull(background->z())) + background->setZ(-1); + if (isComponentComplete()) + d->relayout(); + } + emit backgroundChanged(); +} + +/*! + \qmlproperty Item Qt.labs.controls::ApplicationWindow::header + + This property holds the window header item. The header item is positioned to + the top, and resized to the width of the window. The default value is \c null. + + \note Assigning a ToolBar or TabBar as a window header sets the respective + \l ToolBar::position or \l TabBar::position property automatically to \c Header. + + \sa footer, Page::header +*/ +QQuickItem *QQuickApplicationWindow::header() const +{ + Q_D(const QQuickApplicationWindow); + return d->header; +} + +void QQuickApplicationWindow::setHeader(QQuickItem *header) +{ + Q_D(QQuickApplicationWindow); + if (d->header == header) + return; + + if (d->header) { + QQuickItemPrivate::get(d->header)->removeItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | + QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight); + d->header->setParentItem(nullptr); + } + d->header = header; + if (header) { + header->setParentItem(contentItem()); + QQuickItemPrivate *p = QQuickItemPrivate::get(header); + p->addItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | + QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight); + if (qFuzzyIsNull(header->z())) + header->setZ(1); + if (QQuickToolBar *toolBar = qobject_cast(header)) + toolBar->setPosition(QQuickToolBar::Header); + else if (QQuickTabBar *tabBar = qobject_cast(header)) + tabBar->setPosition(QQuickTabBar::Header); + } + if (isComponentComplete()) + d->relayout(); + emit headerChanged(); +} + +/*! + \qmlproperty Item Qt.labs.controls::ApplicationWindow::footer + + This property holds the window footer item. The footer item is positioned to + the bottom, and resized to the width of the window. The default value is \c null. + + \note Assigning a ToolBar or TabBar as a window footer sets the respective + \l ToolBar::position or \l TabBar::position property automatically to \c Footer. + + \sa header, Page::footer +*/ +QQuickItem *QQuickApplicationWindow::footer() const +{ + Q_D(const QQuickApplicationWindow); + return d->footer; +} + +void QQuickApplicationWindow::setFooter(QQuickItem *footer) +{ + Q_D(QQuickApplicationWindow); + if (d->footer == footer) + return; + + if (d->footer) { + QQuickItemPrivate::get(d->footer)->removeItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | + QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight); + d->footer->setParentItem(nullptr); + } + d->footer = footer; + if (footer) { + footer->setParentItem(contentItem()); + QQuickItemPrivate *p = QQuickItemPrivate::get(footer); + p->addItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | + QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight); + if (qFuzzyIsNull(footer->z())) + footer->setZ(1); + if (QQuickToolBar *toolBar = qobject_cast(footer)) + toolBar->setPosition(QQuickToolBar::Footer); + else if (QQuickTabBar *tabBar = qobject_cast(footer)) + tabBar->setPosition(QQuickTabBar::Footer); + } + if (isComponentComplete()) + d->relayout(); + emit footerChanged(); +} + +/*! + \qmlproperty list Qt.labs.controls::ApplicationWindow::contentData + \default + + This default property holds the list of all objects declared as children of + the window. + + \sa contentItem +*/ +QQmlListProperty QQuickApplicationWindow::contentData() +{ + return QQuickItemPrivate::get(contentItem())->data(); +} + +/*! + \qmlproperty Item Qt.labs.controls::ApplicationWindow::contentItem + \readonly + + This property holds the window content item. +*/ +QQuickItem *QQuickApplicationWindow::contentItem() const +{ + QQuickApplicationWindowPrivate *d = const_cast(d_func()); + if (!d->contentItem) { + d->contentItem = new QQuickItem(QQuickWindow::contentItem()); + d->relayout(); + } + return d->contentItem; +} + +/*! + \qmlproperty Control Qt.labs.controls::ApplicationWindow::activeFocusControl + \readonly + + This property holds the control that currently has active focus, or \c null if there is + no control with active focus. + + The difference between \l Window::activeFocusItem and ApplicationWindow::activeFocusControl + is that the former may point to a building block of a control, whereas the latter points + to the enclosing control. For example, when SpinBox has focus, activeFocusItem points to + the editor and acticeFocusControl to the SpinBox itself. + + \sa Window::activeFocusItem +*/ +QQuickItem *QQuickApplicationWindow::activeFocusControl() const +{ + Q_D(const QQuickApplicationWindow); + return d->activeFocusControl; +} + +/*! + \qmlpropertygroup Qt.labs.controls::ApplicationWindow::overlay + \qmlproperty Item Qt.labs.controls::ApplicationWindow::overlay + \qmlproperty Item Qt.labs.controls::ApplicationWindow::overlay.background + + This property holds the window overlay item and its background that implements the + background dimming when any modal popups are open. Popups are automatically + reparented to the overlay. + + \sa Popup +*/ +QQuickOverlay *QQuickApplicationWindow::overlay() const +{ + QQuickApplicationWindowPrivate *d = const_cast(d_func()); + if (!d->overlay) { + d->overlay = new QQuickOverlay(QQuickWindow::contentItem()); + d->relayout(); + } + return d->overlay; +} + +/*! + \qmlproperty font Qt.labs.controls::ApplicationWindow::font + + This property holds the font currently set for the window. + + The default font depends on the system environment. QGuiApplication maintains a system/theme + font which serves as a default for all application windows. You can also set the default font + for windows by passing a custom font to QGuiApplication::setFont(), before loading any QML. + Finally, the font is matched against Qt's font database to find the best match. + + ApplicationWindow propagates explicit font properties to child controls. If you change a specific + property on the window's font, that property propagates to all child controls in the window, + overriding any system defaults for that property. + + \sa Control::font +*/ +QFont QQuickApplicationWindow::font() const +{ + Q_D(const QQuickApplicationWindow); + return d->font; +} + +void QQuickApplicationWindow::setFont(const QFont &font) +{ + Q_D(QQuickApplicationWindow); + if (d->font.resolve() == font.resolve() && d->font == font) + return; + + QFont resolvedFont = font.resolve(QQuickControlPrivate::themeFont(QPlatformTheme::SystemFont)); + d->setFont_helper(resolvedFont); +} + +void QQuickApplicationWindow::resetFont() +{ + setFont(QFont()); +} + +void QQuickApplicationWindowPrivate::resolveFont() +{ + QFont resolvedFont = font.resolve(QQuickControlPrivate::themeFont(QPlatformTheme::SystemFont)); + setFont_helper(resolvedFont); +} + +void QQuickApplicationWindowPrivate::updateFont(const QFont &f) +{ + Q_Q(QQuickApplicationWindow); + const bool changed = font != f; + font = f; + + QQuickControlPrivate::updateFontRecur(q->QQuickWindow::contentItem(), f); + + // TODO: internal QQuickPopupManager that provides reliable access to all QQuickPopup instances + const QList popups = q->findChildren(); + for (QQuickPopup *popup : popups) + QQuickControlPrivate::get(static_cast(popup->popupItem()))->inheritFont(f); + + if (changed) + emit q->fontChanged(); +} + +QLocale QQuickApplicationWindow::locale() const +{ + Q_D(const QQuickApplicationWindow); + return d->locale; +} + +void QQuickApplicationWindow::setLocale(const QLocale &locale) +{ + Q_D(QQuickApplicationWindow); + if (d->locale == locale) + return; + + d->locale = locale; + QQuickControlPrivate::updateLocaleRecur(QQuickWindow::contentItem(), locale); + + // TODO: internal QQuickPopupManager that provides reliable access to all QQuickPopup instances + const QList popups = QQuickWindow::contentItem()->findChildren(); + for (QQuickPopup *popup : popups) + QQuickControlPrivate::get(static_cast(popup->popupItem()))->updateLocale(locale, false); // explicit=false + + emit localeChanged(); +} + +void QQuickApplicationWindow::resetLocale() +{ + setLocale(QLocale()); +} + +QQuickApplicationWindowAttached *QQuickApplicationWindow::qmlAttachedProperties(QObject *object) +{ + return new QQuickApplicationWindowAttached(object); +} + +bool QQuickApplicationWindow::isComponentComplete() const +{ + Q_D(const QQuickApplicationWindow); + return d->complete; +} + +void QQuickApplicationWindow::classBegin() +{ + Q_D(QQuickApplicationWindow); + QQuickWindowQmlImpl::classBegin(); + d->resolveFont(); +} + +void QQuickApplicationWindow::componentComplete() +{ + Q_D(QQuickApplicationWindow); + d->complete = true; + QQuickWindowQmlImpl::componentComplete(); +} + +void QQuickApplicationWindow::resizeEvent(QResizeEvent *event) +{ + Q_D(QQuickApplicationWindow); + QQuickWindowQmlImpl::resizeEvent(event); + d->relayout(); +} + +class QQuickApplicationWindowAttachedPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QQuickApplicationWindowAttached) + +public: + QQuickApplicationWindowAttachedPrivate() : window(nullptr) { } + + void windowChange(QQuickWindow *wnd); + + QQuickApplicationWindow *window; +}; + +void QQuickApplicationWindowAttachedPrivate::windowChange(QQuickWindow *wnd) +{ + Q_Q(QQuickApplicationWindowAttached); + QQuickApplicationWindow *newWindow = qobject_cast(wnd); + if (window != newWindow) { + QQuickApplicationWindow *oldWindow = window; + if (oldWindow) { + QObject::disconnect(oldWindow, &QQuickApplicationWindow::activeFocusControlChanged, + q, &QQuickApplicationWindowAttached::activeFocusControlChanged); + QObject::disconnect(oldWindow, &QQuickApplicationWindow::headerChanged, + q, &QQuickApplicationWindowAttached::headerChanged); + QObject::disconnect(oldWindow, &QQuickApplicationWindow::footerChanged, + q, &QQuickApplicationWindowAttached::footerChanged); + } + if (newWindow) { + QObject::connect(newWindow, &QQuickApplicationWindow::activeFocusControlChanged, + q, &QQuickApplicationWindowAttached::activeFocusControlChanged); + QObject::connect(newWindow, &QQuickApplicationWindow::headerChanged, + q, &QQuickApplicationWindowAttached::headerChanged); + QObject::connect(newWindow, &QQuickApplicationWindow::footerChanged, + q, &QQuickApplicationWindowAttached::footerChanged); + } + + window = newWindow; + emit q->windowChanged(); + emit q->contentItemChanged(); + emit q->overlayChanged(); + + if ((oldWindow && oldWindow->activeFocusControl()) || (newWindow && newWindow->activeFocusControl())) + emit q->activeFocusControlChanged(); + if ((oldWindow && oldWindow->header()) || (newWindow && newWindow->header())) + emit q->headerChanged(); + if ((oldWindow && oldWindow->footer()) || (newWindow && newWindow->footer())) + emit q->footerChanged(); + } +} + +QQuickApplicationWindowAttached::QQuickApplicationWindowAttached(QObject *parent) + : QObject(*(new QQuickApplicationWindowAttachedPrivate), parent) +{ + Q_D(QQuickApplicationWindowAttached); + if (QQuickItem *item = qobject_cast(parent)) { + d->windowChange(item->window()); + QObjectPrivate::connect(item, &QQuickItem::windowChanged, d, &QQuickApplicationWindowAttachedPrivate::windowChange); + if (!d->window) { + QQuickItem *p = item; + while (p) { + if (QQuickPopup *popup = qobject_cast(p->parent())) { + d->windowChange(popup->window()); + QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickApplicationWindowAttachedPrivate::windowChange); + } + p = p->parentItem(); + } + } + } else if (QQuickPopup *popup = qobject_cast(parent)) { + d->windowChange(popup->window()); + QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickApplicationWindowAttachedPrivate::windowChange); + } +} + +/*! + \qmlattachedproperty ApplicationWindow Qt.labs.controls::ApplicationWindow::window + \readonly + + This attached property holds the application window. The property can be attached + to any item. The value is \c null if the item is not in an ApplicationWindow. +*/ +QQuickApplicationWindow *QQuickApplicationWindowAttached::window() const +{ + Q_D(const QQuickApplicationWindowAttached); + return d->window; +} + +/*! + \qmlattachedproperty Item Qt.labs.controls::ApplicationWindow::contentItem + \readonly + + This attached property holds the window content item. The property can be attached + to any item. The value is \c null if the item is not in an ApplicationWindow. +*/ +QQuickItem *QQuickApplicationWindowAttached::contentItem() const +{ + Q_D(const QQuickApplicationWindowAttached); + return d->window ? d->window->contentItem() : nullptr; +} + +/*! + \qmlattachedproperty Control Qt.labs.controls::ApplicationWindow::activeFocusControl + \readonly + + This attached property holds the control that currently has active focus, or \c null + if there is no control with active focus. The property can be attached to any item. + The value is \c null if the item is not in an ApplicationWindow, or the window has + no active focus. + + \sa Window::activeFocusItem +*/ +QQuickItem *QQuickApplicationWindowAttached::activeFocusControl() const +{ + Q_D(const QQuickApplicationWindowAttached); + return d->window ? d->window->activeFocusControl() : nullptr; +} + +/*! + \qmlattachedproperty Item Qt.labs.controls::ApplicationWindow::header + \readonly + + This attached property holds the window header item. The property can be attached + to any item. The value is \c null if the item is not in an ApplicationWindow, or + the window has no header item. +*/ +QQuickItem *QQuickApplicationWindowAttached::header() const +{ + Q_D(const QQuickApplicationWindowAttached); + return d->window ? d->window->header() : nullptr; +} + +/*! + \qmlattachedproperty Item Qt.labs.controls::ApplicationWindow::footer + \readonly + + This attached property holds the window footer item. The property can be attached + to any item. The value is \c null if the item is not in an ApplicationWindow, or + the window has no footer item. +*/ +QQuickItem *QQuickApplicationWindowAttached::footer() const +{ + Q_D(const QQuickApplicationWindowAttached); + return d->window ? d->window->footer() : nullptr; +} + +/*! + \qmlattachedproperty Item Qt.labs.controls::ApplicationWindow::overlay + \readonly + + This attached property holds the window overlay item. The property can be attached + to any item. The value is \c null if the item is not in an ApplicationWindow. +*/ +QQuickOverlay *QQuickApplicationWindowAttached::overlay() const +{ + Q_D(const QQuickApplicationWindowAttached); + return d->window ? d->window->overlay() : nullptr; +} + +QT_END_NAMESPACE + +#include "moc_qquickapplicationwindow_p.cpp" diff --git a/src/quicktemplates2/qquickapplicationwindow_p.h b/src/quicktemplates2/qquickapplicationwindow_p.h new file mode 100644 index 00000000..e383d08b --- /dev/null +++ b/src/quicktemplates2/qquickapplicationwindow_p.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKAPPLICATIONWINDOW_P_H +#define QQUICKAPPLICATIONWINDOW_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickOverlay; +class QQuickApplicationWindowPrivate; +class QQuickApplicationWindowAttached; +class QQuickApplicationWindowAttachedPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickApplicationWindow : public QQuickWindowQmlImpl +{ + Q_OBJECT + Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL) + Q_PROPERTY(QQuickItem *contentItem READ contentItem CONSTANT FINAL) + Q_PROPERTY(QQmlListProperty data READ contentData FINAL) + Q_PROPERTY(QQuickItem *activeFocusControl READ activeFocusControl NOTIFY activeFocusControlChanged FINAL) + Q_PROPERTY(QQuickItem *header READ header WRITE setHeader NOTIFY headerChanged FINAL) + Q_PROPERTY(QQuickItem *footer READ footer WRITE setFooter NOTIFY footerChanged FINAL) + Q_PROPERTY(QQuickOverlay *overlay READ overlay CONSTANT FINAL) + Q_PROPERTY(QFont font READ font WRITE setFont RESET resetFont NOTIFY fontChanged FINAL) + Q_PROPERTY(QLocale locale READ locale WRITE setLocale RESET resetLocale NOTIFY localeChanged FINAL) + Q_CLASSINFO("DefaultProperty", "data") + +public: + explicit QQuickApplicationWindow(QWindow *parent = nullptr); + ~QQuickApplicationWindow(); + + QQuickItem *background() const; + void setBackground(QQuickItem *background); + + QQuickItem *contentItem() const; + QQmlListProperty contentData(); + + QQuickItem *activeFocusControl() const; + + QQuickItem *header() const; + void setHeader(QQuickItem *header); + + QQuickItem *footer() const; + void setFooter(QQuickItem *footer); + + QQuickOverlay *overlay() const; + + QFont font() const; + void setFont(const QFont &font); + void resetFont(); + + QLocale locale() const; + void setLocale(const QLocale &locale); + void resetLocale(); + + static QQuickApplicationWindowAttached *qmlAttachedProperties(QObject *object); + +Q_SIGNALS: + void backgroundChanged(); + void activeFocusControlChanged(); + void headerChanged(); + void footerChanged(); + void fontChanged(); + void localeChanged(); + +protected: + bool isComponentComplete() const; + void classBegin() override; + void componentComplete() override; + void resizeEvent(QResizeEvent *event) override; + +private: + Q_DISABLE_COPY(QQuickApplicationWindow) + Q_DECLARE_PRIVATE(QQuickApplicationWindow) + Q_PRIVATE_SLOT(d_func(), void _q_updateActiveFocus()) + QScopedPointer d_ptr; +}; + +class Q_QUICKTEMPLATES2_EXPORT QQuickApplicationWindowAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQuickApplicationWindow *window READ window NOTIFY windowChanged FINAL) + Q_PROPERTY(QQuickItem *contentItem READ contentItem NOTIFY contentItemChanged FINAL) + Q_PROPERTY(QQuickItem *activeFocusControl READ activeFocusControl NOTIFY activeFocusControlChanged FINAL) + Q_PROPERTY(QQuickItem *header READ header NOTIFY headerChanged FINAL) + Q_PROPERTY(QQuickItem *footer READ footer NOTIFY footerChanged FINAL) + Q_PROPERTY(QQuickOverlay *overlay READ overlay NOTIFY overlayChanged FINAL) + +public: + explicit QQuickApplicationWindowAttached(QObject *parent = nullptr); + + QQuickApplicationWindow *window() const; + QQuickItem *contentItem() const; + QQuickItem *activeFocusControl() const; + QQuickItem *header() const; + QQuickItem *footer() const; + QQuickOverlay *overlay() const; + +Q_SIGNALS: + void windowChanged(); + void contentItemChanged(); + void activeFocusControlChanged(); + void headerChanged(); + void footerChanged(); + void overlayChanged(); + +private: + Q_DISABLE_COPY(QQuickApplicationWindowAttached) + Q_DECLARE_PRIVATE(QQuickApplicationWindowAttached) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickApplicationWindow) +QML_DECLARE_TYPEINFO(QQuickApplicationWindow, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QQUICKAPPLICATIONWINDOW_P_H diff --git a/src/quicktemplates2/qquickbusyindicator.cpp b/src/quicktemplates2/qquickbusyindicator.cpp new file mode 100644 index 00000000..631101c3 --- /dev/null +++ b/src/quicktemplates2/qquickbusyindicator.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickbusyindicator_p.h" +#include "qquickcontrol_p_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype BusyIndicator + \inherits Control + \instantiates QQuickBusyIndicator + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-indicators + \brief Indicates activity while content is being loaded. + + \image qtquickcontrols-busyindicator.gif + + The busy indicator should be used to indicate activity while content is + being loaded or the UI is blocked waiting for a resource to become available. + + The following snippet shows how to use the BusyIndicator: + + \qml + BusyIndicator { + running: image.status === Image.Loading + } + \endqml + + \labs + + \sa {Customizing BusyIndicator}, {Indicator Controls} +*/ + +class QQuickBusyIndicatorPrivate : public QQuickControlPrivate +{ +public: + QQuickBusyIndicatorPrivate() : running(true) { } + + bool running; +}; + +QQuickBusyIndicator::QQuickBusyIndicator(QQuickItem *parent) : + QQuickControl(*(new QQuickBusyIndicatorPrivate), parent) +{ +} + +/*! + \qmlproperty bool Qt.labs.controls::BusyIndicator::running + + This property holds whether the busy indicator is currently indicating + activity. + + \note The indicator is only visible when this property is set to \c true. + + The default value is \c true. + +*/ +bool QQuickBusyIndicator::isRunning() const +{ + Q_D(const QQuickBusyIndicator); + return d->running; +} + +void QQuickBusyIndicator::setRunning(bool running) +{ + Q_D(QQuickBusyIndicator); + if (d->running == running) + return; + + d->running = running; + emit runningChanged(); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickBusyIndicator::accessibleRole() const +{ + return QAccessible::Indicator; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickbusyindicator_p.h b/src/quicktemplates2/qquickbusyindicator_p.h new file mode 100644 index 00000000..d7c4c70f --- /dev/null +++ b/src/quicktemplates2/qquickbusyindicator_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKBUSYINDICATOR_P_H +#define QQUICKBUSYINDICATOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickBusyIndicatorPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickBusyIndicator : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged FINAL) + +public: + explicit QQuickBusyIndicator(QQuickItem *parent = nullptr); + + bool isRunning() const; + void setRunning(bool running); + +Q_SIGNALS: + void runningChanged(); + +protected: +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickBusyIndicator) + Q_DECLARE_PRIVATE(QQuickBusyIndicator) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickBusyIndicator) + +#endif // QQUICKBUSYINDICATOR_P_H diff --git a/src/quicktemplates2/qquickbutton.cpp b/src/quicktemplates2/qquickbutton.cpp new file mode 100644 index 00000000..3dbab498 --- /dev/null +++ b/src/quicktemplates2/qquickbutton.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickbutton_p.h" +#include "qquickabstractbutton_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Button + \inherits AbstractButton + \instantiates QQuickButton + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-buttons + \brief A push-button control that can be clicked by the user. + + \image qtquickcontrols-button.gif + + Button presents a push-button control that can be pushed or clicked by + the user. Buttons are normally used to perform an action, or to answer + a question. Typical buttons are \e OK, \e Apply, \e Cancel, \e Close, + \e Yes, \e No, and \e Help. + + \table + \row \li \image qtquickcontrols-button-normal.png + \li A button in its normal state. + \row \li \image qtquickcontrols-button-pressed.png + \li A button that is pressed. + \row \li \image qtquickcontrols-button-focused.png + \li A button that has active focus. + \row \li \image qtquickcontrols-button-disabled.png + \li A button that is disabled. + \endtable + + A button emits the signal \l {AbstractButton::}{clicked()} when it is activated by the user. + Connect to this signal to perform the button's action. Buttons also + provide the signals \l {AbstractButton::}{canceled()}, \l {AbstractButton::}{doubleClicked()}, \l {AbstractButton::}{pressed()}, + \l {AbstractButton::}{released()} and \l {AbstractButton::}{pressAndHold()} for long presses. + + See the snippet below on how to connect to the button's signals. + + \code + RowLayout { + Button { + text: "Ok" + onClicked: model.submit() + } + Button { + text: "Cancel" + onClicked: model.revert() + } + } + \endcode + + \labs + + \sa {Customizing Button}, {Button Controls} +*/ + +QQuickButton::QQuickButton(QQuickItem *parent) : QQuickAbstractButton(parent) +{ +} + +/*! + \qmlproperty bool Qt.labs.controls::Button::checkable + + This property holds whether the button is checkable. +*/ + +void QQuickButton::checkableChange() +{ + emit checkableChanged(); +} + +QFont QQuickButton::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::PushButtonFont); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickbutton_p.h b/src/quicktemplates2/qquickbutton_p.h new file mode 100644 index 00000000..654651d7 --- /dev/null +++ b/src/quicktemplates2/qquickbutton_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKBUTTON_P_H +#define QQUICKBUTTON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class Q_QUICKTEMPLATES2_EXPORT QQuickButton : public QQuickAbstractButton +{ + Q_OBJECT + Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY checkableChanged FINAL) + +public: + explicit QQuickButton(QQuickItem *parent = nullptr); + +Q_SIGNALS: + void checkableChanged(); + +protected: + void checkableChange() override; + + QFont defaultFont() const override; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickButton) + +#endif // QQUICKBUTTON_P_H diff --git a/src/quicktemplates2/qquickbuttongroup.cpp b/src/quicktemplates2/qquickbuttongroup.cpp new file mode 100644 index 00000000..7a087300 --- /dev/null +++ b/src/quicktemplates2/qquickbuttongroup.cpp @@ -0,0 +1,383 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickbuttongroup_p.h" + +#include +#include +#include +#include + +#include "qquickabstractbutton_p_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ButtonGroup + \inherits QtObject + \instantiates QQuickButtonGroup + \inqmlmodule Qt.labs.controls + \ingroup utilities + \brief A mutually-exclusive group of checkable controls. + + ButtonGroup is a non-visual, mutually exclusive group of buttons. + It is used with controls such as RadioButton, where only one of the options + can be selected at a time. + + The most straight-forward way to use ButtonGroup is to assign + a list of buttons. For example, the list of children of a + \l{Item Positioners}{positioner} or a \l{Qt Quick Layouts}{layout} + that manages a group of mutually exclusive buttons. + + \code + ButtonGroup { + buttons: column.children + } + + Column { + id: column + + RadioButton { + checked: true + text: qsTr("DAB") + } + + RadioButton { + text: qsTr("FM") + } + + RadioButton { + text: qsTr("AM") + } + } + \endcode + + Mutually exclusive buttons do not always share the same parent item, + or the parent layout may sometimes contain items that should not be + included in the button group. Such cases are best handled using + the \l group attached property. + + \code + ButtonGroup { id: radioGroup } + + Column { + Label { + text: qsTr("Radio:") + } + + RadioButton { + checked: true + text: qsTr("DAB") + ButtonGroup.group: radioGroup + } + + RadioButton { + text: qsTr("FM") + ButtonGroup.group: radioGroup + } + + RadioButton { + text: qsTr("AM") + ButtonGroup.group: radioGroup + } + } + \endcode + + More advanced use cases can be handled using the \c addButton() and + \c removeButton() methods. + + \labs + + \sa RadioButton +*/ + +class QQuickButtonGroupPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QQuickButtonGroup) + +public: + QQuickButtonGroupPrivate() : checkedButton(nullptr) { } + + void clear(); + void updateCurrent(); + + static void buttons_append(QQmlListProperty *prop, QQuickAbstractButton *obj); + static int buttons_count(QQmlListProperty *prop); + static QQuickAbstractButton *buttons_at(QQmlListProperty *prop, int index); + static void buttons_clear(QQmlListProperty *prop); + + QQuickAbstractButton *checkedButton; + QVector buttons; +}; + +void QQuickButtonGroupPrivate::clear() +{ + for (QQuickAbstractButton *button : qAsConst(buttons)) { + QQuickAbstractButtonPrivate::get(button)->group = nullptr; + QObjectPrivate::disconnect(button, &QQuickAbstractButton::checkedChanged, this, &QQuickButtonGroupPrivate::updateCurrent); + } + buttons.clear(); +} + +void QQuickButtonGroupPrivate::updateCurrent() +{ + Q_Q(QQuickButtonGroup); + QQuickAbstractButton *button = qobject_cast(q->sender()); + if (button && button->isChecked()) + q->setCheckedButton(button); +} + +void QQuickButtonGroupPrivate::buttons_append(QQmlListProperty *prop, QQuickAbstractButton *obj) +{ + QQuickButtonGroup *q = static_cast(prop->object); + q->addButton(obj); +} + +int QQuickButtonGroupPrivate::buttons_count(QQmlListProperty *prop) +{ + QQuickButtonGroupPrivate *p = static_cast(prop->data); + return p->buttons.count(); +} + +QQuickAbstractButton *QQuickButtonGroupPrivate::buttons_at(QQmlListProperty *prop, int index) +{ + QQuickButtonGroupPrivate *p = static_cast(prop->data); + return p->buttons.value(index); +} + +void QQuickButtonGroupPrivate::buttons_clear(QQmlListProperty *prop) +{ + QQuickButtonGroupPrivate *p = static_cast(prop->data); + if (!p->buttons.isEmpty()) { + p->clear(); + QQuickButtonGroup *q = static_cast(prop->object); + q->setCheckedButton(nullptr); + emit q->buttonsChanged(); + } +} + +QQuickButtonGroup::QQuickButtonGroup(QObject *parent) + : QObject(*(new QQuickButtonGroupPrivate), parent) +{ +} + +QQuickButtonGroup::~QQuickButtonGroup() +{ + Q_D(QQuickButtonGroup); + d->clear(); +} + +QQuickButtonGroupAttached *QQuickButtonGroup::qmlAttachedProperties(QObject *object) +{ + return new QQuickButtonGroupAttached(object); +} + +/*! + \qmlproperty AbstractButton Qt.labs.controls::ButtonGroup::current + + This property holds the currently selected button, or \c null if there is none. + + By default, it is the first checked button added to the button group. +*/ +QQuickAbstractButton *QQuickButtonGroup::checkedButton() const +{ + Q_D(const QQuickButtonGroup); + return d->checkedButton; +} + +void QQuickButtonGroup::setCheckedButton(QQuickAbstractButton *checkedButton) +{ + Q_D(QQuickButtonGroup); + if (d->checkedButton == checkedButton) + return; + + if (d->checkedButton) + d->checkedButton->setChecked(false); + d->checkedButton = checkedButton; + if (checkedButton) + checkedButton->setChecked(true); + emit checkedButtonChanged(); +} + +/*! + \qmlproperty list Qt.labs.controls::ButtonGroup::buttons + \default + + This property holds the list of buttons. + + \code + ButtonGroup { + buttons: column.children + } + + Column { + id: column + + RadioButton { + checked: true + text: qsTr("Option A") + } + + RadioButton { + text: qsTr("Option B") + } + } + \endcode + + \sa group +*/ +QQmlListProperty QQuickButtonGroup::buttons() +{ + Q_D(QQuickButtonGroup); + return QQmlListProperty(this, d, + QQuickButtonGroupPrivate::buttons_append, + QQuickButtonGroupPrivate::buttons_count, + QQuickButtonGroupPrivate::buttons_at, + QQuickButtonGroupPrivate::buttons_clear); +} + +/*! + \qmlmethod void Qt.labs.controls::ButtonGroup::addButton(AbstractButton button) + + Adds a \a button to the button group. + + \note Manually adding objects to a button group is typically unnecessary. + The \l buttons property and the \l group attached property provide a + convenient and declarative syntax. + + \sa buttons, group +*/ +void QQuickButtonGroup::addButton(QQuickAbstractButton *button) +{ + Q_D(QQuickButtonGroup); + if (!button || d->buttons.contains(button)) + return; + + QQuickAbstractButtonPrivate::get(button)->group = this; + QObjectPrivate::connect(button, &QQuickAbstractButton::checkedChanged, d, &QQuickButtonGroupPrivate::updateCurrent); + + if (button->isChecked()) + setCheckedButton(button); + + d->buttons.append(button); + emit buttonsChanged(); +} + +/*! + \qmlmethod void Qt.labs.controls::ButtonGroup::removeButton(AbstractButton button) + + Removes a \a button from the button group. + + \note Manually removing objects from a button group is typically unnecessary. + The \l buttons property and the \l group attached property provide a + convenient and declarative syntax. + + \sa buttons, group +*/ +void QQuickButtonGroup::removeButton(QQuickAbstractButton *button) +{ + Q_D(QQuickButtonGroup); + if (!button || !d->buttons.contains(button)) + return; + + QQuickAbstractButtonPrivate::get(button)->group = nullptr; + QObjectPrivate::disconnect(button, &QQuickAbstractButton::checkedChanged, d, &QQuickButtonGroupPrivate::updateCurrent); + + if (d->checkedButton == button) + setCheckedButton(nullptr); + + d->buttons.removeOne(button); + emit buttonsChanged(); +} + +class QQuickButtonGroupAttachedPrivate : public QObjectPrivate +{ +public: + QQuickButtonGroupAttachedPrivate() : group(nullptr) { } + + QQuickButtonGroup *group; +}; + +QQuickButtonGroupAttached::QQuickButtonGroupAttached(QObject *parent) : + QObject(*(new QQuickButtonGroupAttachedPrivate), parent) +{ +} + +/*! + \qmlattachedproperty ButtonGroup Qt.labs.controls::ButtonGroup::group + + This property attaches a button to a button group. + + \code + ButtonGroup { id: group } + + RadioButton { + checked: true + text: qsTr("Option A") + ButtonGroup.group: group + } + + RadioButton { + text: qsTr("Option B") + ButtonGroup.group: group + } + \endcode + + \sa buttons +*/ +QQuickButtonGroup *QQuickButtonGroupAttached::group() const +{ + Q_D(const QQuickButtonGroupAttached); + return d->group; +} + +void QQuickButtonGroupAttached::setGroup(QQuickButtonGroup *group) +{ + Q_D(QQuickButtonGroupAttached); + if (d->group == group) + return; + + if (d->group) + d->group->removeButton(qobject_cast(parent())); + d->group = group; + if (group) + group->addButton(qobject_cast(parent())); + emit groupChanged(); +} + +QT_END_NAMESPACE + +#include "moc_qquickbuttongroup_p.cpp" diff --git a/src/quicktemplates2/qquickbuttongroup_p.h b/src/quicktemplates2/qquickbuttongroup_p.h new file mode 100644 index 00000000..96991e19 --- /dev/null +++ b/src/quicktemplates2/qquickbuttongroup_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKBUTTONGROUP_P_H +#define QQUICKBUTTONGROUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickAbstractButton; +class QQuickButtonGroupPrivate; +class QQuickButtonGroupAttached; +class QQuickButtonGroupAttachedPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickButtonGroup : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQuickAbstractButton *checkedButton READ checkedButton WRITE setCheckedButton NOTIFY checkedButtonChanged) + Q_PROPERTY(QQmlListProperty buttons READ buttons NOTIFY buttonsChanged FINAL) + +public: + explicit QQuickButtonGroup(QObject *parent = nullptr); + ~QQuickButtonGroup(); + + static QQuickButtonGroupAttached *qmlAttachedProperties(QObject *object); + + QQuickAbstractButton *checkedButton() const; + void setCheckedButton(QQuickAbstractButton *checkedButton); + + QQmlListProperty buttons(); + +public Q_SLOTS: + void addButton(QQuickAbstractButton *button); + void removeButton(QQuickAbstractButton *button); + +Q_SIGNALS: + void checkedButtonChanged(); + void buttonsChanged(); + +private: + Q_DISABLE_COPY(QQuickButtonGroup) + Q_DECLARE_PRIVATE(QQuickButtonGroup) +}; + +class Q_QUICKTEMPLATES2_EXPORT QQuickButtonGroupAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQuickButtonGroup *group READ group WRITE setGroup NOTIFY groupChanged FINAL) + +public: + explicit QQuickButtonGroupAttached(QObject *parent = nullptr); + + QQuickButtonGroup *group() const; + void setGroup(QQuickButtonGroup *group); + +Q_SIGNALS: + void groupChanged(); + +private: + Q_DISABLE_COPY(QQuickButtonGroupAttached) + Q_DECLARE_PRIVATE(QQuickButtonGroupAttached) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickButtonGroup) +QML_DECLARE_TYPEINFO(QQuickButtonGroup, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QQuickButtonGroup_H diff --git a/src/quicktemplates2/qquickcheckbox.cpp b/src/quicktemplates2/qquickcheckbox.cpp new file mode 100644 index 00000000..8e0b3953 --- /dev/null +++ b/src/quicktemplates2/qquickcheckbox.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickcheckbox_p.h" +#include "qquickabstractbutton_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype CheckBox + \inherits AbstractButton + \instantiates QQuickCheckBox + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-buttons + \brief An option button that can be checked or unchecked. + + CheckBox presents an option button that can be toggled on (checked) or + off (unchecked). Check boxes are typically used to select one or more + options from a set of options. + + The state of the checkbox can be set with the \l {AbstractButton::}{checked} property. + + In addition to the checked and unchecked states, there is a third state: + partially checked. The partially checked state can be enabled using the + \l tristate property. This state indicates that the regular checked/unchecked + state can not be determined; generally because of other states that affect + the checkbox. This state is useful when several child nodes are selected + in a treeview, for example. + + \table + \row \li \image qtquickcontrols-checkbox-normal.png + \li A check box in its normal state. + \row \li \image qtquickcontrols-checkbox-checked.png + \li A check box that is checked. + \row \li \image qtquickcontrols-checkbox-focused.png + \li A check box that has active focus. + \row \li \image qtquickcontrols-checkbox-disabled.png + \li A check box that is disabled. + \endtable + + \code + ColumnLayout { + CheckBox { + checked: true + text: qsTr("First") + } + CheckBox { + text: qsTr("Second") + } + CheckBox { + checked: true + text: qsTr("Third") + } + } + \endcode + + \labs + + \sa {Customizing CheckBox}, {Button Controls} +*/ + +class QQuickCheckBoxPrivate : public QQuickAbstractButtonPrivate +{ + Q_DECLARE_PUBLIC(QQuickCheckBox) + +public: + QQuickCheckBoxPrivate() + : tristate(false), checkState(Qt::Unchecked) + { + } + + bool tristate; + Qt::CheckState checkState; +}; + +QQuickCheckBox::QQuickCheckBox(QQuickItem *parent) : + QQuickAbstractButton(*(new QQuickCheckBoxPrivate), parent) +{ + setCheckable(true); +} + +/*! + \qmlproperty bool Qt.labs.controls::CheckBox::tristate + + This property holds whether the checkbox is a tri-state checkbox. + + The default is \c false, i.e., the checkbox has only two states. +*/ +bool QQuickCheckBox::isTristate() const +{ + Q_D(const QQuickCheckBox); + return d->tristate; +} + +void QQuickCheckBox::setTristate(bool tristate) +{ + Q_D(QQuickCheckBox); + if (d->tristate == tristate) + return; + + d->tristate = tristate; + emit tristateChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::CheckBox::checkState + + This property holds the check state of the checkbox. + + Available states: + \value Qt.Unchecked The checkbox is unchecked. + \value Qt.PartiallyChecked The checkbox is partially checked. This state is only used when \l tristate is enabled. + \value Qt.Checked The checkbox is checked. + + \sa tristate, {AbstractButton::checked}{checked} +*/ +Qt::CheckState QQuickCheckBox::checkState() const +{ + Q_D(const QQuickCheckBox); + return d->checkState; +} + +void QQuickCheckBox::setCheckState(Qt::CheckState state) +{ + Q_D(QQuickCheckBox); + if (d->checkState == state) + return; + + if (!d->tristate && state == Qt::PartiallyChecked) + setTristate(true); + + bool wasChecked = isChecked(); + d->checked = state != Qt::Unchecked; + d->checkState = state; + emit checkStateChanged(); + if (d->checked != wasChecked) + emit checkedChanged(); +} + +QFont QQuickCheckBox::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::CheckBoxFont); +} + +void QQuickCheckBox::checkStateSet() +{ + setCheckState(isChecked() ? Qt::Checked : Qt::Unchecked); +} + +void QQuickCheckBox::nextCheckState() +{ + Q_D(QQuickCheckBox); + if (d->tristate) + setCheckState(static_cast((d->checkState + 1) % 3)); + else + QQuickAbstractButton::nextCheckState(); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickCheckBox::accessibleRole() const +{ + return QAccessible::CheckBox; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickcheckbox_p.h b/src/quicktemplates2/qquickcheckbox_p.h new file mode 100644 index 00000000..1e9389b2 --- /dev/null +++ b/src/quicktemplates2/qquickcheckbox_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKCHECKBOX_P_H +#define QQUICKCHECKBOX_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickCheckBoxPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickCheckBox : public QQuickAbstractButton +{ + Q_OBJECT + Q_PROPERTY(bool tristate READ isTristate WRITE setTristate NOTIFY tristateChanged FINAL) + Q_PROPERTY(Qt::CheckState checkState READ checkState WRITE setCheckState NOTIFY checkStateChanged FINAL) + +public: + explicit QQuickCheckBox(QQuickItem *parent = nullptr); + + bool isTristate() const; + void setTristate(bool tristate); + + Qt::CheckState checkState() const; + void setCheckState(Qt::CheckState state); + +Q_SIGNALS: + void tristateChanged(); + void checkStateChanged(); + +protected: + QFont defaultFont() const override; + + void checkStateSet() override; + void nextCheckState() override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickCheckBox) + Q_DECLARE_PRIVATE(QQuickCheckBox) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickCheckBox) + +#endif // QQUICKCHECKBOX_P_H diff --git a/src/quicktemplates2/qquickcheckdelegate.cpp b/src/quicktemplates2/qquickcheckdelegate.cpp new file mode 100644 index 00000000..53c2af69 --- /dev/null +++ b/src/quicktemplates2/qquickcheckdelegate.cpp @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickcheckdelegate_p.h" +#include "qquickabstractbutton_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype CheckDelegate + \inherits ItemDelegate + \instantiates QQuickCheckDelegate + \inqmlmodule Qt.labs.controls + \ingroup qtlabscontrols-delegates + \brief An item delegate that can be checked or unchecked. + + \image qtquickcontrols-checkdelegate.gif + + CheckDelegate presents an item delegate that can be toggled on (checked) or + off (unchecked). Check delegates are typically used to select one or more + options from a set of options. + + The state of the check delegate can be set with the + \l {AbstractButton::}{checked} property. + + In addition to the checked and unchecked states, there is a third state: + partially checked. The partially checked state can be enabled using the + \l tristate property. This state indicates that the regular checked/unchecked + state can not be determined; generally because of other states that affect + the check delegate. This state is useful when several child nodes are selected + in a treeview, for example. + + \code + ListView { + model: ["Option 1", "Option 2", "Option 3"] + delegate: CheckDelegate { + text: modelData + } + } + \endcode + + \labs + + \sa {Customizing CheckDelegate}, {Delegate Controls} +*/ + +class QQuickCheckDelegatePrivate : public QQuickAbstractButtonPrivate +{ + Q_DECLARE_PUBLIC(QQuickCheckDelegate) + +public: + QQuickCheckDelegatePrivate() + : tristate(false), checkState(Qt::Unchecked) + { + } + + bool tristate; + Qt::CheckState checkState; +}; + +QQuickCheckDelegate::QQuickCheckDelegate(QQuickItem *parent) : + QQuickItemDelegate(*(new QQuickCheckDelegatePrivate), parent) +{ + setCheckable(true); +} + +/*! + \qmlproperty bool Qt.labs.controls::CheckDelegate::tristate + + This property determines whether the check delegate has three states. + + The default is \c false, i.e., the delegate has only two states. +*/ +bool QQuickCheckDelegate::isTristate() const +{ + Q_D(const QQuickCheckDelegate); + return d->tristate; +} + +void QQuickCheckDelegate::setTristate(bool tristate) +{ + Q_D(QQuickCheckDelegate); + if (d->tristate == tristate) + return; + + d->tristate = tristate; + emit tristateChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::CheckDelegate::checkState + + This property determines the check state of the check delegate. + + Available states: + \value Qt.Unchecked The delegate is unchecked. + \value Qt.PartiallyChecked The delegate is partially checked. This state is only used when \l tristate is enabled. + \value Qt.Checked The delegate is checked. + + \sa tristate, {AbstractButton::checked}{checked} +*/ +Qt::CheckState QQuickCheckDelegate::checkState() const +{ + Q_D(const QQuickCheckDelegate); + return d->checkState; +} + +void QQuickCheckDelegate::setCheckState(Qt::CheckState state) +{ + Q_D(QQuickCheckDelegate); + if (d->checkState == state) + return; + + if (!d->tristate && state == Qt::PartiallyChecked) + setTristate(true); + + bool wasChecked = isChecked(); + d->checked = state != Qt::Unchecked; + d->checkState = state; + emit checkStateChanged(); + if (d->checked != wasChecked) + emit checkedChanged(); +} + +void QQuickCheckDelegate::checkStateSet() +{ + setCheckState(isChecked() ? Qt::Checked : Qt::Unchecked); +} + +void QQuickCheckDelegate::nextCheckState() +{ + Q_D(QQuickCheckDelegate); + if (d->tristate) + setCheckState(static_cast((d->checkState + 1) % 3)); + else + QQuickItemDelegate::nextCheckState(); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickCheckDelegate::accessibleRole() const +{ + return QAccessible::CheckBox; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickcheckdelegate_p.h b/src/quicktemplates2/qquickcheckdelegate_p.h new file mode 100644 index 00000000..183953d1 --- /dev/null +++ b/src/quicktemplates2/qquickcheckdelegate_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKCHECKDELEGATE_P_H +#define QQUICKCHECKDELEGATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickCheckDelegatePrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickCheckDelegate : public QQuickItemDelegate +{ + Q_OBJECT + Q_PROPERTY(bool tristate READ isTristate WRITE setTristate NOTIFY tristateChanged FINAL) + Q_PROPERTY(Qt::CheckState checkState READ checkState WRITE setCheckState NOTIFY checkStateChanged FINAL) + +public: + explicit QQuickCheckDelegate(QQuickItem *parent = nullptr); + + bool isTristate() const; + void setTristate(bool tristate); + + Qt::CheckState checkState() const; + void setCheckState(Qt::CheckState state); + +Q_SIGNALS: + void tristateChanged(); + void checkStateChanged(); + +protected: + void checkStateSet() override; + void nextCheckState() override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickCheckDelegate) + Q_DECLARE_PRIVATE(QQuickCheckDelegate) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickCheckDelegate) + +#endif // QQUICKCHECKDELEGATE_P_H diff --git a/src/quicktemplates2/qquickcombobox.cpp b/src/quicktemplates2/qquickcombobox.cpp new file mode 100644 index 00000000..d25e674c --- /dev/null +++ b/src/quicktemplates2/qquickcombobox.cpp @@ -0,0 +1,872 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickcombobox_p.h" +#include "qquickcontrol_p_p.h" +#include "qquickabstractbutton_p.h" +#include "qquickpopup_p.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ComboBox + \inherits Control + \instantiates QQuickComboBox + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-input + \brief A combined button and popup list taking minimal space. + + \image qtquickcontrols-combobox.png + + ComboBox is a combined button and popup list. It provides a means of + presenting a list of options to the user in a way that takes up the + minimum amount of screen space. + + ComboBox is populated with a data model. The data model is commonly + a JavaScript array, a \l ListModel or an integer, but also other types + of \l {qml-data-models}{data models} are supported. + + \code + ComboBox { + model: ["First", "Second", "Third"] + } + \endcode + + ComboBox is able to visualize standard \l {qml-data-models}{data models} + that provide the \c modelData role: + \list + \li models that have only one role + \li models that do not have named roles (JavaScript array, integer) + \endlist + + When using models that have multiple named roles, ComboBox must be configured + to use a specific \l {textRole}{text role} for its \l {displayText}{display text} + and \l delegate instances. + + \code + ComboBox { + textRole: "key" + model: ListModel { + ListElement { key: "First"; value: 123 } + ListElement { key: "Second"; value: 456 } + ListElement { key: "Third"; value: 789 } + } + } + \endcode + + \note If ComboBox is assigned a data model that has multiple named roles, but + \l textRole is not defined, ComboBox is unable to visualize it and throws a + \c {ReferenceError: modelData is not defined}. + + \labs + + \sa {Customizing ComboBox}, {Input Controls} +*/ + +/*! + \qmlsignal void Qt.labs.controls::ComboBox::activated(int index) + + This signal is emitted when the item at \a index is activated by the user. + + \sa currentIndex +*/ + +/*! + \qmlsignal void Qt.labs.controls::ComboBox::highlighted(int index) + + This signal is emitted when the item at \a index in the popup list is highlighted by the user. + + \sa highlightedIndex +*/ + +class QQuickComboBoxDelegateModel : public QQmlDelegateModel +{ +public: + explicit QQuickComboBoxDelegateModel(QQuickComboBox *combo); + QString stringValue(int index, const QString &role) override; + +private: + QQuickComboBox *combo; +}; + +QQuickComboBoxDelegateModel::QQuickComboBoxDelegateModel(QQuickComboBox *combo) : + QQmlDelegateModel(qmlContext(combo), combo), combo(combo) +{ +} + +QString QQuickComboBoxDelegateModel::stringValue(int index, const QString &role) +{ + QVariant model = combo->model(); + if (model.userType() == QMetaType::QVariantList) { + QVariant object = model.toList().value(index); + if (object.userType() == QMetaType::QVariantMap) { + const QVariantMap data = object.toMap(); + if (data.count() == 1 && role == QLatin1String("modelData")) + return data.first().toString(); + return data.value(role).toString(); + } + } + return QQmlDelegateModel::stringValue(index, role); +} + +class QQuickComboBoxPrivate : public QQuickControlPrivate +{ + Q_DECLARE_PUBLIC(QQuickComboBox) + +public: + QQuickComboBoxPrivate() : pressed(false), ownModel(false), hasDisplayText(false), + highlightedIndex(-1), currentIndex(-1), delegateModel(nullptr), + delegate(nullptr), popup(nullptr) { } + + bool isPopupVisible() const; + void showPopup(); + void hidePopup(bool accept); + void togglePopup(bool accept); + + void itemClicked(); + + void createdItem(int index, QObject *object); + void countChanged(); + void updateCurrentText(); + void increase(); + void decrease(); + void setHighlightedIndex(int index); + + void createDelegateModel(); + + bool pressed; + bool ownModel; + bool hasDisplayText; + int highlightedIndex; + int currentIndex; + QVariant model; + QString textRole; + QString currentText; + QString displayText; + QQuickItem *pressedItem; + QQmlInstanceModel *delegateModel; + QQmlComponent *delegate; + QQuickPopup *popup; +}; + +bool QQuickComboBoxPrivate::isPopupVisible() const +{ + return popup && popup->isVisible(); +} + +void QQuickComboBoxPrivate::showPopup() +{ + if (popup && !popup->isVisible()) + popup->open(); + setHighlightedIndex(currentIndex); +} + +void QQuickComboBoxPrivate::hidePopup(bool accept) +{ + Q_Q(QQuickComboBox); + if (popup && popup->isVisible()) + popup->close(); + if (accept) { + q->setCurrentIndex(highlightedIndex); + emit q->activated(currentIndex); + } + setHighlightedIndex(-1); +} + +void QQuickComboBoxPrivate::togglePopup(bool accept) +{ + if (!popup) + return; + + if (popup->isVisible()) + hidePopup(accept); + else + showPopup(); +} + +void QQuickComboBoxPrivate::itemClicked() +{ + Q_Q(QQuickComboBox); + int index = delegateModel->indexOf(q->sender(), nullptr); + if (index != -1) { + setHighlightedIndex(index); + emit q->highlighted(index); + hidePopup(true); + } +} + +void QQuickComboBoxPrivate::createdItem(int index, QObject *object) +{ + QQuickAbstractButton *button = qobject_cast(object); + if (button) + connect(button, &QQuickAbstractButton::clicked, this, &QQuickComboBoxPrivate::itemClicked); + + if (index == currentIndex) + updateCurrentText(); +} + +void QQuickComboBoxPrivate::countChanged() +{ + Q_Q(QQuickComboBox); + if (q->count() == 0) + q->setCurrentIndex(-1); + emit q->countChanged(); +} + +void QQuickComboBoxPrivate::updateCurrentText() +{ + Q_Q(QQuickComboBox); + QString text = q->textAt(currentIndex); + if (currentText != text) { + currentText = text; + emit q->currentTextChanged(); + } + if (!hasDisplayText && displayText != text) { + displayText = text; + emit q->displayTextChanged(); + } +} + +void QQuickComboBoxPrivate::increase() +{ + Q_Q(QQuickComboBox); + if (isPopupVisible()) { + if (highlightedIndex < q->count() - 1) { + setHighlightedIndex(highlightedIndex + 1); + emit q->highlighted(highlightedIndex); + } + } else { + if (currentIndex < q->count() - 1) { + q->setCurrentIndex(currentIndex + 1); + emit q->activated(currentIndex); + } + } +} + +void QQuickComboBoxPrivate::decrease() +{ + Q_Q(QQuickComboBox); + if (isPopupVisible()) { + if (highlightedIndex > 0) { + setHighlightedIndex(highlightedIndex - 1); + emit q->highlighted(highlightedIndex); + } + } else { + if (currentIndex > 0) { + q->setCurrentIndex(currentIndex - 1); + emit q->activated(currentIndex); + } + } +} + +void QQuickComboBoxPrivate::setHighlightedIndex(int index) +{ + Q_Q(QQuickComboBox); + if (highlightedIndex == index) + return; + + highlightedIndex = index; + emit q->highlightedIndexChanged(); +} + +void QQuickComboBoxPrivate::createDelegateModel() +{ + Q_Q(QQuickComboBox); + bool ownedOldModel = ownModel; + QQmlInstanceModel* oldModel = delegateModel; + if (oldModel) { + disconnect(delegateModel, &QQmlInstanceModel::countChanged, this, &QQuickComboBoxPrivate::countChanged); + disconnect(delegateModel, &QQmlInstanceModel::modelUpdated, this, &QQuickComboBoxPrivate::updateCurrentText); + disconnect(delegateModel, &QQmlInstanceModel::createdItem, this, &QQuickComboBoxPrivate::createdItem); + } + + ownModel = false; + delegateModel = model.value(); + + if (!delegateModel && model.isValid()) { + QQmlDelegateModel *dataModel = new QQuickComboBoxDelegateModel(q); + dataModel->setModel(model); + dataModel->setDelegate(delegate); + if (q->isComponentComplete()) + dataModel->componentComplete(); + + ownModel = true; + delegateModel = dataModel; + } + + if (delegateModel) { + connect(delegateModel, &QQmlInstanceModel::countChanged, this, &QQuickComboBoxPrivate::countChanged); + connect(delegateModel, &QQmlInstanceModel::modelUpdated, this, &QQuickComboBoxPrivate::updateCurrentText); + connect(delegateModel, &QQmlInstanceModel::createdItem, this, &QQuickComboBoxPrivate::createdItem); + } + + emit q->delegateModelChanged(); + + if (ownedOldModel) + delete oldModel; +} + +QQuickComboBox::QQuickComboBox(QQuickItem *parent) : + QQuickControl(*(new QQuickComboBoxPrivate), parent) +{ + setFocusPolicy(Qt::StrongFocus); + setFlag(QQuickItem::ItemIsFocusScope); + setAcceptedMouseButtons(Qt::LeftButton); +} + +QQuickComboBox::~QQuickComboBox() +{ + Q_D(QQuickComboBox); + delete d->popup; + d->popup = nullptr; +} + +/*! + \readonly + \qmlproperty int Qt.labs.controls::ComboBox::count + + This property holds the number of items in the combo box. +*/ +int QQuickComboBox::count() const +{ + Q_D(const QQuickComboBox); + return d->delegateModel ? d->delegateModel->count() : 0; +} + +/*! + \qmlproperty model Qt.labs.controls::ComboBox::model + + This property holds the model providing data for the combo box. + + \code + ComboBox { + textRole: "key" + model: ListModel { + ListElement { key: "First"; value: 123 } + ListElement { key: "Second"; value: 456 } + ListElement { key: "Third"; value: 789 } + } + } + \endcode + + \sa textRole, {qml-data-models}{Data Models} +*/ +QVariant QQuickComboBox::model() const +{ + Q_D(const QQuickComboBox); + return d->model; +} + +void QQuickComboBox::setModel(const QVariant& m) +{ + Q_D(QQuickComboBox); + QVariant model = m; + if (model.userType() == qMetaTypeId()) + model = model.value().toVariant(); + + if (d->model == model) + return; + + d->model = model; + d->createDelegateModel(); + if (isComponentComplete()) { + setCurrentIndex(count() > 0 ? 0 : -1); + d->updateCurrentText(); + } + emit modelChanged(); +} + +/*! + \internal + \qmlproperty model Qt.labs.controls::ComboBox::delegateModel + + This property holds the model providing delegate instances for the combo box. +*/ +QQmlInstanceModel *QQuickComboBox::delegateModel() const +{ + Q_D(const QQuickComboBox); + return d->delegateModel; +} + +/*! + \qmlproperty bool Qt.labs.controls::ComboBox::pressed + + This property holds whether the combo box button is pressed. +*/ +bool QQuickComboBox::isPressed() const +{ + Q_D(const QQuickComboBox); + return d->pressed; +} + +void QQuickComboBox::setPressed(bool pressed) +{ + Q_D(QQuickComboBox); + if (d->pressed == pressed) + return; + + d->pressed = pressed; + emit pressedChanged(); +} + +/*! + \readonly + \qmlproperty int Qt.labs.controls::ComboBox::highlightedIndex + + This property holds the index of the highlighted item in the combo box popup list. + + \sa highlighted(), currentIndex +*/ +int QQuickComboBox::highlightedIndex() const +{ + Q_D(const QQuickComboBox); + return d->highlightedIndex; +} + +/*! + \qmlproperty int Qt.labs.controls::ComboBox::currentIndex + + This property holds the index of the current item in the combo box. + + \sa activated(), currentText +*/ +int QQuickComboBox::currentIndex() const +{ + Q_D(const QQuickComboBox); + return d->currentIndex; +} + +void QQuickComboBox::setCurrentIndex(int index) +{ + Q_D(QQuickComboBox); + if (d->currentIndex == index) + return; + + d->currentIndex = index; + emit currentIndexChanged(); + if (isComponentComplete()) + d->updateCurrentText(); +} + +/*! + \readonly + \qmlproperty string Qt.labs.controls::ComboBox::currentText + + This property holds the text of the current item in the combo box. + + \sa currentIndex, displayText, textRole +*/ +QString QQuickComboBox::currentText() const +{ + Q_D(const QQuickComboBox); + return d->currentText; +} + +/*! + \qmlproperty string Qt.labs.controls::ComboBox::displayText + + This property holds the text that is displayed on the combo box button. + + By default, the display text presents the current selection. That is, + it follows the text of the current item. However, the default display + text can be overridden with a custom value. + + \code + ComboBox { + currentIndex: 1 + displayText: "Size: " + currentText + model: ["S", "M", "L"] + } + \endcode + + \sa currentText, textRole +*/ +QString QQuickComboBox::displayText() const +{ + Q_D(const QQuickComboBox); + return d->displayText; +} + +void QQuickComboBox::setDisplayText(const QString &text) +{ + Q_D(QQuickComboBox); + d->hasDisplayText = true; + if (d->displayText == text) + return; + + d->displayText = text; + emit displayTextChanged(); +} + +void QQuickComboBox::resetDisplayText() +{ + Q_D(QQuickComboBox); + if (!d->hasDisplayText) + return; + + d->hasDisplayText = false; + d->updateCurrentText(); +} + +/*! + \qmlproperty string Qt.labs.controls::ComboBox::textRole + + This property holds the model role used for populating the combo box. + + \sa model, currentText, displayText +*/ +QString QQuickComboBox::textRole() const +{ + Q_D(const QQuickComboBox); + return d->textRole; +} + +void QQuickComboBox::setTextRole(const QString &role) +{ + Q_D(QQuickComboBox); + if (d->textRole == role) + return; + + d->textRole = role; + if (isComponentComplete()) + d->updateCurrentText(); + emit textRoleChanged(); +} + +/*! + \qmlproperty Component Qt.labs.controls::ComboBox::delegate + + This property holds a delegate that presents an item in the combo box popup. + + \sa ItemDelegate, {Customizing ComboBox} +*/ +QQmlComponent *QQuickComboBox::delegate() const +{ + Q_D(const QQuickComboBox); + return d->delegate; +} + +void QQuickComboBox::setDelegate(QQmlComponent* delegate) +{ + Q_D(QQuickComboBox); + if (d->delegate == delegate) + return; + + delete d->delegate; + d->delegate = delegate; + QQmlDelegateModel *delegateModel = qobject_cast(d->delegateModel); + if (delegateModel) + delegateModel->setDelegate(d->delegate); + emit delegateChanged(); +} + +/*! + \qmlproperty Popup Qt.labs.controls::ComboBox::popup + + This property holds the popup. + + \sa {Customizing ComboBox} +*/ +QQuickPopup *QQuickComboBox::popup() const +{ + Q_D(const QQuickComboBox); + return d->popup; +} + +void QQuickComboBox::setPopup(QQuickPopup *popup) +{ + Q_D(QQuickComboBox); + if (d->popup == popup) + return; + + delete d->popup; + if (popup) + popup->setClosePolicy(QQuickPopup::OnEscape | QQuickPopup::OnPressOutsideParent); + d->popup = popup; + emit popupChanged(); +} + +/*! + \qmlmethod string Qt.labs.controls::ComboBox::textAt(int index) + + Returns the text for the specified \a index, or an empty string + if the index is out of bounds. + + \sa textRole +*/ +QString QQuickComboBox::textAt(int index) const +{ + Q_D(const QQuickComboBox); + if (!d->delegateModel || index < 0 || index >= d->delegateModel->count() || !d->delegateModel->object(index)) + return QString(); + return d->delegateModel->stringValue(index, d->textRole.isEmpty() ? QStringLiteral("modelData") : d->textRole); +} + +/*! + \qmlmethod int Qt.labs.controls::ComboBox::find(string text, flags = Qt.MatchExactly) + + Returns the index of the specified \a text, or \c -1 if no match is found. + + The way the search is performed is defined by the specified match \a flags. By default, + combo box performs case sensitive exact matching (\c Qt.MatchExactly). All other match + types are case-insensitive unless the \c Qt.MatchCaseSensitive flag is also specified. + + \value Qt.MatchExactly The search term matches exactly (default). + \value Qt.MatchRegExp The search term matches as a regular expression. + \value Qt.MatchWildcard The search term matches using wildcards. + \value Qt.MatchFixedString The search term matches as a fixed string. + \value Qt.MatchStartsWith The search term matches the start of the item. + \value Qt.MatchEndsWidth The search term matches the end of the item. + \value Qt.MatchContains The search term is contained in the item. + \value Qt.MatchCaseSensitive The search is case sensitive. + + \sa textRole +*/ +int QQuickComboBox::find(const QString &text, Qt::MatchFlags flags) const +{ + int itemCount = count(); + uint matchType = flags & 0x0F; + Qt::CaseSensitivity cs = flags & Qt::MatchCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; + + for (int idx = 0; idx < itemCount; ++idx) { + QString t = textAt(idx); + switch (matchType) { + case Qt::MatchExactly: + if (t == text) + return idx; + break; + case Qt::MatchRegExp: + if (QRegExp(text, cs).exactMatch(t)) + return idx; + break; + case Qt::MatchWildcard: + if (QRegExp(text, cs, QRegExp::Wildcard).exactMatch(t)) + return idx; + break; + case Qt::MatchStartsWith: + if (t.startsWith(text, cs)) + return idx; + break; + case Qt::MatchEndsWith: + if (t.endsWith(text, cs)) + return idx; + break; + case Qt::MatchFixedString: + if (t.compare(text, cs) == 0) + return idx; + break; + case Qt::MatchContains: + default: + if (t.contains(text, cs)) + return idx; + break; + } + } + return -1; +} + +/*! + \qmlmethod void Qt.labs.controls::ComboBox::increase() + + Increases the current index of the combo box, or the highlighted + index if the popup list when it is visible. + + \sa currentIndex, highlightedIndex +*/ +void QQuickComboBox::increase() +{ + Q_D(QQuickComboBox); + d->increase(); +} + +/*! + \qmlmethod void Qt.labs.controls::ComboBox::decrease() + + Decreases the current index of the combo box, or the highlighted + index if the popup list when it is visible. + + \sa currentIndex, highlightedIndex +*/ +void QQuickComboBox::decrease() +{ + Q_D(QQuickComboBox); + d->decrease(); +} + +void QQuickComboBox::focusOutEvent(QFocusEvent *event) +{ + Q_D(QQuickComboBox); + QQuickControl::focusOutEvent(event); + d->hidePopup(false); + setPressed(false); +} + +void QQuickComboBox::keyPressEvent(QKeyEvent *event) +{ + Q_D(QQuickComboBox); + QQuickControl::keyPressEvent(event); + if (!d->popup) + return; + + switch (event->key()) { + case Qt::Key_Escape: + if (d->isPopupVisible()) + event->accept(); + break; + case Qt::Key_Space: + if (!event->isAutoRepeat()) + setPressed(true); + event->accept(); + break; + case Qt::Key_Enter: + case Qt::Key_Return: + if (d->isPopupVisible()) + setPressed(true); + event->accept(); + break; + case Qt::Key_Up: + d->decrease(); + event->accept(); + break; + case Qt::Key_Down: + d->increase(); + event->accept(); + break; + default: + break; + } +} + +void QQuickComboBox::keyReleaseEvent(QKeyEvent *event) +{ + Q_D(QQuickComboBox); + QQuickControl::keyReleaseEvent(event); + if (!d->popup || event->isAutoRepeat()) + return; + + switch (event->key()) { + case Qt::Key_Space: + d->togglePopup(true); + setPressed(false); + event->accept(); + break; + case Qt::Key_Enter: + case Qt::Key_Return: + d->hidePopup(d->isPopupVisible()); + setPressed(false); + event->accept(); + break; + case Qt::Key_Escape: + d->hidePopup(false); + setPressed(false); + event->accept(); + break; + default: + break; + } +} + +void QQuickComboBox::mousePressEvent(QMouseEvent *event) +{ + QQuickControl::mousePressEvent(event); + setPressed(true); +} + +void QQuickComboBox::mouseMoveEvent(QMouseEvent* event) +{ + QQuickControl::mouseMoveEvent(event); + setPressed(contains(event->pos())); +} + +void QQuickComboBox::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickComboBox); + QQuickControl::mouseReleaseEvent(event); + if (d->pressed) { + setPressed(false); + d->togglePopup(false); + } +} + +void QQuickComboBox::mouseUngrabEvent() +{ + QQuickControl::mouseUngrabEvent(); + setPressed(false); +} + +void QQuickComboBox::wheelEvent(QWheelEvent *event) +{ + Q_D(QQuickComboBox); + QQuickControl::wheelEvent(event); + if (d->wheelEnabled && !d->isPopupVisible()) { + const int oldIndex = d->currentIndex; + if (event->angleDelta().y() > 0) + d->decrease(); + else + d->increase(); + event->setAccepted(d->currentIndex != oldIndex); + } +} + +void QQuickComboBox::componentComplete() +{ + Q_D(QQuickComboBox); + QQuickControl::componentComplete(); + + if (d->delegateModel && d->ownModel) + static_cast(d->delegateModel)->componentComplete(); + + if (count() > 0) { + if (d->currentIndex == -1) + setCurrentIndex(0); + else + d->updateCurrentText(); + } +} + +QFont QQuickComboBox::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::ComboMenuItemFont); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickcombobox_p.h b/src/quicktemplates2/qquickcombobox_p.h new file mode 100644 index 00000000..e90141e3 --- /dev/null +++ b/src/quicktemplates2/qquickcombobox_p.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKCOMBOBOX_P_H +#define QQUICKCOMBOBOX_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickPopup; +class QQmlInstanceModel; +class QQuickComboBoxPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickComboBox : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(int count READ count NOTIFY countChanged FINAL) + Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged FINAL) + Q_PROPERTY(QQmlInstanceModel *delegateModel READ delegateModel NOTIFY delegateModelChanged FINAL) + Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL) + Q_PROPERTY(int highlightedIndex READ highlightedIndex NOTIFY highlightedIndexChanged FINAL) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL) + Q_PROPERTY(QString currentText READ currentText NOTIFY currentTextChanged FINAL) + Q_PROPERTY(QString displayText READ displayText WRITE setDisplayText RESET resetDisplayText NOTIFY displayTextChanged FINAL) + Q_PROPERTY(QString textRole READ textRole WRITE setTextRole NOTIFY textRoleChanged FINAL) + Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL) + Q_PROPERTY(QQuickPopup *popup READ popup WRITE setPopup NOTIFY popupChanged FINAL) + +public: + explicit QQuickComboBox(QQuickItem *parent = nullptr); + ~QQuickComboBox(); + + int count() const; + + QVariant model() const; + void setModel(const QVariant &model); + QQmlInstanceModel *delegateModel() const; + + bool isPressed() const; + void setPressed(bool pressed); + + int highlightedIndex() const; + + int currentIndex() const; + void setCurrentIndex(int index); + + QString currentText() const; + + QString displayText() const; + void setDisplayText(const QString &text); + void resetDisplayText(); + + QString textRole() const; + void setTextRole(const QString &role); + + QQmlComponent *delegate() const; + void setDelegate(QQmlComponent *delegate); + + QQuickPopup *popup() const; + void setPopup(QQuickPopup *popup); + + Q_INVOKABLE QString textAt(int index) const; + Q_INVOKABLE int find(const QString &text, Qt::MatchFlags flags = Qt::MatchExactly) const; + +public Q_SLOTS: + void increase(); + void decrease(); + +Q_SIGNALS: + void countChanged(); + void modelChanged(); + void delegateModelChanged(); + void pressedChanged(); + void highlightedIndexChanged(); + void currentIndexChanged(); + void currentTextChanged(); + void displayTextChanged(); + void textRoleChanged(); + void delegateChanged(); + void popupChanged(); + + void activated(int index); + void highlighted(int index); + +protected: + void focusOutEvent(QFocusEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseUngrabEvent() override; + void wheelEvent(QWheelEvent *event) override; + + void componentComplete() override; + + QFont defaultFont() const override; + +private: + Q_DISABLE_COPY(QQuickComboBox) + Q_DECLARE_PRIVATE(QQuickComboBox) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickComboBox) + +#endif // QQUICKCOMBOBOX_P_H diff --git a/src/quicktemplates2/qquickcontainer.cpp b/src/quicktemplates2/qquickcontainer.cpp new file mode 100644 index 00000000..9d39182f --- /dev/null +++ b/src/quicktemplates2/qquickcontainer.cpp @@ -0,0 +1,527 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickcontainer_p.h" +#include "qquickcontainer_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Container + \inherits Control + \instantiates QQuickContainer + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-containers + \brief A container control base type. + + Container is the base type of container-like user interface controls. + + \labs + + \sa {Container Controls} +*/ + +static QQuickItem *effectiveContentItem(QQuickItem *item) +{ + QQuickFlickable *flickable = qobject_cast(item); + if (flickable) + return flickable->contentItem(); + return item; +} + +QQuickContainerPrivate::QQuickContainerPrivate() : contentModel(nullptr), currentIndex(-1), updatingCurrent(false) +{ +} + +void QQuickContainerPrivate::init() +{ + Q_Q(QQuickContainer); + contentModel = new QQmlObjectModel(q); + QObject::connect(contentModel, &QQmlObjectModel::countChanged, q, &QQuickContainer::countChanged); + QObject::connect(contentModel, &QQmlObjectModel::childrenChanged, q, &QQuickContainer::contentChildrenChanged); +} + +void QQuickContainerPrivate::cleanup() +{ + // ensure correct destruction order (QTBUG-46798) + delete contentItem; + const int count = contentModel->count(); + for (int i = 0; i < count; ++i) { + QQuickItem *item = itemAt(i); + if (item) { + QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); + delete item; + } + } + delete contentModel; +} + +QQuickItem *QQuickContainerPrivate::itemAt(int index) const +{ + return qobject_cast(contentModel->get(index)); +} + +void QQuickContainerPrivate::insertItem(int index, QQuickItem *item) +{ + Q_Q(QQuickContainer); + if (!q->isContent(item)) + return; + contentData.append(item); + + updatingCurrent = true; + + item->setParentItem(effectiveContentItem(contentItem)); + QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); + contentModel->insert(index, item); + + q->itemAdded(index, item); + + if (contentModel->count() == 1 && currentIndex == -1) + q->setCurrentIndex(index); + + updatingCurrent = false; +} + +void QQuickContainerPrivate::moveItem(int from, int to) +{ + Q_Q(QQuickContainer); + int oldCurrent = currentIndex; + contentModel->move(from, to); + + updatingCurrent = true; + + if (from == oldCurrent) + q->setCurrentIndex(to); + else if (from < oldCurrent && to >= oldCurrent) + q->setCurrentIndex(oldCurrent - 1); + else if (from > oldCurrent && to <= oldCurrent) + q->setCurrentIndex(oldCurrent + 1); + + updatingCurrent = false; +} + +void QQuickContainerPrivate::removeItem(int index, QQuickItem *item) +{ + Q_Q(QQuickContainer); + if (!q->isContent(item)) + return; + contentData.removeOne(item); + + updatingCurrent = true; + + bool currentChanged = false; + if (index == currentIndex) { + q->setCurrentIndex(currentIndex - 1); + } else if (index < currentIndex) { + --currentIndex; + currentChanged = true; + } + + QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); + item->setParentItem(nullptr); + contentModel->remove(index); + + q->itemRemoved(index, item); + + if (currentChanged) + emit q->currentIndexChanged(); + + updatingCurrent = false; +} + +void QQuickContainerPrivate::_q_currentIndexChanged() +{ + Q_Q(QQuickContainer); + if (!updatingCurrent) + q->setCurrentIndex(contentItem ? contentItem->property("currentIndex").toInt() : -1); +} + +void QQuickContainerPrivate::itemChildAdded(QQuickItem *, QQuickItem *child) +{ + // add dynamically reparented items (eg. by a Repeater) + if (!QQuickItemPrivate::get(child)->isTransparentForPositioner() && !contentData.contains(child)) + insertItem(contentModel->count(), child); +} + +void QQuickContainerPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent) +{ + // remove dynamically unparented items (eg. by a Repeater) + if (!parent) + removeItem(contentModel->indexOf(item, nullptr), item); +} + +void QQuickContainerPrivate::itemSiblingOrderChanged(QQuickItem *) +{ + // reorder the restacked items (eg. by a Repeater) + Q_Q(QQuickContainer); + QList siblings = effectiveContentItem(contentItem)->childItems(); + for (int i = 0; i < siblings.count(); ++i) { + QQuickItem* sibling = siblings.at(i); + int index = contentModel->indexOf(sibling, nullptr); + q->moveItem(index, i); + } +} + +void QQuickContainerPrivate::itemDestroyed(QQuickItem *item) +{ + int index = contentModel->indexOf(item, nullptr); + if (index != -1) + removeItem(index, item); +} + +void QQuickContainerPrivate::contentData_append(QQmlListProperty *prop, QObject *obj) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + QQuickContainer *q = static_cast(prop->object); + QQuickItem *item = qobject_cast(obj); + if (item) { + if (QQuickItemPrivate::get(item)->isTransparentForPositioner()) { + QQuickItemPrivate::get(item)->addItemChangeListener(p, QQuickItemPrivate::SiblingOrder); + item->setParentItem(effectiveContentItem(p->contentItem)); + } else if (p->contentModel->indexOf(item, nullptr) == -1) { + q->addItem(item); + } + } else { + p->contentData.append(obj); + } +} + +int QQuickContainerPrivate::contentData_count(QQmlListProperty *prop) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + return p->contentData.count(); +} + +QObject *QQuickContainerPrivate::contentData_at(QQmlListProperty *prop, int index) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + return p->contentData.value(index); +} + +void QQuickContainerPrivate::contentData_clear(QQmlListProperty *prop) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + p->contentData.clear(); +} + +void QQuickContainerPrivate::contentChildren_append(QQmlListProperty *prop, QQuickItem *item) +{ + QQuickContainer *q = static_cast(prop->object); + q->addItem(item); +} + +int QQuickContainerPrivate::contentChildren_count(QQmlListProperty *prop) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + return p->contentModel->count(); +} + +QQuickItem *QQuickContainerPrivate::contentChildren_at(QQmlListProperty *prop, int index) +{ + QQuickContainer *q = static_cast(prop->object); + return q->itemAt(index); +} + +void QQuickContainerPrivate::contentChildren_clear(QQmlListProperty *prop) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + p->contentModel->clear(); +} + +QQuickContainer::QQuickContainer(QQuickItem *parent) : + QQuickControl(*(new QQuickContainerPrivate), parent) +{ + Q_D(QQuickContainer); + d->init(); +} + +QQuickContainer::QQuickContainer(QQuickContainerPrivate &dd, QQuickItem *parent) : + QQuickControl(dd, parent) +{ + Q_D(QQuickContainer); + d->init(); +} + +QQuickContainer::~QQuickContainer() +{ + Q_D(QQuickContainer); + d->cleanup(); +} + +/*! + \qmlproperty int Qt.labs.controls::Container::count + \readonly + + This property holds the number of items. +*/ +int QQuickContainer::count() const +{ + Q_D(const QQuickContainer); + return d->contentModel->count(); +} + +/*! + \qmlmethod Item Qt.labs.controls::Container::itemAt(int index) + + Returns the item at \a index, or \c null if it does not exist. +*/ +QQuickItem *QQuickContainer::itemAt(int index) const +{ + Q_D(const QQuickContainer); + return d->itemAt(index); +} + +/*! + \qmlmethod void Qt.labs.controls::Container::addItem(Item item) + + Adds an \a item. +*/ +void QQuickContainer::addItem(QQuickItem *item) +{ + Q_D(QQuickContainer); + insertItem(d->contentModel->count(), item); +} + +/*! + \qmlmethod void Qt.labs.controls::Container::insertItem(int index, Item item) + + Inserts an \a item at \a index. +*/ +void QQuickContainer::insertItem(int index, QQuickItem *item) +{ + Q_D(QQuickContainer); + if (!item) + return; + const int count = d->contentModel->count(); + if (index < 0 || index > count) + index = count; + + int oldIndex = d->contentModel->indexOf(item, nullptr); + if (oldIndex != -1) { + if (oldIndex < index) + --index; + if (oldIndex != index) + d->moveItem(oldIndex, index); + } else { + d->insertItem(index, item); + } +} + +/*! + \qmlmethod void Qt.labs.controls::Container::moveItem(int from, int to) + + Moves an item \a from one index \a to another. +*/ +void QQuickContainer::moveItem(int from, int to) +{ + Q_D(QQuickContainer); + const int count = d->contentModel->count(); + if (from < 0 || from > count - 1) + return; + if (to < 0 || to > count - 1) + to = count - 1; + + if (from != to) + d->moveItem(from, to); +} + +/*! + \qmlmethod void Qt.labs.controls::Container::removeItem(int index) + + Removes an item at \a index. + + \note The ownership of the item is transferred to the caller. +*/ +void QQuickContainer::removeItem(int index) +{ + Q_D(QQuickContainer); + const int count = d->contentModel->count(); + if (index < 0 || index >= count) + return; + + QQuickItem *item = itemAt(index); + if (item) + d->removeItem(index, item); +} + +/*! + \qmlproperty model Qt.labs.controls::Container::contentModel + \readonly + + This property holds the content model of items. +*/ +QVariant QQuickContainer::contentModel() const +{ + Q_D(const QQuickContainer); + return QVariant::fromValue(d->contentModel); +} + +/*! + \qmlproperty list Qt.labs.controls::Container::contentData + \default + + This property holds the list of content data. + + \sa Item::data +*/ +QQmlListProperty QQuickContainer::contentData() +{ + Q_D(QQuickContainer); + return QQmlListProperty(this, d, + QQuickContainerPrivate::contentData_append, + QQuickContainerPrivate::contentData_count, + QQuickContainerPrivate::contentData_at, + QQuickContainerPrivate::contentData_clear); +} + +/*! + \qmlproperty list Qt.labs.controls::Container::contentChildren + + This property holds the list of content children. + + \sa Item::children +*/ +QQmlListProperty QQuickContainer::contentChildren() +{ + Q_D(QQuickContainer); + return QQmlListProperty(this, d, + QQuickContainerPrivate::contentChildren_append, + QQuickContainerPrivate::contentChildren_count, + QQuickContainerPrivate::contentChildren_at, + QQuickContainerPrivate::contentChildren_clear); +} + +/*! + \qmlproperty int Qt.labs.controls::Container::currentIndex + + This property holds the index of the current item in the container. +*/ +int QQuickContainer::currentIndex() const +{ + Q_D(const QQuickContainer); + return d->currentIndex; +} + +void QQuickContainer::setCurrentIndex(int index) +{ + Q_D(QQuickContainer); + if (d->currentIndex == index) + return; + + d->currentIndex = index; + emit currentIndexChanged(); + emit currentItemChanged(); +} + +/*! + \qmlproperty Item Qt.labs.controls::Container::currentItem + + This property holds the current item. +*/ +QQuickItem *QQuickContainer::currentItem() const +{ + Q_D(const QQuickContainer); + return itemAt(d->currentIndex); +} + +void QQuickContainer::itemChange(ItemChange change, const ItemChangeData &data) +{ + Q_D(QQuickContainer); + QQuickControl::itemChange(change, data); + if (change == QQuickItem::ItemChildAddedChange && isComponentComplete() && data.item != d->background && data.item != d->contentItem) { + if (!QQuickItemPrivate::get(data.item)->isTransparentForPositioner() && d->contentModel->indexOf(data.item, nullptr) == -1) + addItem(data.item); + } +} + +void QQuickContainer::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_D(QQuickContainer); + QQuickControl::contentItemChange(newItem, oldItem); + + static const int slotIndex = metaObject()->indexOfSlot("_q_currentIndexChanged()"); + + if (oldItem) { + QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Children); + QQuickItem *oldContentItem = effectiveContentItem(oldItem); + if (oldContentItem != oldItem) + QQuickItemPrivate::get(oldContentItem)->removeItemChangeListener(d, QQuickItemPrivate::Children); + + int signalIndex = oldItem->metaObject()->indexOfSignal("currentIndexChanged()"); + if (signalIndex != -1) + QMetaObject::disconnect(oldItem, signalIndex, this, slotIndex); + } + + if (newItem) { + QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Children); + QQuickItem *newContentItem = effectiveContentItem(newItem); + if (newContentItem != newItem) + QQuickItemPrivate::get(newContentItem)->addItemChangeListener(d, QQuickItemPrivate::Children); + + int signalIndex = newItem->metaObject()->indexOfSignal("currentIndexChanged()"); + if (signalIndex != -1) + QMetaObject::connect(newItem, signalIndex, this, slotIndex); + } +} + +bool QQuickContainer::isContent(QQuickItem *item) const +{ + // If the item has a QML context associated to it (it was created in QML), + // we add it to the content model. Otherwise, it's probably the default + // highlight item that is always created by the item views, which we need + // to exclude. + // + // TODO: Find a better way to identify/exclude the highlight item... + return qmlContext(item); +} + +void QQuickContainer::itemAdded(int index, QQuickItem *item) +{ + Q_UNUSED(index); + Q_UNUSED(item); +} + +void QQuickContainer::itemRemoved(int index, QQuickItem *item) +{ + Q_UNUSED(index); + Q_UNUSED(item); +} + +QT_END_NAMESPACE + +#include "moc_qquickcontainer_p.cpp" diff --git a/src/quicktemplates2/qquickcontainer_p.h b/src/quicktemplates2/qquickcontainer_p.h new file mode 100644 index 00000000..4efcdba1 --- /dev/null +++ b/src/quicktemplates2/qquickcontainer_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKCONTAINER_P_H +#define QQUICKCONTAINER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickContainerPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickContainer : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(int count READ count NOTIFY countChanged FINAL) + Q_PROPERTY(QVariant contentModel READ contentModel CONSTANT FINAL) + Q_PROPERTY(QQmlListProperty contentData READ contentData FINAL) + Q_PROPERTY(QQmlListProperty contentChildren READ contentChildren NOTIFY contentChildrenChanged FINAL) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL) + Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL) + Q_CLASSINFO("DefaultProperty", "contentData") + +public: + explicit QQuickContainer(QQuickItem *parent = nullptr); + ~QQuickContainer(); + + int count() const; + Q_INVOKABLE QQuickItem *itemAt(int index) const; + Q_INVOKABLE void addItem(QQuickItem *item); + Q_INVOKABLE void insertItem(int index, QQuickItem *item); + Q_INVOKABLE void moveItem(int from, int to); + Q_INVOKABLE void removeItem(int index); + + QVariant contentModel() const; + QQmlListProperty contentData(); + QQmlListProperty contentChildren(); + + int currentIndex() const; + QQuickItem *currentItem() const; + +public Q_SLOTS: + void setCurrentIndex(int index); + +Q_SIGNALS: + void countChanged(); + void contentChildrenChanged(); + void currentIndexChanged(); + void currentItemChanged(); + +protected: + QQuickContainer(QQuickContainerPrivate &dd, QQuickItem *parent); + + void itemChange(ItemChange change, const ItemChangeData &data) override; + void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; + + virtual bool isContent(QQuickItem *item) const; + virtual void itemAdded(int index, QQuickItem *item); + virtual void itemRemoved(int index, QQuickItem *item); + +private: + Q_DISABLE_COPY(QQuickContainer) + Q_DECLARE_PRIVATE(QQuickContainer) + Q_PRIVATE_SLOT(d_func(), void _q_currentIndexChanged()) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickContainer) + +#endif // QQUICKCONTAINER_P_H diff --git a/src/quicktemplates2/qquickcontainer_p_p.h b/src/quicktemplates2/qquickcontainer_p_p.h new file mode 100644 index 00000000..25ccfda9 --- /dev/null +++ b/src/quicktemplates2/qquickcontainer_p_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKCONTAINER_P_P_H +#define QQUICKCONTAINER_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_QUICKTEMPLATES2_EXPORT QQuickContainerPrivate : public QQuickControlPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickContainer) + +public: + QQuickContainerPrivate(); + + void init(); + void cleanup(); + + QQuickItem *itemAt(int index) const; + void insertItem(int index, QQuickItem *item); + void moveItem(int from, int to); + void removeItem(int index, QQuickItem *item); + + void _q_currentIndexChanged(); + + void itemChildAdded(QQuickItem *item, QQuickItem *child) override; + void itemSiblingOrderChanged(QQuickItem *item) override; + void itemParentChanged(QQuickItem *item, QQuickItem *parent) override; + void itemDestroyed(QQuickItem *item) override; + + static void contentData_append(QQmlListProperty *prop, QObject *obj); + static int contentData_count(QQmlListProperty *prop); + static QObject *contentData_at(QQmlListProperty *prop, int index); + static void contentData_clear(QQmlListProperty *prop); + + static void contentChildren_append(QQmlListProperty *prop, QQuickItem *obj); + static int contentChildren_count(QQmlListProperty *prop); + static QQuickItem *contentChildren_at(QQmlListProperty *prop, int index); + static void contentChildren_clear(QQmlListProperty *prop); + + QObjectList contentData; + QQmlObjectModel *contentModel; + int currentIndex; + bool updatingCurrent; +}; + +QT_END_NAMESPACE + +#endif // QQUICKCONTAINER_P_P_H diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp new file mode 100644 index 00000000..2bee0ed2 --- /dev/null +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -0,0 +1,1102 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickcontrol_p.h" +#include "qquickcontrol_p_p.h" + +#include +#include +#include "qquicklabel_p.h" +#include "qquicklabel_p_p.h" +#include "qquicktextarea_p.h" +#include "qquicktextarea_p_p.h" +#include "qquicktextfield_p.h" +#include "qquicktextfield_p_p.h" +#include "qquickpopup_p.h" +#include "qquickpopup_p_p.h" +#include "qquickapplicationwindow_p.h" + +#include +#include + +#ifndef QT_NO_ACCESSIBILITY +#include +#endif + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Control + \inherits Item + \instantiates QQuickControl + \inqmlmodule Qt.labs.controls + \brief The base type of user interface controls. + + Control is the base type of user interface controls. It receives input + events from the window system, and paints a representation of itself on + the screen. + + \image qtquickcontrols-control.png + \labs +*/ + +static bool isKeyFocusReason(Qt::FocusReason reason) +{ + return reason == Qt::TabFocusReason || reason == Qt::BacktabFocusReason || reason == Qt::ShortcutFocusReason; +} + +QQuickControlPrivate::QQuickControlPrivate() : + hasTopPadding(false), hasLeftPadding(false), hasRightPadding(false), hasBottomPadding(false), hasLocale(false), hovered(false), wheelEnabled(false), + padding(0), topPadding(0), leftPadding(0), rightPadding(0), bottomPadding(0), spacing(0), + focusPolicy(Qt::NoFocus), focusReason(Qt::OtherFocusReason), + background(nullptr), contentItem(nullptr), accessibleAttached(nullptr) +{ +#ifndef QT_NO_ACCESSIBILITY + QAccessible::installActivationObserver(this); +#endif +} + +QQuickControlPrivate::~QQuickControlPrivate() +{ +#ifndef QT_NO_ACCESSIBILITY + QAccessible::removeActivationObserver(this); +#endif +} + +void QQuickControlPrivate::mirrorChange() +{ + Q_Q(QQuickControl); + if (locale.textDirection() == Qt::LeftToRight) + q->mirrorChange(); +} + +void QQuickControlPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickControl); + qreal oldPadding = q->topPadding(); + topPadding = value; + hasTopPadding = !reset; + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) { + emit q->topPaddingChanged(); + emit q->availableHeightChanged(); + q->paddingChange(QMarginsF(leftPadding, topPadding, rightPadding, bottomPadding), + QMarginsF(leftPadding, oldPadding, rightPadding, bottomPadding)); + } +} + +void QQuickControlPrivate::setLeftPadding(qreal value, bool reset) +{ + Q_Q(QQuickControl); + qreal oldPadding = q->leftPadding(); + leftPadding = value; + hasLeftPadding = !reset; + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) { + emit q->leftPaddingChanged(); + emit q->availableWidthChanged(); + q->paddingChange(QMarginsF(leftPadding, topPadding, rightPadding, bottomPadding), + QMarginsF(oldPadding, topPadding, rightPadding, bottomPadding)); + } +} + +void QQuickControlPrivate::setRightPadding(qreal value, bool reset) +{ + Q_Q(QQuickControl); + qreal oldPadding = q->rightPadding(); + rightPadding = value; + hasRightPadding = !reset; + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) { + emit q->rightPaddingChanged(); + emit q->availableWidthChanged(); + q->paddingChange(QMarginsF(leftPadding, topPadding, rightPadding, bottomPadding), + QMarginsF(leftPadding, topPadding, oldPadding, bottomPadding)); + } +} + +void QQuickControlPrivate::setBottomPadding(qreal value, bool reset) +{ + Q_Q(QQuickControl); + qreal oldPadding = q->bottomPadding(); + bottomPadding = value; + hasBottomPadding = !reset; + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) { + emit q->bottomPaddingChanged(); + emit q->availableHeightChanged(); + q->paddingChange(QMarginsF(leftPadding, topPadding, rightPadding, bottomPadding), + QMarginsF(leftPadding, topPadding, rightPadding, oldPadding)); + } +} + +void QQuickControlPrivate::resizeBackground() +{ + Q_Q(QQuickControl); + if (background) { + QQuickItemPrivate *p = QQuickItemPrivate::get(background); + if (!p->widthValid && qFuzzyIsNull(background->x())) { + background->setWidth(q->width()); + p->widthValid = false; + } + if (!p->heightValid && qFuzzyIsNull(background->y())) { + background->setHeight(q->height()); + p->heightValid = false; + } + } +} + +void QQuickControlPrivate::resizeContent() +{ + Q_Q(QQuickControl); + if (contentItem) { + contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding())); + contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight())); + } +} + +#ifndef QT_NO_ACCESSIBILITY +void QQuickControlPrivate::accessibilityActiveChanged(bool active) +{ + Q_Q(QQuickControl); + return q->accessibilityActiveChanged(active); +} + +QAccessible::Role QQuickControlPrivate::accessibleRole() const +{ + Q_Q(const QQuickControl); + return q->accessibleRole(); +} + +QAccessible::Role QQuickControl::accessibleRole() const +{ + return QAccessible::NoRole; +} + +void QQuickControl::accessibilityActiveChanged(bool active) +{ + Q_D(QQuickControl); + if (d->accessibleAttached || !active) + return; + + d->accessibleAttached = qobject_cast(qmlAttachedPropertiesObject(this, true)); + + // QQuickControl relies on the existence of a QQuickAccessibleAttached object. + // However, qmlAttachedPropertiesObject(create=true) creates an instance only + // for items that have been created by a QML engine. Therefore we create the + // object by hand for items created in C++ (QQuickPopupItem, for instance). + if (!d->accessibleAttached) + d->accessibleAttached = new QQuickAccessibleAttached(this); + + d->accessibleAttached->setRole(accessibleRole()); +} +#endif + +/*! + \internal + + Returns the font that the control w inherits from its ancestors and + QGuiApplication::font. +*/ +QFont QQuickControlPrivate::parentFont(const QQuickItem *item) +{ + QQuickItem *p = item->parentItem(); + while (p) { + if (QQuickControl *control = qobject_cast(p)) + return control->font(); + else if (QQuickLabel *label = qobject_cast(p)) + return label->font(); + else if (QQuickTextField *textField = qobject_cast(p)) + return textField->font(); + else if (QQuickTextArea *textArea = qobject_cast(p)) + return textArea->font(); + + p = p->parentItem(); + } + + if (QQuickApplicationWindow *window = qobject_cast(item->window())) + return window->font(); + + return themeFont(QPlatformTheme::SystemFont); +} + +QFont QQuickControlPrivate::themeFont(QPlatformTheme::Font type) +{ + if (QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { + if (const QFont *font = theme->font(type)) { + QFont f = *font; + if (type == QPlatformTheme::SystemFont) + f.resolve(0); + return f; + } + } + + return QFont(); +} + +/*! + \internal + + Determine which font is implicitly imposed on this control by its ancestors + and QGuiApplication::font, resolve this against its own font (attributes from + the implicit font are copied over). Then propagate this font to this + control's children. +*/ +void QQuickControlPrivate::resolveFont() +{ + Q_Q(QQuickControl); + inheritFont(parentFont(q)); +} + +void QQuickControlPrivate::inheritFont(const QFont &f) +{ + Q_Q(QQuickControl); + QFont parentFont = font.resolve(f); + parentFont.resolve(font.resolve() | f.resolve()); + + const QFont defaultFont = q->defaultFont(); + const QFont resolvedFont = parentFont.resolve(defaultFont); + + setFont_helper(resolvedFont); +} + +/*! + \internal + + Assign \a font to this control, and propagate it to all children. +*/ +void QQuickControlPrivate::updateFont(const QFont &f) +{ + Q_Q(QQuickControl); + QFont old = resolvedFont; + resolvedFont = f; + + if (old != f) + q->fontChange(f, old); + + QQuickControlPrivate::updateFontRecur(q, f); + + if (old != f) + emit q->fontChanged(); +} + +void QQuickControlPrivate::updateFontRecur(QQuickItem *item, const QFont &f) +{ + const auto childItems = item->childItems(); + for (QQuickItem *child : childItems) { + if (QQuickControl *control = qobject_cast(child)) + QQuickControlPrivate::get(control)->inheritFont(f); + else if (QQuickLabel *label = qobject_cast(child)) + QQuickLabelPrivate::get(label)->inheritFont(f); + else if (QQuickTextArea *textArea = qobject_cast(child)) + QQuickTextAreaPrivate::get(textArea)->inheritFont(f); + else if (QQuickTextField *textField = qobject_cast(child)) + QQuickTextFieldPrivate::get(textField)->inheritFont(f); + else + QQuickControlPrivate::updateFontRecur(child, f); + } +} + +QString QQuickControl::accessibleName() const +{ +#ifndef QT_NO_ACCESSIBILITY + Q_D(const QQuickControl); + if (d->accessibleAttached) + return d->accessibleAttached->name(); +#endif + return QString(); +} + +void QQuickControl::setAccessibleName(const QString &name) +{ +#ifndef QT_NO_ACCESSIBILITY + Q_D(QQuickControl); + if (d->accessibleAttached) + d->accessibleAttached->setName(name); +#else + Q_UNUSED(name) +#endif +} + +QVariant QQuickControl::accessibleProperty(const char *propertyName) +{ +#ifndef QT_NO_ACCESSIBILITY + Q_D(QQuickControl); + if (d->accessibleAttached) + return QQuickAccessibleAttached::property(this, propertyName); +#endif + Q_UNUSED(propertyName) + return QVariant(); +} + +bool QQuickControl::setAccessibleProperty(const char *propertyName, const QVariant &value) +{ +#ifndef QT_NO_ACCESSIBILITY + Q_D(QQuickControl); + if (d->accessibleAttached) + return QQuickAccessibleAttached::setProperty(this, propertyName, value); +#endif + Q_UNUSED(propertyName) + Q_UNUSED(value) + return false; +} + +QQuickControl::QQuickControl(QQuickItem *parent) : + QQuickItem(*(new QQuickControlPrivate), parent) +{ +} + +QQuickControl::QQuickControl(QQuickControlPrivate &dd, QQuickItem *parent) : + QQuickItem(dd, parent) +{ +} + +void QQuickControl::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) +{ + Q_D(QQuickControl); + QQuickItem::itemChange(change, value); + switch (change) { + case ItemParentHasChanged: + if (value.item) { + d->resolveFont(); + if (!d->hasLocale) + d->updateLocale(QQuickControlPrivate::calcLocale(d->parentItem), false); // explicit=false + } + break; + case ItemActiveFocusHasChanged: + if (isKeyFocusReason(d->focusReason)) + emit activeKeyFocusChanged(); + break; + default: + break; + } +} + +/*! + \qmlproperty font Qt.labs.controls::Control::font + + This property holds the font currently set for the control. + + This property describes the control's requested font. The font is used by the control's + style when rendering standard components, and is available as a means to ensure that custom + controls can maintain consistency with the native platform's native look and feel. It's common + that different platforms, or different styles, define different fonts for an application. + + The default font depends on the system environment. ApplicationWindow maintains a system/theme + font which serves as a default for all controls. There may also be special font defaults for + certain types of controls. You can also set the default font for controls by passing a custom + font to QGuiApplication::setFont(), before loading the QML. Finally, the font is matched + against Qt's font database to find the best match. + + Control propagates explicit font properties from parent to children. If you change a specific + property on a control's font, that property propagates to all of the control's children, + overriding any system defaults for that property. +*/ +QFont QQuickControl::font() const +{ + Q_D(const QQuickControl); + return d->resolvedFont; +} + +void QQuickControl::setFont(const QFont &font) +{ + Q_D(QQuickControl); + if (d->font.resolve() == font.resolve() && d->font == font) + return; + + d->font = font; + d->resolveFont(); +} + +void QQuickControl::resetFont() +{ + setFont(QFont()); +} + +/*! + \qmlproperty real Qt.labs.controls::Control::availableWidth + \readonly + + This property holds the width available after deducting horizontal padding. + + \sa padding, leftPadding, rightPadding +*/ +qreal QQuickControl::availableWidth() const +{ + return qMax(0.0, width() - leftPadding() - rightPadding()); +} + +/*! + \qmlproperty real Qt.labs.controls::Control::availableHeight + \readonly + + This property holds the height available after deducting vertical padding. + + \sa padding, topPadding, bottomPadding +*/ +qreal QQuickControl::availableHeight() const +{ + return qMax(0.0, height() - topPadding() - bottomPadding()); +} + +/*! + \qmlproperty real Qt.labs.controls::Control::padding + + This property holds the default padding. + + \sa availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding +*/ +qreal QQuickControl::padding() const +{ + Q_D(const QQuickControl); + return d->padding; +} + +void QQuickControl::setPadding(qreal padding) +{ + Q_D(QQuickControl); + if (qFuzzyCompare(d->padding, padding)) + return; + QMarginsF oldPadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); + d->padding = padding; + emit paddingChanged(); + QMarginsF newPadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); + if (!qFuzzyCompare(newPadding.top(), oldPadding.top())) + emit topPaddingChanged(); + if (!qFuzzyCompare(newPadding.left(), oldPadding.left())) + emit leftPaddingChanged(); + if (!qFuzzyCompare(newPadding.right(), oldPadding.right())) + emit rightPaddingChanged(); + if (!qFuzzyCompare(newPadding.bottom(), oldPadding.bottom())) + emit bottomPaddingChanged(); + if (!qFuzzyCompare(newPadding.top(), oldPadding.top()) || !qFuzzyCompare(newPadding.bottom(), oldPadding.bottom())) + emit availableHeightChanged(); + if (!qFuzzyCompare(newPadding.left(), oldPadding.left()) || !qFuzzyCompare(newPadding.right(), oldPadding.right())) + emit availableWidthChanged(); + paddingChange(newPadding, oldPadding); +} + +void QQuickControl::resetPadding() +{ + setPadding(0); +} + +/*! + \qmlproperty real Qt.labs.controls::Control::topPadding + + This property holds the top padding. + + \sa padding, bottomPadding, availableHeight +*/ +qreal QQuickControl::topPadding() const +{ + Q_D(const QQuickControl); + if (d->hasTopPadding) + return d->topPadding; + return d->padding; +} + +void QQuickControl::setTopPadding(qreal padding) +{ + Q_D(QQuickControl); + d->setTopPadding(padding); +} + +void QQuickControl::resetTopPadding() +{ + Q_D(QQuickControl); + d->setTopPadding(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Control::leftPadding + + This property holds the left padding. + + \sa padding, rightPadding, availableWidth +*/ +qreal QQuickControl::leftPadding() const +{ + Q_D(const QQuickControl); + if (d->hasLeftPadding) + return d->leftPadding; + return d->padding; +} + +void QQuickControl::setLeftPadding(qreal padding) +{ + Q_D(QQuickControl); + d->setLeftPadding(padding); +} + +void QQuickControl::resetLeftPadding() +{ + Q_D(QQuickControl); + d->setLeftPadding(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Control::rightPadding + + This property holds the right padding. + + \sa padding, leftPadding, availableWidth +*/ +qreal QQuickControl::rightPadding() const +{ + Q_D(const QQuickControl); + if (d->hasRightPadding) + return d->rightPadding; + return d->padding; +} + +void QQuickControl::setRightPadding(qreal padding) +{ + Q_D(QQuickControl); + d->setRightPadding(padding); +} + +void QQuickControl::resetRightPadding() +{ + Q_D(QQuickControl); + d->setRightPadding(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Control::bottomPadding + + This property holds the bottom padding. + + \sa padding, topPadding, availableHeight +*/ +qreal QQuickControl::bottomPadding() const +{ + Q_D(const QQuickControl); + if (d->hasBottomPadding) + return d->bottomPadding; + return d->padding; +} + +void QQuickControl::setBottomPadding(qreal padding) +{ + Q_D(QQuickControl); + d->setBottomPadding(padding); +} + +void QQuickControl::resetBottomPadding() +{ + Q_D(QQuickControl); + d->setBottomPadding(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Control::spacing + + This property holds the spacing. +*/ +qreal QQuickControl::spacing() const +{ + Q_D(const QQuickControl); + return d->spacing; +} + +void QQuickControl::setSpacing(qreal spacing) +{ + Q_D(QQuickControl); + if (!qFuzzyCompare(d->spacing, spacing)) { + d->spacing = spacing; + emit spacingChanged(); + } +} + +void QQuickControl::resetSpacing() +{ + setSpacing(0); +} + +/*! + \qmlproperty Locale Qt.labs.controls::Control::locale + + This property holds the locale of the control. + It contains locale specific properties for formatting data and numbers. + Unless a special locale has been set, this is either the parent's locale + or the default locale. + + Control propagates explicit locale properties from parent to children. + If you change a specific property on a control's locale, that property + propagates to all of the control's children, overriding any system defaults + for that property. + + \sa mirrored, {LayoutMirroring}{LayoutMirroring} +*/ +QLocale QQuickControl::locale() const +{ + Q_D(const QQuickControl); + return d->locale; +} + +void QQuickControl::setLocale(const QLocale &locale) +{ + Q_D(QQuickControl); + if (d->hasLocale && d->locale == locale) + return; + + d->updateLocale(locale, true); // explicit=true +} + +void QQuickControl::resetLocale() +{ + Q_D(QQuickControl); + if (!d->hasLocale) + return; + + d->hasLocale = false; + d->updateLocale(QQuickControlPrivate::calcLocale(d->parentItem), false); // explicit=false +} + +QLocale QQuickControlPrivate::calcLocale(const QQuickItem *item) +{ + const QQuickItem *p = item; + while (p) { + if (const QQuickControl *control = qobject_cast(p)) + return control->locale(); + + QVariant v = p->property("locale"); + if (v.isValid() && v.userType() == QMetaType::QLocale) + return v.toLocale(); + + p = p->parentItem(); + } + + if (item) { + if (QQuickApplicationWindow *window = qobject_cast(item->window())) + return window->locale(); + } + + return QLocale(); +} + +void QQuickControlPrivate::updateLocale(const QLocale &l, bool e) +{ + Q_Q(QQuickControl); + if (!e && hasLocale) + return; + + QLocale old = q->locale(); + hasLocale = e; + if (old != l) { + bool wasMirrored = q->isMirrored(); + q->localeChange(l, old); + locale = l; + QQuickControlPrivate::updateLocaleRecur(q, l); + emit q->localeChanged(); + if (wasMirrored != q->isMirrored()) + q->mirrorChange(); + } +} + +void QQuickControlPrivate::updateLocaleRecur(QQuickItem *item, const QLocale &l) +{ + const auto childItems = item->childItems(); + for (QQuickItem *child : childItems) { + if (QQuickControl *control = qobject_cast(child)) + QQuickControlPrivate::get(control)->updateLocale(l, false); + else + updateLocaleRecur(child, l); + } +} + +/*! + \qmlproperty bool Qt.labs.controls::Control::mirrored + \readonly + + This property holds whether the control is mirrored. + + This property is provided for convenience. A control is considered mirrored + when its visual layout direction is right-to-left. + + \sa locale, {LayoutMirroring}{LayoutMirroring} +*/ +bool QQuickControl::isMirrored() const +{ + Q_D(const QQuickControl); + return d->isMirrored() || d->locale.textDirection() == Qt::RightToLeft; +} + +/*! + \qmlproperty enumeration Qt.labs.controls::Control::focusPolicy + + This property determines the way the control accepts focus. + + \value Qt.TabFocus The control accepts focus by tabbing. + \value Qt.ClickFocus The control accepts focus by clicking. + \value Qt.StrongFocus The control accepts focus by both tabbing and clicking. + \value Qt.WheelFocus The control accepts focus by tabbing, clicking, and using the mouse wheel. + \value Qt.NoFocus The control does not accept focus. +*/ +Qt::FocusPolicy QQuickControl::focusPolicy() const +{ + Q_D(const QQuickControl); + uint policy = d->focusPolicy; + if (activeFocusOnTab()) + policy |= Qt::TabFocus; + return static_cast(policy); +} + +void QQuickControl::setFocusPolicy(Qt::FocusPolicy policy) +{ + Q_D(QQuickControl); + if (d->focusPolicy == policy) + return; + + d->focusPolicy = policy; + setActiveFocusOnTab(policy & Qt::TabFocus); + emit focusPolicyChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::Control::focusReason + \readonly + + This property holds the reason of the last focus change. + + \note This property does not indicate whether the control has \l {Item::activeFocus} + {active focus}, but the reason why the control either gained or lost focus. + + \value Qt.MouseFocusReason A mouse action occurred. + \value Qt.TabFocusReason The Tab key was pressed. + \value Qt.BacktabFocusReason A Backtab occurred. The input for this may include the Shift or Control keys; e.g. Shift+Tab. + \value Qt.ActiveWindowFocusReason The window system made this window either active or inactive. + \value Qt.PopupFocusReason The application opened/closed a pop-up that grabbed/released the keyboard focus. + \value Qt.ShortcutFocusReason The user typed a label's buddy shortcut + \value Qt.MenuBarFocusReason The menu bar took focus. + \value Qt.OtherFocusReason Another reason, usually application-specific. + + \sa activeKeyFocus, Item::activeFocus +*/ +Qt::FocusReason QQuickControl::focusReason() const +{ + Q_D(const QQuickControl); + return d->focusReason; +} + +void QQuickControl::setFocusReason(Qt::FocusReason reason) +{ + Q_D(QQuickControl); + if (d->focusReason == reason) + return; + + Qt::FocusReason oldReason = d->focusReason; + d->focusReason = reason; + emit focusReasonChanged(); + if (d->activeFocus && isKeyFocusReason(oldReason) != isKeyFocusReason(reason)) + emit activeKeyFocusChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::Control::activeKeyFocus + \readonly + + This property holds whether the control has active focus and the focus + reason is either \c Qt.TabFocusReason, \c Qt.BacktabFocusReason, or + \c Qt.ShortcutFocusReason. + + In general, for visualizing key focus, this property is preferred over + \l Item::activeFocus. This ensures that key focus is only visualized when + interacting with keys - not when interacting via touch or mouse. + + \sa focusReason, Item::activeFocus +*/ +bool QQuickControl::hasActiveKeyFocus() const +{ + Q_D(const QQuickControl); + return d->activeFocus && isKeyFocusReason(d->focusReason); +} + +/*! + \qmlproperty bool Qt.labs.controls::Control::hovered + \readonly + + This property holds whether the control is hovered. + + \sa hoverEnabled +*/ +bool QQuickControl::isHovered() const +{ + Q_D(const QQuickControl); + return d->hovered; +} + +void QQuickControl::setHovered(bool hovered) +{ + Q_D(QQuickControl); + if (hovered == d->hovered) + return; + + d->hovered = hovered; + emit hoveredChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::Control::hoverEnabled + + This property determines whether the control accepts hover events. The default value is \c false. + + \sa hovered +*/ +bool QQuickControl::isHoverEnabled() const +{ + Q_D(const QQuickControl); + return d->hoverEnabled; +} + +void QQuickControl::setHoverEnabled(bool enabled) +{ + Q_D(QQuickControl); + if (enabled == d->hoverEnabled) + return; + + setAcceptHoverEvents(enabled); + emit hoverEnabledChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::Control::wheelEnabled + + This property determines whether the control handles wheel events. The default value is \c false. +*/ +bool QQuickControl::isWheelEnabled() const +{ + Q_D(const QQuickControl); + return d->wheelEnabled; +} + +void QQuickControl::setWheelEnabled(bool enabled) +{ + Q_D(QQuickControl); + if (d->wheelEnabled == enabled) + return; + + d->wheelEnabled = enabled; + emit wheelEnabledChanged(); +} + +/*! + \qmlproperty Item Qt.labs.controls::Control::background + + This property holds the background item. + + \note If the background item has no explicit size specified, it automatically + follows the control's size. In most cases, there is no need to specify + width or height for a background item. +*/ +QQuickItem *QQuickControl::background() const +{ + Q_D(const QQuickControl); + return d->background; +} + +void QQuickControl::setBackground(QQuickItem *background) +{ + Q_D(QQuickControl); + if (d->background == background) + return; + + delete d->background; + d->background = background; + if (background) { + background->setParentItem(this); + if (qFuzzyIsNull(background->z())) + background->setZ(-1); + if (isComponentComplete()) + d->resizeBackground(); + } + emit backgroundChanged(); +} + +/*! + \qmlproperty Item Qt.labs.controls::Control::contentItem + + This property holds the visual content item. + + \note The content item is automatically resized inside the \l padding of the control. +*/ +QQuickItem *QQuickControl::contentItem() const +{ + Q_D(const QQuickControl); + return d->contentItem; +} + +void QQuickControl::setContentItem(QQuickItem *item) +{ + Q_D(QQuickControl); + if (d->contentItem == item) + return; + + contentItemChange(item, d->contentItem); + delete d->contentItem; + d->contentItem = item; + if (item) { + if (!item->parentItem()) + item->setParentItem(this); + if (isComponentComplete()) + d->resizeContent(); + } + emit contentItemChanged(); +} + +void QQuickControl::classBegin() +{ + Q_D(QQuickControl); + QQuickItem::classBegin(); + d->resolveFont(); +} + +void QQuickControl::componentComplete() +{ + Q_D(QQuickControl); + QQuickItem::componentComplete(); + if (!d->hasLocale) + d->locale = QQuickControlPrivate::calcLocale(d->parentItem); +#ifndef QT_NO_ACCESSIBILITY + if (!d->accessibleAttached && QAccessible::isActive()) + accessibilityActiveChanged(true); +#endif +} + +QFont QQuickControl::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::SystemFont); +} + +void QQuickControl::focusInEvent(QFocusEvent *event) +{ + QQuickItem::focusInEvent(event); + setFocusReason(event->reason()); +} + +void QQuickControl::focusOutEvent(QFocusEvent *event) +{ + QQuickItem::focusOutEvent(event); + setFocusReason(event->reason()); +} + +void QQuickControl::hoverEnterEvent(QHoverEvent *event) +{ + Q_D(QQuickControl); + setHovered(d->hoverEnabled); + event->setAccepted(d->hoverEnabled); +} + +void QQuickControl::hoverLeaveEvent(QHoverEvent *event) +{ + Q_D(QQuickControl); + setHovered(false); + event->setAccepted(d->hoverEnabled); +} + +void QQuickControl::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickControl); + if ((d->focusPolicy & Qt::ClickFocus) == Qt::ClickFocus && !QGuiApplication::styleHints()->setFocusOnTouchRelease()) + forceActiveFocus(Qt::MouseFocusReason); + + event->accept(); +} + +void QQuickControl::mouseMoveEvent(QMouseEvent *event) +{ + event->accept(); +} + +void QQuickControl::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickControl); + if ((d->focusPolicy & Qt::ClickFocus) == Qt::ClickFocus && QGuiApplication::styleHints()->setFocusOnTouchRelease()) + forceActiveFocus(Qt::MouseFocusReason); + + event->accept(); +} + +void QQuickControl::wheelEvent(QWheelEvent *event) +{ + Q_D(QQuickControl); + if ((d->focusPolicy & Qt::WheelFocus) == Qt::WheelFocus) + forceActiveFocus(Qt::MouseFocusReason); + + event->setAccepted(d->wheelEnabled); +} + +void QQuickControl::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickControl); + QQuickItem::geometryChanged(newGeometry, oldGeometry); + d->resizeBackground(); + d->resizeContent(); + if (!qFuzzyCompare(newGeometry.width(), oldGeometry.width())) + emit availableWidthChanged(); + if (!qFuzzyCompare(newGeometry.height(), oldGeometry.height())) + emit availableHeightChanged(); +} + +void QQuickControl::fontChange(const QFont &newFont, const QFont &oldFont) +{ + Q_UNUSED(newFont); + Q_UNUSED(oldFont); +} + +void QQuickControl::mirrorChange() +{ + emit mirroredChanged(); +} + +void QQuickControl::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) +{ + Q_D(QQuickControl); + Q_UNUSED(newPadding); + Q_UNUSED(oldPadding); + d->resizeContent(); +} + +void QQuickControl::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_UNUSED(newItem); + Q_UNUSED(oldItem); +} + +void QQuickControl::localeChange(const QLocale &newLocale, const QLocale &oldLocale) +{ + Q_UNUSED(newLocale); + Q_UNUSED(oldLocale); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickcontrol_p.h b/src/quicktemplates2/qquickcontrol_p.h new file mode 100644 index 00000000..086489b3 --- /dev/null +++ b/src/quicktemplates2/qquickcontrol_p.h @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKCONTROL_P_H +#define QQUICKCONTROL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickControlPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickControl : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(QFont font READ font WRITE setFont RESET resetFont NOTIFY fontChanged FINAL) + Q_PROPERTY(qreal availableWidth READ availableWidth NOTIFY availableWidthChanged FINAL) + Q_PROPERTY(qreal availableHeight READ availableHeight NOTIFY availableHeightChanged FINAL) + Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged FINAL) + Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged FINAL) + Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged FINAL) + Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged FINAL) + Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged FINAL) + Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing RESET resetSpacing NOTIFY spacingChanged FINAL) + Q_PROPERTY(QLocale locale READ locale WRITE setLocale RESET resetLocale NOTIFY localeChanged FINAL) + Q_PROPERTY(bool mirrored READ isMirrored NOTIFY mirroredChanged FINAL) + Q_PROPERTY(Qt::FocusPolicy focusPolicy READ focusPolicy WRITE setFocusPolicy NOTIFY focusPolicyChanged FINAL) + Q_PROPERTY(Qt::FocusReason focusReason READ focusReason WRITE setFocusReason NOTIFY focusReasonChanged FINAL) + Q_PROPERTY(bool activeKeyFocus READ hasActiveKeyFocus NOTIFY activeKeyFocusChanged FINAL) + Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged FINAL) + Q_PROPERTY(bool hoverEnabled READ isHoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged FINAL) + Q_PROPERTY(bool wheelEnabled READ isWheelEnabled WRITE setWheelEnabled NOTIFY wheelEnabledChanged FINAL) + Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL) + Q_PROPERTY(QQuickItem *contentItem READ contentItem WRITE setContentItem NOTIFY contentItemChanged FINAL) + +public: + explicit QQuickControl(QQuickItem *parent = nullptr); + + QFont font() const; + void setFont(const QFont &font); + void resetFont(); + + qreal availableWidth() const; + qreal availableHeight() const; + + qreal padding() const; + void setPadding(qreal padding); + void resetPadding(); + + qreal topPadding() const; + void setTopPadding(qreal padding); + void resetTopPadding(); + + qreal leftPadding() const; + void setLeftPadding(qreal padding); + void resetLeftPadding(); + + qreal rightPadding() const; + void setRightPadding(qreal padding); + void resetRightPadding(); + + qreal bottomPadding() const; + void setBottomPadding(qreal padding); + void resetBottomPadding(); + + qreal spacing() const; + void setSpacing(qreal spacing); + void resetSpacing(); + + QLocale locale() const; + void setLocale(const QLocale &locale); + void resetLocale(); + + bool isMirrored() const; + + Qt::FocusPolicy focusPolicy() const; + void setFocusPolicy(Qt::FocusPolicy policy); + + Qt::FocusReason focusReason() const; + void setFocusReason(Qt::FocusReason reason); + + bool hasActiveKeyFocus() const; + + bool isHovered() const; + void setHovered(bool hovered); + + bool isHoverEnabled() const; + void setHoverEnabled(bool enabled); + + bool isWheelEnabled() const; + void setWheelEnabled(bool enabled); + + QQuickItem *background() const; + void setBackground(QQuickItem *background); + + QQuickItem *contentItem() const; + void setContentItem(QQuickItem *item); + +Q_SIGNALS: + void fontChanged(); + void availableWidthChanged(); + void availableHeightChanged(); + void paddingChanged(); + void topPaddingChanged(); + void leftPaddingChanged(); + void rightPaddingChanged(); + void bottomPaddingChanged(); + void spacingChanged(); + void localeChanged(); + void mirroredChanged(); + void focusPolicyChanged(); + void focusReasonChanged(); + void activeKeyFocusChanged(); + void hoveredChanged(); + void hoverEnabledChanged(); + void wheelEnabledChanged(); + void backgroundChanged(); + void contentItemChanged(); + +protected: + virtual QFont defaultFont() const; + + QQuickControl(QQuickControlPrivate &dd, QQuickItem *parent); + + void classBegin() override; + void componentComplete() override; + + void itemChange(ItemChange change, const ItemChangeData &value) override; + + void focusInEvent(QFocusEvent *event) override; + void focusOutEvent(QFocusEvent *event) override; + void hoverEnterEvent(QHoverEvent *event) override; + void hoverLeaveEvent(QHoverEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void wheelEvent(QWheelEvent *event) override; + + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + + virtual void fontChange(const QFont &newFont, const QFont &oldFont); + virtual void mirrorChange(); + virtual void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding); + virtual void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem); + virtual void localeChange(const QLocale &newLocale, const QLocale &oldLocale); + +#ifndef QT_NO_ACCESSIBILITY + virtual void accessibilityActiveChanged(bool active); + virtual QAccessible::Role accessibleRole() const; +#endif + + // helper functions which avoid to check QT_NO_ACCESSIBILITY + QString accessibleName() const; + void setAccessibleName(const QString &name); + + QVariant accessibleProperty(const char *propertyName); + bool setAccessibleProperty(const char *propertyName, const QVariant &value); + +private: + Q_DISABLE_COPY(QQuickControl) + Q_DECLARE_PRIVATE(QQuickControl) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickControl) + +#endif // QQUICKCONTROL_P_H diff --git a/src/quicktemplates2/qquickcontrol_p_p.h b/src/quicktemplates2/qquickcontrol_p_p.h new file mode 100644 index 00000000..6972f3c8 --- /dev/null +++ b/src/quicktemplates2/qquickcontrol_p_p.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKCONTROL_P_P_H +#define QQUICKCONTROL_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickcontrol_p.h" + +#include +#include + +#ifndef QT_NO_ACCESSIBILITY +#include +#endif + +QT_BEGIN_NAMESPACE + +class QQuickAccessibleAttached; + +class Q_QUICKTEMPLATES2_EXPORT QQuickControlPrivate : public QQuickItemPrivate +#ifndef QT_NO_ACCESSIBILITY + , public QAccessible::ActivationObserver +#endif +{ + Q_DECLARE_PUBLIC(QQuickControl) + +public: + QQuickControlPrivate(); + virtual ~QQuickControlPrivate(); + + static QQuickControlPrivate *get(QQuickControl *control) + { + return control->d_func(); + } + + void mirrorChange() override; + + void setTopPadding(qreal value, bool reset = false); + void setLeftPadding(qreal value, bool reset = false); + void setRightPadding(qreal value, bool reset = false); + void setBottomPadding(qreal value, bool reset = false); + + void resizeBackground(); + virtual void resizeContent(); + +#ifndef QT_NO_ACCESSIBILITY + void accessibilityActiveChanged(bool active) override; + QAccessible::Role accessibleRole() const override; +#endif + + void updateFont(const QFont &f); + static void updateFontRecur(QQuickItem *item, const QFont &f); + inline void setFont_helper(const QFont &f) { + if (resolvedFont.resolve() == f.resolve() && resolvedFont == f) + return; + updateFont(f); + } + virtual void resolveFont(); + void inheritFont(const QFont &f); + static QFont parentFont(const QQuickItem *item); + static QFont themeFont(QPlatformTheme::Font type); + + void updateLocale(const QLocale &l, bool e); + static void updateLocaleRecur(QQuickItem *item, const QLocale &l); + static QLocale calcLocale(const QQuickItem *item); + + // TODO: QLazilyAllocated + QFont font; + QFont resolvedFont; + bool hasTopPadding; + bool hasLeftPadding; + bool hasRightPadding; + bool hasBottomPadding; + bool hasLocale; + bool hovered; + bool wheelEnabled; + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + qreal spacing; + QLocale locale; + Qt::FocusPolicy focusPolicy; + Qt::FocusReason focusReason; + QQuickItem *background; + QQuickItem *contentItem; + QQuickAccessibleAttached *accessibleAttached; +}; + +QT_END_NAMESPACE + +#endif // QQUICKCONTROL_P_P_H diff --git a/src/quicktemplates2/qquickdial.cpp b/src/quicktemplates2/qquickdial.cpp new file mode 100644 index 00000000..7cdca7ef --- /dev/null +++ b/src/quicktemplates2/qquickdial.cpp @@ -0,0 +1,566 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickdial_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Dial + \inherits Control + \instantiates QQuickDial + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-input + \brief A circular dial that is rotated to set a value. + + The Dial is similar to a traditional dial knob that is found on devices + such as stereos or industrial equipment. It allows the user to specify a + value within a range. + + The value of the dial is set with the \l value property. The range is + set with the \l from and \l to properties. + + The dial can be manipulated with a keyboard. It supports the following + actions: + + \table + \header \li \b {Action} \li \b {Key} + \row \li Decrease \l value by \l stepSize \li \c Qt.Key_Left + \row \li Decrease \l value by \l stepSize \li \c Qt.Key_Down + \row \li Set \l value to \l from \li \c Qt.Key_Home + \row \li Increase \l value by \l stepSize \li \c Qt.Key_Right + \row \li Increase \l value by \l stepSize \li \c Qt.Key_Up + \row \li Set \l value to \l to \li \c Qt.Key_End + \endtable + + \labs + + \sa {Customizing Dial}, {Input Controls} +*/ + +static const qreal startAngle = -140; +static const qreal endAngle = 140; + +class QQuickDialPrivate : public QQuickControlPrivate +{ + Q_DECLARE_PUBLIC(QQuickDial) + +public: + QQuickDialPrivate() : + from(0), + to(1), + value(0), + position(0), + angle(startAngle), + stepSize(0), + pressed(false), + snapMode(QQuickDial::NoSnap), + handle(nullptr) + { + } + + qreal valueAt(qreal position) const; + qreal snapPosition(qreal position) const; + qreal positionAt(const QPoint &point) const; + void setPosition(qreal position); + void updatePosition(); + + qreal from; + qreal to; + qreal value; + qreal position; + qreal angle; + qreal stepSize; + bool pressed; + QPoint pressPoint; + QQuickDial::SnapMode snapMode; + QQuickItem *handle; +}; + +qreal QQuickDialPrivate::valueAt(qreal position) const +{ + return from + (to - from) * position; +} + +qreal QQuickDialPrivate::snapPosition(qreal position) const +{ + if (qFuzzyIsNull(stepSize)) + return position; + return qRound(position / stepSize) * stepSize; +} + +qreal QQuickDialPrivate::positionAt(const QPoint &point) const +{ + qreal yy = height / 2.0 - point.y(); + qreal xx = point.x() - width / 2.0; + qreal angle = (xx || yy) ? atan2(yy, xx) : 0; + + if (angle < M_PI / -2) + angle = angle + M_PI * 2; + + qreal normalizedAngle = (M_PI * 4 / 3 - angle) / (M_PI * 10 / 6); + return normalizedAngle; +} + +void QQuickDialPrivate::setPosition(qreal pos) +{ + Q_Q(QQuickDial); + pos = qBound(0.0, pos, 1.0); + if (qFuzzyCompare(position, pos)) + return; + + position = pos; + + angle = startAngle + position * qAbs(endAngle - startAngle); + + emit q->positionChanged(); + emit q->angleChanged(); +} + +void QQuickDialPrivate::updatePosition() +{ + qreal pos = 0; + if (!qFuzzyCompare(from, to)) + pos = (value - from) / (to - from); + setPosition(pos); +} + +QQuickDial::QQuickDial(QQuickItem *parent) : + QQuickControl(*(new QQuickDialPrivate), parent) +{ + setActiveFocusOnTab(true); + setAcceptedMouseButtons(Qt::LeftButton); +} + +/*! + \qmlproperty real Qt.labs.controls::Dial::from + + This property holds the starting value for the range. The default value is \c 0.0. + + \sa to, value +*/ +qreal QQuickDial::from() const +{ + Q_D(const QQuickDial); + return d->from; +} + +void QQuickDial::setFrom(qreal from) +{ + Q_D(QQuickDial); + if (qFuzzyCompare(d->from, from)) + return; + + d->from = from; + emit fromChanged(); + if (isComponentComplete()) { + setValue(d->value); + d->updatePosition(); + } +} + +/*! + \qmlproperty real Qt.labs.controls::Dial::to + + This property holds the end value for the range. The default value is + \c 1.0. + + \sa from, value +*/ +qreal QQuickDial::to() const +{ + Q_D(const QQuickDial); + return d->to; +} + +void QQuickDial::setTo(qreal to) +{ + Q_D(QQuickDial); + if (qFuzzyCompare(d->to, to)) + return; + + d->to = to; + emit toChanged(); + if (isComponentComplete()) { + setValue(d->value); + d->updatePosition(); + } +} + +/*! + \qmlproperty real Qt.labs.controls::Dial::value + + This property holds the value in the range \c from - \c to. The default + value is \c 0.0. + + Unlike the \l position property, the \c value is not updated while the + handle is dragged. The value is updated after the value has been chosen + and the dial has been released. + + \sa position +*/ +qreal QQuickDial::value() const +{ + Q_D(const QQuickDial); + return d->value; +} + +void QQuickDial::setValue(qreal value) +{ + Q_D(QQuickDial); + if (isComponentComplete()) + value = d->from > d->to ? qBound(d->to, value, d->from) : qBound(d->from, value, d->to); + + if (qFuzzyCompare(d->value, value)) + return; + + d->value = value; + d->updatePosition(); + emit valueChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::Dial::position + \readonly + + This property holds the logical position of the handle. + + The position is defined as a percentage of the control's angle range (the + range within which the handle can be moved) scaled to \c {0.0 - 1.0}. + Unlike the \l value property, the \c position is continuously updated while + the handle is dragged. + + \sa value, angle +*/ +qreal QQuickDial::position() const +{ + Q_D(const QQuickDial); + return d->position; +} + +/*! + \qmlproperty real Qt.labs.controls::Dial::angle + \readonly + + This property holds the angle of the handle. + + Like the \l position property, angle is continuously updated while the + handle is dragged. + + \sa position +*/ +qreal QQuickDial::angle() const +{ + Q_D(const QQuickDial); + return d->angle; +} + +/*! + \qmlproperty real Qt.labs.controls::Dial::stepSize + + This property holds the step size. The default value is \c 0.0. + + \sa snapMode, increase(), decrease() +*/ +qreal QQuickDial::stepSize() const +{ + Q_D(const QQuickDial); + return d->stepSize; +} + +void QQuickDial::setStepSize(qreal step) +{ + Q_D(QQuickDial); + if (qFuzzyCompare(d->stepSize, step)) + return; + + d->stepSize = step; + emit stepSizeChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::Dial::snapMode + + This property holds the snap mode. + + The snap mode works with the \l stepSize to allow the handle to snap to + certain points along the dial. + + Possible values: + \value Dial.NoSnap The dial does not snap (default). + \value Dial.SnapAlways The dial snaps while the handle is dragged. + \value Dial.SnapOnRelease The dial does not snap while being dragged, but only after the handle is released. + + \sa stepSize +*/ +QQuickDial::SnapMode QQuickDial::snapMode() const +{ + Q_D(const QQuickDial); + return d->snapMode; +} + +void QQuickDial::setSnapMode(SnapMode mode) +{ + Q_D(QQuickDial); + if (d->snapMode == mode) + return; + + d->snapMode = mode; + emit snapModeChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::Dial::pressed + + This property holds whether the dial is pressed. + + The dial will be pressed when either the mouse is pressed over it, or a key + such as \c Qt.Key_Left is held down. If you'd prefer not to have the dial + be pressed upon key presses (due to styling reasons, for example), you can + use the \l {Keys}{Keys attached property}: + + \code + Dial { + Keys.onLeftPressed: {} + } + \endcode + + This will result in pressed only being \c true upon mouse presses. +*/ +bool QQuickDial::isPressed() const +{ + Q_D(const QQuickDial); + return d->pressed; +} + +void QQuickDial::setPressed(bool pressed) +{ + Q_D(QQuickDial); + if (d->pressed == pressed) + return; + + d->pressed = pressed; + setAccessibleProperty("pressed", pressed); + emit pressedChanged(); +} + +/*! + \qmlmethod void Qt.labs.controls::Dial::increase() + + Increases the value by \l stepSize, or \c 0.1 if stepSize is not defined. + + \sa stepSize +*/ +void QQuickDial::increase() +{ + Q_D(QQuickDial); + qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize; + setValue(d->value + step); +} + +/*! + \qmlmethod void Qt.labs.controls::Dial::decrease() + + Decreases the value by \l stepSize, or \c 0.1 if stepSize is not defined. + + \sa stepSize +*/ +void QQuickDial::decrease() +{ + Q_D(QQuickDial); + qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize; + setValue(d->value - step); +} + +/*! + \qmlproperty component Qt.labs.controls::Dial::handle + + This property holds the handle of the dial. + + The handle acts as a visual indicator of the position of the dial. + + \sa {Customizing Dial} +*/ +QQuickItem *QQuickDial::handle() const +{ + Q_D(const QQuickDial); + return d->handle; +} + +void QQuickDial::setHandle(QQuickItem *handle) +{ + Q_D(QQuickDial); + if (handle == d->handle) + return; + + d->handle = handle; + if (d->handle && !d->handle->parentItem()) + d->handle->setParentItem(this); + emit handleChanged(); +} + +void QQuickDial::keyPressEvent(QKeyEvent *event) +{ + Q_D(QQuickDial); + switch (event->key()) { + case Qt::Key_Left: + case Qt::Key_Down: + setPressed(true); + if (isMirrored()) + increase(); + else + decrease(); + break; + + case Qt::Key_Right: + case Qt::Key_Up: + setPressed(true); + if (isMirrored()) + decrease(); + else + increase(); + break; + + case Qt::Key_Home: + setPressed(true); + setValue(isMirrored() ? d->to : d->from); + break; + + case Qt::Key_End: + setPressed(true); + setValue(isMirrored() ? d->from : d->to); + break; + + default: + event->ignore(); + QQuickControl::keyPressEvent(event); + break; + } +} + +void QQuickDial::keyReleaseEvent(QKeyEvent *event) +{ + QQuickControl::keyReleaseEvent(event); + setPressed(false); +} + +void QQuickDial::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickDial); + QQuickControl::mousePressEvent(event); + d->pressPoint = event->pos(); + setPressed(true); +} + +void QQuickDial::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickDial); + QQuickControl::mouseMoveEvent(event); + if (!keepMouseGrab()) { + bool overXDragThreshold = QQuickWindowPrivate::dragOverThreshold(event->pos().x() - d->pressPoint.x(), Qt::XAxis, event); + setKeepMouseGrab(overXDragThreshold); + + if (!overXDragThreshold) { + bool overYDragThreshold = QQuickWindowPrivate::dragOverThreshold(event->pos().y() - d->pressPoint.y(), Qt::YAxis, event); + setKeepMouseGrab(overYDragThreshold); + } + } + if (keepMouseGrab()) { + qreal pos = d->positionAt(event->pos()); + if (d->snapMode == SnapAlways) + pos = d->snapPosition(pos); + d->setPosition(pos); + } +} + +void QQuickDial::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickDial); + QQuickControl::mouseReleaseEvent(event); + d->pressPoint = QPoint(); + if (keepMouseGrab()) { + qreal pos = d->positionAt(event->pos()); + if (d->snapMode != NoSnap) + pos = d->snapPosition(pos); + setValue(d->valueAt(pos)); + setKeepMouseGrab(false); + } + setPressed(false); +} + +void QQuickDial::mouseUngrabEvent() +{ + Q_D(QQuickDial); + QQuickControl::mouseUngrabEvent(); + d->pressPoint = QPoint(); + setPressed(false); +} + +void QQuickDial::mirrorChange() +{ + QQuickControl::mirrorChange(); + emit angleChanged(); +} + +void QQuickDial::componentComplete() +{ + Q_D(QQuickDial); + QQuickControl::componentComplete(); + setValue(d->value); + d->updatePosition(); +} + +#ifndef QT_NO_ACCESSIBILITY +void QQuickDial::accessibilityActiveChanged(bool active) +{ + QQuickControl::accessibilityActiveChanged(active); + + Q_D(QQuickDial); + if (active) + setAccessibleProperty("pressed", d->pressed); +} + +QAccessible::Role QQuickDial::accessibleRole() const +{ + return QAccessible::Dial; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickdial_p.h b/src/quicktemplates2/qquickdial_p.h new file mode 100644 index 00000000..11ffb3c1 --- /dev/null +++ b/src/quicktemplates2/qquickdial_p.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKDIAL_H +#define QQUICKDIAL_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickDialAttached; +class QQuickDialPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickDial : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged FINAL) + Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged FINAL) + Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged FINAL) + Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL) + Q_PROPERTY(qreal angle READ angle NOTIFY angleChanged FINAL) + Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL) + Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged FINAL) + Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged FINAL) + Q_PROPERTY(QQuickItem *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL) + +public: + explicit QQuickDial(QQuickItem *parent = nullptr); + + qreal from() const; + void setFrom(qreal from); + + qreal to() const; + void setTo(qreal to); + + qreal value() const; + void setValue(qreal value); + + qreal position() const; + + qreal angle() const; + + qreal stepSize() const; + void setStepSize(qreal step); + + enum SnapMode { + NoSnap, + SnapAlways, + SnapOnRelease + }; + Q_ENUM(SnapMode) + + SnapMode snapMode() const; + void setSnapMode(SnapMode mode); + + bool isPressed() const; + void setPressed(bool pressed); + + QQuickItem *handle() const; + void setHandle(QQuickItem *handle); + +public Q_SLOTS: + void increase(); + void decrease(); + +Q_SIGNALS: + void fromChanged(); + void toChanged(); + void valueChanged(); + void positionChanged(); + void angleChanged(); + void stepSizeChanged(); + void snapModeChanged(); + void pressedChanged(); + void handleChanged(); + +protected: + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseUngrabEvent() override; + void mirrorChange() override; + void componentComplete() override; + +#ifndef QT_NO_ACCESSIBILITY + void accessibilityActiveChanged(bool active) override; + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickDial) + Q_DECLARE_PRIVATE(QQuickDial) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickDial) + +#endif // QQUICKDIAL_H diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp new file mode 100644 index 00000000..8d8d2d78 --- /dev/null +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -0,0 +1,460 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickdrawer_p.h" +#include "qquickpopup_p_p.h" +#include "qquickvelocitycalculator_p_p.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Drawer + \inherits Popup + \instantiates QQuickDrawer + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-navigation + \ingroup qtquickcontrols2-containers + \brief Provides a swipe-based side panel. + + Drawer provides a swipe-based side panel, similar to those often used in + touch interfaces to provide a central location for navigation. + + \table + \row + \li \image qtquickcontrols-drawer-wireframe.png + Drawer can be positioned at any of the four edges of the content item. \br + In this image, it is against the left edge of the window. + + \li \image qtquickcontrols-drawer-expanded-wireframe.png + The drawer is then opened by \e "dragging" it out from the left edge \br + of the window. + \endtable + + In the image above, the application's contents are \e "pushed" across the + screen. This is achieved by applying a translation to the contents: + + \code + transform: Translate { + x: (1.0 - drawer.position) * listview.width + } + \endcode + + If you would like the application's contents to stay where they are when + the drawer is opened, don't apply a translation. + + \labs + + \sa SwipeView, {Customizing Drawer}, {Navigation Controls}, {Container Controls} +*/ + +class QQuickDrawerPrivate : public QQuickPopupPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickDrawer) + +public: + QQuickDrawerPrivate() : edge(Qt::LeftEdge), offset(0), position(0) { } + + qreal positionAt(const QPointF &point) const; + void reposition() override; + + bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); + bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); + bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); + + void prepareEnterTransition(bool notify = true) override; + void prepareExitTransition() override; + void finalizeEnterTransition() override; + void finalizeExitTransition(bool hide = true) override; + + Qt::Edge edge; + qreal offset; + qreal position; + QPointF pressPoint; + QQuickVelocityCalculator velocityCalculator; +}; + +qreal QQuickDrawerPrivate::positionAt(const QPointF &point) const +{ + Q_Q(const QQuickDrawer); + switch (edge) { + case Qt::TopEdge: + return point.y() / q->height(); + case Qt::LeftEdge: + return point.x() / q->width(); + case Qt::RightEdge: + return (q->width() - point.x()) / popupItem->width(); + case Qt::BottomEdge: + return (q->height() - point.y()) / popupItem->height(); + default: + return 0; + } +} + +void QQuickDrawerPrivate::reposition() +{ + Q_Q(QQuickDrawer); + QQuickWindow *window = q->window(); + if (!window) + return; + + switch (edge) { + case Qt::LeftEdge: + popupItem->setX((position - 1.0) * popupItem->width()); + break; + case Qt::RightEdge: + popupItem->setX(window->width() - position * popupItem->width()); + break; + case Qt::TopEdge: + popupItem->setY((position - 1.0) * popupItem->height()); + break; + case Qt::BottomEdge: + popupItem->setY(window->height() - position * popupItem->height()); + break; + } +} + +static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int threshold = -1) +{ + return QQuickWindowPrivate::dragOverThreshold(d, axis, event, threshold); +} + +bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) +{ + pressPoint = event->windowPos(); + offset = 0; + + QQuickWindow *window = item->window(); + if (!window) + return false; + + if (qFuzzyIsNull(position)) { + // only accept pressing at drag margins when fully closed + switch (edge) { + case Qt::LeftEdge: + event->setAccepted(!dragOverThreshold(event->windowPos().x(), Qt::XAxis, event)); + break; + case Qt::RightEdge: + event->setAccepted(!dragOverThreshold(window->width() - event->windowPos().x(), Qt::XAxis, event)); + break; + case Qt::TopEdge: + event->setAccepted(!dragOverThreshold(event->windowPos().y(), Qt::YAxis, event)); + break; + case Qt::BottomEdge: + event->setAccepted(!dragOverThreshold(window->height() - event->windowPos().y(), Qt::YAxis, event)); + break; + } + } else { + event->setAccepted(item->isAncestorOf(popupItem)); + } + + velocityCalculator.startMeasuring(pressPoint, event->timestamp()); + + return event->isAccepted(); +} + +bool QQuickDrawerPrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event) +{ + Q_Q(QQuickDrawer); + QQuickWindow *window = item->window(); + if (!window) + return false; + + QPointF movePoint = event->windowPos(); + + if (!popupItem->keepMouseGrab()) { + // Flickable uses a hard-coded threshold of 15 for flicking, and + // QStyleHints::startDragDistance for dragging. Drawer uses a bit + // larger threshold to avoid being too eager to steal touch (QTBUG-50045) + int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5); + bool overThreshold = false; + if (edge == Qt::LeftEdge || edge == Qt::RightEdge) + overThreshold = dragOverThreshold(movePoint.x() - pressPoint.x(), Qt::XAxis, event, threshold); + else + overThreshold = dragOverThreshold(movePoint.y() - pressPoint.y(), Qt::YAxis, event, threshold); + + if (overThreshold) { + QQuickItem *grabber = window->mouseGrabberItem(); + if (!grabber || !grabber->keepMouseGrab()) { + popupItem->grabMouse(); + popupItem->setKeepMouseGrab(overThreshold); + offset = qMin(0.0, positionAt(movePoint) - position); + } + } + } + + if (popupItem->keepMouseGrab()) + q->setPosition(positionAt(movePoint) - offset); + event->accept(); + + return popupItem->keepMouseGrab(); +} + +static const qreal openCloseVelocityThreshold = 300; + +bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event) +{ + Q_UNUSED(item); + + bool wasGrabbed = popupItem->keepMouseGrab(); + if (wasGrabbed) { + velocityCalculator.stopMeasuring(event->pos(), event->timestamp()); + const qreal velocity = velocityCalculator.velocity().x(); + + if (position > 0.7 || velocity > openCloseVelocityThreshold) { + transitionManager.transitionEnter(); + } else if (position < 0.3 || velocity < -openCloseVelocityThreshold) { + transitionManager.transitionExit(); + } else { + switch (edge) { + case Qt::LeftEdge: + if (event->x() - pressPoint.x() > 0) + transitionManager.transitionEnter(); + else + transitionManager.transitionExit(); + break; + case Qt::RightEdge: + if (event->x() - pressPoint.x() < 0) + transitionManager.transitionEnter(); + else + transitionManager.transitionExit(); + break; + case Qt::TopEdge: + if (event->y() - pressPoint.y() > 0) + transitionManager.transitionEnter(); + else + transitionManager.transitionExit(); + break; + case Qt::BottomEdge: + if (event->y() - pressPoint.y() < 0) + transitionManager.transitionEnter(); + else + transitionManager.transitionExit(); + break; + } + } + popupItem->setKeepMouseGrab(false); + } + pressPoint = QPoint(); + event->accept(); + return wasGrabbed; +} + +static QList prepareTransition(QQuickDrawer *drawer, QQuickTransition *transition, qreal to) +{ + QList actions; + if (!transition) + return actions; + + qmlExecuteDeferred(transition); + + QQmlProperty defaultTarget(drawer, QLatin1String("position")); + QQmlListProperty animations = transition->animations(); + int count = animations.count(&animations); + for (int i = 0; i < count; ++i) { + QQuickAbstractAnimation *anim = animations.at(&animations, i); + anim->setDefaultTarget(defaultTarget); + } + + actions << QQuickStateAction(drawer, QLatin1String("position"), to); + return actions; +} + +void QQuickDrawerPrivate::prepareEnterTransition(bool notify) +{ + Q_Q(QQuickDrawer); + enterActions = prepareTransition(q, enter, 1.0); + QQuickPopupPrivate::prepareEnterTransition(notify); +} + +void QQuickDrawerPrivate::prepareExitTransition() +{ + Q_Q(QQuickDrawer); + exitActions = prepareTransition(q, exit, 0.0); + QQuickPopupPrivate::prepareExitTransition(); +} + +void QQuickDrawerPrivate::finalizeEnterTransition() +{ + QQuickPopupPrivate::finalizeEnterTransition(); +} + +void QQuickDrawerPrivate::finalizeExitTransition(bool hide) +{ + QQuickPopupPrivate::finalizeExitTransition(hide = false); +} + +QQuickDrawer::QQuickDrawer(QObject *parent) : + QQuickPopup(*(new QQuickDrawerPrivate), parent) +{ + setFocus(true); + setModal(true); + setFiltersChildMouseEvents(true); + setClosePolicy(OnEscape | OnReleaseOutside); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::Drawer::edge + + This property holds the edge of the content item at which the drawer will + open from. The acceptable values are: + + \value Qt.TopEdge The top edge of the content item. + \value Qt.LeftEdge The left edge of the content item (default). + \value Qt.RightEdge The right edge of the content item. + \value Qt.BottomEdge The bottom edge of the content item. +*/ +Qt::Edge QQuickDrawer::edge() const +{ + Q_D(const QQuickDrawer); + return d->edge; +} + +void QQuickDrawer::setEdge(Qt::Edge edge) +{ + Q_D(QQuickDrawer); + if (d->edge == edge) + return; + + d->edge = edge; + if (isComponentComplete()) + d->reposition(); + emit edgeChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::Drawer::position + + This property holds the position of the drawer relative to its final + destination. That is, the position will be \c 0 when the drawer + is fully closed, and \c 1 when fully open. +*/ +qreal QQuickDrawer::position() const +{ + Q_D(const QQuickDrawer); + return d->position; +} + +void QQuickDrawer::setPosition(qreal position) +{ + Q_D(QQuickDrawer); + position = qBound(0.0, position, 1.0); + if (qFuzzyCompare(d->position, position)) + return; + + d->position = position; + if (isComponentComplete()) + d->reposition(); + emit positionChanged(); +} + +bool QQuickDrawer::childMouseEventFilter(QQuickItem *child, QEvent *event) +{ + Q_D(QQuickDrawer); + switch (event->type()) { + case QEvent::MouseButtonPress: + return d->handleMousePressEvent(child, static_cast(event)); + case QEvent::MouseMove: + return d->handleMouseMoveEvent(child, static_cast(event)); + case QEvent::MouseButtonRelease: + return d->handleMouseReleaseEvent(child, static_cast(event)); + default: + return false; + } +} + +void QQuickDrawer::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickDrawer); + QQuickPopup::mousePressEvent(event); + d->handleMousePressEvent(d->popupItem, event); +} + +void QQuickDrawer::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickDrawer); + QQuickPopup::mouseMoveEvent(event); + d->handleMouseMoveEvent(d->popupItem, event); +} + +void QQuickDrawer::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickDrawer); + QQuickPopup::mouseReleaseEvent(event); + d->handleMouseReleaseEvent(d->popupItem, event); +} + +void QQuickDrawer::mouseUngrabEvent() +{ + Q_D(QQuickDrawer); + QQuickPopup::mouseUngrabEvent(); + d->pressPoint = QPoint(); + d->velocityCalculator.reset(); +} + +bool QQuickDrawer::overlayEvent(QQuickItem *item, QEvent *event) +{ + Q_D(QQuickDrawer); + switch (event->type()) { + case QEvent::MouseButtonPress: + d->tryClose(item, static_cast(event)); + return d->handleMousePressEvent(item, static_cast(event)); + case QEvent::MouseMove: + return d->handleMouseMoveEvent(item, static_cast(event)); + case QEvent::MouseButtonRelease: + d->tryClose(item, static_cast(event)); + return d->handleMouseReleaseEvent(item, static_cast(event)); + default: + return false; + } +} + +void QQuickDrawer::componentComplete() +{ + Q_D(QQuickDrawer); + QQuickPopup::componentComplete(); + bool notify = false; + d->prepareEnterTransition(notify); + d->reposition(); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickdrawer_p.h b/src/quicktemplates2/qquickdrawer_p.h new file mode 100644 index 00000000..a6ab50ee --- /dev/null +++ b/src/quicktemplates2/qquickdrawer_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKDRAWER_P_H +#define QQUICKDRAWER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickDrawerPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickDrawer : public QQuickPopup +{ + Q_OBJECT + Q_PROPERTY(Qt::Edge edge READ edge WRITE setEdge NOTIFY edgeChanged FINAL) + Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL) + +public: + explicit QQuickDrawer(QObject *parent = nullptr); + + Qt::Edge edge() const; + void setEdge(Qt::Edge edge); + + qreal position() const; + void setPosition(qreal position); + +Q_SIGNALS: + void edgeChanged(); + void positionChanged(); + +protected: + bool childMouseEventFilter(QQuickItem *child, QEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseUngrabEvent() override; + bool overlayEvent(QQuickItem *item, QEvent *event) override; + + void componentComplete() override; + +private: + Q_DISABLE_COPY(QQuickDrawer) + Q_DECLARE_PRIVATE(QQuickDrawer) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickDrawer) + +#endif // QQUICKDRAWER_P_H diff --git a/src/quicktemplates2/qquickframe.cpp b/src/quicktemplates2/qquickframe.cpp new file mode 100644 index 00000000..265c2ba3 --- /dev/null +++ b/src/quicktemplates2/qquickframe.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickframe_p.h" +#include "qquickframe_p_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Frame + \inherits Pane + \instantiates QQuickFrame + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-containers + \brief A logical group of controls within a visual frame. + + Frame is used to layout a logical group of controls together within a + visual frame. Frame does not provide a layout of its own, but requires + you to position its contents, for instance by creating a \l RowLayout + or a \l ColumnLayout. + + Items declared as children of a Frame are automatically parented to the + Frame's contentItem. Items created dynamically need to be explicitly + parented to the contentItem. + + If only a single item is used within a Frame, it will resize to fit the + implicit size of its contained item. This makes it particularly suitable + for use together with layouts. + + \image qtquickcontrols-frame.png + + \snippet qtquickcontrols-frame.qml 1 + + \labs + + \sa {Customizing Frame}, {Container Controls} +*/ + +QQuickFrame::QQuickFrame(QQuickItem *parent) : + QQuickPane(*(new QQuickFramePrivate), parent) +{ +} + +QQuickFrame::QQuickFrame(QQuickFramePrivate &dd, QQuickItem *parent) : + QQuickPane(dd, parent) +{ +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickframe_p.h b/src/quicktemplates2/qquickframe_p.h new file mode 100644 index 00000000..d1f9b0ba --- /dev/null +++ b/src/quicktemplates2/qquickframe_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKFRAME_P_H +#define QQUICKFRAME_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickFramePrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickFrame : public QQuickPane +{ + Q_OBJECT + +public: + explicit QQuickFrame(QQuickItem *parent = nullptr); + +protected: + QQuickFrame(QQuickFramePrivate &dd, QQuickItem *parent); + +private: + Q_DISABLE_COPY(QQuickFrame) + Q_DECLARE_PRIVATE(QQuickFrame) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickFrame) + +#endif // QQUICKFRAME_P_H diff --git a/src/quicktemplates2/qquickframe_p_p.h b/src/quicktemplates2/qquickframe_p_p.h new file mode 100644 index 00000000..35cda8ae --- /dev/null +++ b/src/quicktemplates2/qquickframe_p_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKFRAME_P_P_H +#define QQUICKFRAME_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickFrame; + +class Q_QUICKTEMPLATES2_EXPORT QQuickFramePrivate : public QQuickPanePrivate +{ +}; + +QT_END_NAMESPACE + +#endif // QQUICKFRAME_P_P_H diff --git a/src/quicktemplates2/qquickgroupbox.cpp b/src/quicktemplates2/qquickgroupbox.cpp new file mode 100644 index 00000000..6efdb140 --- /dev/null +++ b/src/quicktemplates2/qquickgroupbox.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickgroupbox_p.h" +#include "qquickframe_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype GroupBox + \inherits Frame + \instantiates QQuickGroupBox + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-containers + \brief A frame with a logical group of controls. + + GroupBox is used to layout a logical group of controls together, within + a titled visual frame. GroupBox does not provide a layout of its own, but + requires you to position its contents, for instance by creating a \l RowLayout + or a \l ColumnLayout. + + Items declared as children of a GroupBox are automatically parented to the + GroupBox's contentItem. Items created dynamically need to be explicitly + parented to the contentItem. + + If only a single item is used within a GroupBox, it will resize to fit the + implicit size of its contained item. This makes it particularly suitable + for use together with layouts. + + \image qtquickcontrols-groupbox.png + + \snippet qtquickcontrols-groupbox.qml 1 + + \section2 Checkable GroupBox + + Even though GroupBox has no built-in check box, it is straightforward + to create a checkable GroupBox by pairing it with a CheckBox. + + \image qtquickcontrols-groupbox-checkable.png + + It is a common pattern to enable or disable the groupbox's children when + its checkbox is toggled on or off, but it is the application that decides + on the behavior of the groupbox. + + \snippet qtquickcontrols-groupbox-checkable.qml 1 + + \labs + + \sa CheckBox, {Customizing GroupBox}, {Container Controls} +*/ + +class QQuickGroupBoxPrivate : public QQuickFramePrivate +{ +public: + QQuickGroupBoxPrivate() : label(nullptr) { } + + QString title; + QQuickItem *label; +}; + +QQuickGroupBox::QQuickGroupBox(QQuickItem *parent) : + QQuickFrame(*(new QQuickGroupBoxPrivate), parent) +{ +} + +/*! + \qmlproperty string Qt.labs.controls::GroupBox::title + + This property holds the title. +*/ +QString QQuickGroupBox::title() const +{ + Q_D(const QQuickGroupBox); + return d->title; +} + +void QQuickGroupBox::setTitle(const QString &title) +{ + Q_D(QQuickGroupBox); + if (d->title == title) + return; + + d->title = title; + emit titleChanged(); +} + +/*! + \qmlproperty Item Qt.labs.controls::GroupBox::label + + This property holds the label item that visualizes \l title. + + \sa {Customizing GroupBox} +*/ +QQuickItem *QQuickGroupBox::label() const +{ + Q_D(const QQuickGroupBox); + return d->label; +} + +void QQuickGroupBox::setLabel(QQuickItem *label) +{ + Q_D(QQuickGroupBox); + if (d->label == label) + return; + + delete d->label; + d->label = label; + if (label && !label->parentItem()) + label->setParentItem(this); + emit labelChanged(); +} + +QFont QQuickGroupBox::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::GroupBoxTitleFont); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickgroupbox_p.h b/src/quicktemplates2/qquickgroupbox_p.h new file mode 100644 index 00000000..f1670904 --- /dev/null +++ b/src/quicktemplates2/qquickgroupbox_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKGROUPBOX_P_H +#define QQUICKGROUPBOX_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickGroupBoxPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickGroupBox : public QQuickFrame +{ + Q_OBJECT + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged FINAL) + Q_PROPERTY(QQuickItem *label READ label WRITE setLabel NOTIFY labelChanged FINAL) + +public: + explicit QQuickGroupBox(QQuickItem *parent = nullptr); + + QString title() const; + void setTitle(const QString &title); + + QQuickItem *label() const; + void setLabel(QQuickItem *label); + +Q_SIGNALS: + void titleChanged(); + void labelChanged(); + +protected: + QFont defaultFont() const override; + +private: + Q_DISABLE_COPY(QQuickGroupBox) + Q_DECLARE_PRIVATE(QQuickGroupBox) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickGroupBox) + +#endif // QQUICKGROUPBOX_P_H diff --git a/src/quicktemplates2/qquickitemdelegate.cpp b/src/quicktemplates2/qquickitemdelegate.cpp new file mode 100644 index 00000000..604c7464 --- /dev/null +++ b/src/quicktemplates2/qquickitemdelegate.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickitemdelegate_p.h" +#include "qquickcontrol_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ItemDelegate + \inherits AbstractButton + \instantiates QQuickItemDelegate + \inqmlmodule Qt.labs.controls + \brief A standard view item that can be used in various views and controls. + + \image qtquickcontrols-itemdelegate.gif + + ItemDelegate presents a standard view item. It can be used as a delegate + in various views and controls, such as \l ListView and \l ComboBox. + + ItemDelegate inherits its API from AbstractButton. For instance, you can set + \l {AbstractButton::text}{text}, make items \l {AbstractButton::checkable}{checkable}, + and react to \l {AbstractButton::clicked}{clicks} using the AbstractButton API. + + \snippet qtquickcontrols-itemdelegate.qml 1 + + \labs + + \sa {Customizing ItemDelegate}, {Delegate Controls} +*/ + +QQuickItemDelegate::QQuickItemDelegate(QQuickItem *parent) : QQuickAbstractButton(parent) +{ +} + +QQuickItemDelegate::QQuickItemDelegate(QQuickAbstractButtonPrivate &dd, QQuickItem *parent) : + QQuickAbstractButton(dd, parent) +{ +} + +QFont QQuickItemDelegate::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::ItemViewFont); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickItemDelegate::accessibleRole() const +{ + return QAccessible::ListItem; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickitemdelegate_p.h b/src/quicktemplates2/qquickitemdelegate_p.h new file mode 100644 index 00000000..b34b4283 --- /dev/null +++ b/src/quicktemplates2/qquickitemdelegate_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKITEMDELEGATE_P_H +#define QQUICKITEMDELEGATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class Q_QUICKTEMPLATES2_EXPORT QQuickItemDelegate : public QQuickAbstractButton +{ + Q_OBJECT + +public: + explicit QQuickItemDelegate(QQuickItem *parent = nullptr); + +protected: + QFont defaultFont() const override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +protected: + QQuickItemDelegate(QQuickAbstractButtonPrivate &dd, QQuickItem *parent); +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickItemDelegate) + +#endif // QQUICKITEMDELEGATE_P_H diff --git a/src/quicktemplates2/qquicklabel.cpp b/src/quicktemplates2/qquicklabel.cpp new file mode 100644 index 00000000..86eb9144 --- /dev/null +++ b/src/quicktemplates2/qquicklabel.cpp @@ -0,0 +1,251 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicklabel_p.h" +#include "qquicklabel_p_p.h" +#include "qquickcontrol_p.h" +#include "qquickcontrol_p_p.h" + +#include +#include +#include + +#ifndef QT_NO_ACCESSIBILITY +#include +#endif + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Label + \inherits Text + \instantiates QQuickLabel + \inqmlmodule Qt.labs.controls + \ingroup text + \brief A text label with inherited styling and font. + + Label extends \l Text with styling and \l {Control::font}{font} + inheritance. The default colors and font are style specific. Label + can also have a visual \l background item. + + \image qtquickcontrols-label.png + + \snippet qtquickcontrols-label.qml 1 + + You can use the properties of Text to change the appearance of the text as desired: + + \qml + Label { + text: "Hello world" + font.pixelSize: 22 + font.italic: true + } + \endqml + + \labs + + \sa {Customizing Label} +*/ + +QQuickLabel::QQuickLabel(QQuickItem *parent) : + QQuickText(*(new QQuickLabelPrivate), parent) +{ + Q_D(QQuickLabel); + QObjectPrivate::connect(this, &QQuickText::textChanged, + d, &QQuickLabelPrivate::_q_textChanged); +} + +QQuickLabel::~QQuickLabel() +{ +} + +QQuickLabelPrivate::QQuickLabelPrivate() + : background(nullptr), accessibleAttached(nullptr) +{ +#ifndef QT_NO_ACCESSIBILITY + QAccessible::installActivationObserver(this); +#endif +} + +QQuickLabelPrivate::~QQuickLabelPrivate() +{ +#ifndef QT_NO_ACCESSIBILITY + QAccessible::removeActivationObserver(this); +#endif +} + +/*! + \internal + + Determine which font is implicitly imposed on this control by its ancestors + and QGuiApplication::font, resolve this against its own font (attributes from + the implicit font are copied over). Then propagate this font to this + control's children. +*/ +void QQuickLabelPrivate::resolveFont() +{ + Q_Q(QQuickLabel); + inheritFont(QQuickControlPrivate::parentFont(q)); +} + +void QQuickLabelPrivate::inheritFont(const QFont &f) +{ + Q_Q(QQuickLabel); + QFont parentFont = font.resolve(f); + parentFont.resolve(font.resolve() | f.resolve()); + + const QFont defaultFont = QQuickControlPrivate::themeFont(QPlatformTheme::LabelFont); + const QFont resolvedFont = parentFont.resolve(defaultFont); + + const bool changed = resolvedFont != sourceFont; + q->QQuickText::setFont(resolvedFont); + if (changed) + emit q->fontChanged(); +} + +void QQuickLabelPrivate::_q_textChanged(const QString &text) +{ +#ifndef QT_NO_ACCESSIBILITY + if (accessibleAttached) + accessibleAttached->setName(text); +#else + Q_UNUSED(text) +#endif +} + +#ifndef QT_NO_ACCESSIBILITY +void QQuickLabelPrivate::accessibilityActiveChanged(bool active) +{ + if (accessibleAttached || !active) + return; + + Q_Q(QQuickLabel); + accessibleAttached = qobject_cast(qmlAttachedPropertiesObject(q, true)); + if (accessibleAttached) { + accessibleAttached->setRole(accessibleRole()); + accessibleAttached->setName(text); + } else { + qWarning() << "QQuickLabel: " << q << " QQuickAccessibleAttached object creation failed!"; + } +} + +QAccessible::Role QQuickLabelPrivate::accessibleRole() const +{ + return QAccessible::StaticText; +} +#endif + +QFont QQuickLabel::font() const +{ + return QQuickText::font(); +} + +void QQuickLabel::setFont(const QFont &font) +{ + Q_D(QQuickLabel); + if (d->font.resolve() == font.resolve() && d->font == font) + return; + + d->font = font; + d->resolveFont(); +} + +/*! + \qmlproperty Item Qt.labs.controls::Label::background + + This property holds the background item. + + \note If the background item has no explicit size specified, it automatically + follows the control's size. In most cases, there is no need to specify + width or height for a background item. + + \sa {Customizing Label} +*/ +QQuickItem *QQuickLabel::background() const +{ + Q_D(const QQuickLabel); + return d->background; +} + +void QQuickLabel::setBackground(QQuickItem *background) +{ + Q_D(QQuickLabel); + if (d->background == background) + return; + + delete d->background; + d->background = background; + if (background) { + background->setParentItem(this); + if (qFuzzyIsNull(background->z())) + background->setZ(-1); + } + emit backgroundChanged(); +} + +void QQuickLabel::classBegin() +{ + Q_D(QQuickLabel); + QQuickText::classBegin(); + d->resolveFont(); +} + +void QQuickLabel::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) +{ + Q_D(QQuickLabel); + QQuickText::itemChange(change, value); + if (change == ItemParentHasChanged && value.item) + d->resolveFont(); +} + +void QQuickLabel::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickLabel); + QQuickText::geometryChanged(newGeometry, oldGeometry); + if (d->background) { + QQuickItemPrivate *p = QQuickItemPrivate::get(d->background); + if (!p->widthValid) { + d->background->setWidth(newGeometry.width()); + p->widthValid = false; + } + if (!p->heightValid) { + d->background->setHeight(newGeometry.height()); + p->heightValid = false; + } + } +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquicklabel_p.h b/src/quicktemplates2/qquicklabel_p.h new file mode 100644 index 00000000..c0dd4cb2 --- /dev/null +++ b/src/quicktemplates2/qquicklabel_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKLABEL_P_H +#define QQUICKLABEL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickLabelPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickLabel : public QQuickText +{ + Q_OBJECT + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) // override + Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL) + +public: + explicit QQuickLabel(QQuickItem *parent = nullptr); + ~QQuickLabel(); + + QFont font() const; + void setFont(const QFont &font); + + QQuickItem *background() const; + void setBackground(QQuickItem *background); + +Q_SIGNALS: + void fontChanged(); + void backgroundChanged(); + +protected: + void classBegin() override; + + void itemChange(ItemChange change, const ItemChangeData &value) override; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + +private: + Q_DISABLE_COPY(QQuickLabel) + Q_DECLARE_PRIVATE(QQuickLabel) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickLabel) + +#endif // QQUICKLABEL_P_H diff --git a/src/quicktemplates2/qquicklabel_p_p.h b/src/quicktemplates2/qquicklabel_p_p.h new file mode 100644 index 00000000..aa24a5fd --- /dev/null +++ b/src/quicktemplates2/qquicklabel_p_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKLABEL_P_P_H +#define QQUICKLABEL_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#ifndef QT_NO_ACCESSIBILITY +#include +#endif + +QT_BEGIN_NAMESPACE + +class QQuickAccessibleAttached; + +class QQuickLabelPrivate : public QQuickTextPrivate +#ifndef QT_NO_ACCESSIBILITY + , public QAccessible::ActivationObserver +#endif +{ + Q_DECLARE_PUBLIC(QQuickLabel) + +public: + QQuickLabelPrivate(); + ~QQuickLabelPrivate(); + + static QQuickLabelPrivate *get(QQuickLabel *item) { + return static_cast(QObjectPrivate::get(item)); } + + void resizeBackground(); + void resolveFont(); + void inheritFont(const QFont &f); + + void _q_textChanged(const QString &text); + +#ifndef QT_NO_ACCESSIBILITY + void accessibilityActiveChanged(bool active) override; + QAccessible::Role accessibleRole() const override; +#endif + + QFont font; + QQuickItem *background; + QQuickAccessibleAttached *accessibleAttached; +}; + +QT_END_NAMESPACE + +#endif // QQUICKLABEL_P_P_H diff --git a/src/quicktemplates2/qquickmenu.cpp b/src/quicktemplates2/qquickmenu.cpp new file mode 100644 index 00000000..b4154dc9 --- /dev/null +++ b/src/quicktemplates2/qquickmenu.cpp @@ -0,0 +1,489 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickmenu_p.h" +#include "qquickmenu_p_p.h" +#include "qquickmenuitem_p.h" + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Menu + \inherits Popup + \instantiates QQuickMenu + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-menus + \brief A menu control that can be used as a context menu or popup menu. + + \image qtquickcontrols-menu.png + + Menu has two main use cases: + \list + \li Context menus; for example, a menu that is shown after right clicking + \li Popup menus; for example, a menu that is shown after clicking a button + \endlist + + \code + Button { + id: fileButton + text: "File" + onClicked: menu.open() + + Menu { + id: menu + y: fileButton.height + + MenuItem { + text: "New..." + } + MenuItem { + text: "Open..." + } + MenuItem { + text: "Save" + } + } + } + \endcode + + \labs + + \sa {Customizing Menu}, {Menu Controls} +*/ + +QQuickMenuPrivate::QQuickMenuPrivate() : + contentModel(nullptr) +{ + Q_Q(QQuickMenu); + contentModel = new QQmlObjectModel(q); +} + +QQuickItem *QQuickMenuPrivate::itemAt(int index) const +{ + return qobject_cast(contentModel->get(index)); +} + +void QQuickMenuPrivate::insertItem(int index, QQuickItem *item) +{ + contentData.append(item); + item->setParentItem(contentItem); + if (complete) + resizeItem(item); + QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); + contentModel->insert(index, item); +} + +void QQuickMenuPrivate::moveItem(int from, int to) +{ + contentModel->move(from, to); +} + +void QQuickMenuPrivate::removeItem(int index, QQuickItem *item) +{ + contentData.removeOne(item); + + QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); + item->setParentItem(nullptr); + contentModel->remove(index); +} + +void QQuickMenuPrivate::resizeItem(QQuickItem *item) +{ + if (!item || !contentItem) + return; + + QQuickItemPrivate *p = QQuickItemPrivate::get(item); + if (!p->widthValid) { + item->setWidth(contentItem->width()); + p->widthValid = false; + } +} + +void QQuickMenuPrivate::resizeItems() +{ + if (!contentModel) + return; + + for (int i = 0; i < contentModel->count(); ++i) + resizeItem(itemAt(i)); +} + +void QQuickMenuPrivate::itemChildAdded(QQuickItem *, QQuickItem *child) +{ + // add dynamically reparented items (eg. by a Repeater) + if (!QQuickItemPrivate::get(child)->isTransparentForPositioner() && !contentData.contains(child)) + insertItem(contentModel->count(), child); +} + +void QQuickMenuPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent) +{ + // remove dynamically unparented items (eg. by a Repeater) + if (!parent) + removeItem(contentModel->indexOf(item, nullptr), item); +} + +void QQuickMenuPrivate::itemSiblingOrderChanged(QQuickItem *) +{ + // reorder the restacked items (eg. by a Repeater) + Q_Q(QQuickMenu); + QList siblings = contentItem->childItems(); + for (int i = 0; i < siblings.count(); ++i) { + QQuickItem* sibling = siblings.at(i); + int index = contentModel->indexOf(sibling, nullptr); + q->moveItem(index, i); + } +} + +void QQuickMenuPrivate::itemDestroyed(QQuickItem *item) +{ + int index = contentModel->indexOf(item, nullptr); + if (index != -1) + removeItem(index, item); +} + +void QQuickMenuPrivate::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) +{ + if (complete) + resizeItems(); +} + +void QQuickMenuPrivate::onItemPressed() +{ + Q_Q(QQuickMenu); + QQuickItem *item = qobject_cast(q->sender()); + if (item) + item->forceActiveFocus(); +} + +void QQuickMenuPrivate::onItemActiveFocusChanged() +{ + Q_Q(QQuickMenu); + QQuickItem *item = qobject_cast(q->sender()); + if (!item->hasActiveFocus()) + return; + + int indexOfItem = contentModel->indexOf(item, nullptr); + setCurrentIndex(indexOfItem); +} + +int QQuickMenuPrivate::currentIndex() const +{ + QVariant index = contentItem->property("currentIndex"); + if (!index.isValid()) + return -1; + return index.toInt(); +} + +void QQuickMenuPrivate::setCurrentIndex(int index) +{ + contentItem->setProperty("currentIndex", index); +} + +void QQuickMenuPrivate::contentData_append(QQmlListProperty *prop, QObject *obj) +{ + QQuickMenuPrivate *p = static_cast(prop->data); + QQuickMenu *q = static_cast(prop->object); + QQuickItem *item = qobject_cast(obj); + if (item) { + if (QQuickItemPrivate::get(item)->isTransparentForPositioner()) { + QQuickItemPrivate::get(item)->addItemChangeListener(p, QQuickItemPrivate::SiblingOrder); + item->setParentItem(p->contentItem); + } else if (p->contentModel->indexOf(item, nullptr) == -1) { + q->addItem(item); + + QQuickMenuItem *menuItem = qobject_cast(item); + if (menuItem) { + QObjectPrivate::connect(menuItem, &QQuickMenuItem::pressed, p, &QQuickMenuPrivate::onItemPressed); + QObject::connect(menuItem, &QQuickMenuItem::triggered, q, &QQuickPopup::close); + QObjectPrivate::connect(menuItem, &QQuickItem::activeFocusChanged, p, &QQuickMenuPrivate::onItemActiveFocusChanged); + } + } + } else { + p->contentData.append(obj); + } +} + +int QQuickMenuPrivate::contentData_count(QQmlListProperty *prop) +{ + QQuickMenuPrivate *p = static_cast(prop->data); + return p->contentData.count(); +} + +QObject *QQuickMenuPrivate::contentData_at(QQmlListProperty *prop, int index) +{ + QQuickMenuPrivate *p = static_cast(prop->data); + return p->contentData.value(index); +} + +void QQuickMenuPrivate::contentData_clear(QQmlListProperty *prop) +{ + QQuickMenuPrivate *p = static_cast(prop->data); + p->contentData.clear(); +} + +QQuickMenu::QQuickMenu(QObject *parent) : + QQuickPopup(*(new QQuickMenuPrivate), parent) +{ + setFocus(true); + setClosePolicy(OnEscape | OnPressOutside | OnReleaseOutside); +} + +/*! + \qmlmethod Item Qt.labs.controls::Menu::itemAt(int index) + + Returns the item at \a index, or \c null if it does not exist. +*/ +QQuickItem *QQuickMenu::itemAt(int index) const +{ + Q_D(const QQuickMenu); + return d->itemAt(index); +} + +/*! + \qmlmethod void Qt.labs.controls::Menu::addItem(Item item) + + Adds \a item to the end of the list of items. +*/ +void QQuickMenu::addItem(QQuickItem *item) +{ + Q_D(QQuickMenu); + insertItem(d->contentModel->count(), item); +} + +/*! + \qmlmethod void Qt.labs.controls::Menu::insertItem(int index, Item item) + + Inserts \a item at \a index. +*/ +void QQuickMenu::insertItem(int index, QQuickItem *item) +{ + Q_D(QQuickMenu); + if (!item) + return; + const int count = d->contentModel->count(); + if (index < 0 || index > count) + index = count; + + int oldIndex = d->contentModel->indexOf(item, nullptr); + if (oldIndex != -1) { + if (oldIndex < index) + --index; + if (oldIndex != index) + d->moveItem(oldIndex, index); + } else { + d->insertItem(index, item); + } +} + +/*! + \qmlmethod void Qt.labs.controls::Menu::moveItem(int from, int to) + + Moves an item \a from one index \a to another. +*/ +void QQuickMenu::moveItem(int from, int to) +{ + Q_D(QQuickMenu); + const int count = d->contentModel->count(); + if (from < 0 || from > count - 1) + return; + if (to < 0 || to > count - 1) + to = count - 1; + + if (from != to) + d->moveItem(from, to); +} + +/*! + \qmlmethod void Qt.labs.controls::Menu::removeItem(int index) + + Removes an item at \a index. + + \note The ownership of the item is transferred to the caller. +*/ +void QQuickMenu::removeItem(int index) +{ + Q_D(QQuickMenu); + const int count = d->contentModel->count(); + if (index < 0 || index >= count) + return; + + QQuickItem *item = itemAt(index); + if (item) + d->removeItem(index, item); +} + +/*! + \qmlproperty model Qt.labs.controls::Menu::contentModel + \readonly + + This property holds the model used to display menu items. + + By default, the model is an \l ObjectModel, in order to allow declaring + menu items as children of the menu. +*/ +QVariant QQuickMenu::contentModel() const +{ + Q_D(const QQuickMenu); + return QVariant::fromValue(d->contentModel); +} + +/*! + \qmlproperty list Qt.labs.controls::Menu::contentData + \default + + This property holds the list of content data. + + \sa Item::data +*/ +QQmlListProperty QQuickMenu::contentData() +{ + Q_D(QQuickMenu); + return QQmlListProperty(this, d, + QQuickMenuPrivate::contentData_append, + QQuickMenuPrivate::contentData_count, + QQuickMenuPrivate::contentData_at, + QQuickMenuPrivate::contentData_clear); +} + +/*! + \qmlproperty string Qt.labs.controls::Menu::title + + Title for the menu as a submenu or in a menubar. + + Its value defaults to an empty string. +*/ +QString QQuickMenu::title() const +{ + Q_D(const QQuickMenu); + return d->title; +} + +void QQuickMenu::setTitle(QString &title) +{ + Q_D(QQuickMenu); + if (title == d->title) + return; + d->title = title; + emit titleChanged(); +} + +void QQuickMenu::componentComplete() +{ + Q_D(QQuickMenu); + QQuickPopup::componentComplete(); + d->resizeItems(); +} + +void QQuickMenu::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_D(QQuickMenu); + Q_UNUSED(oldItem); + QQuickPopup::contentItemChange(newItem, oldItem); + d->contentItem = newItem; +} + +void QQuickMenu::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) +{ + Q_D(QQuickMenu); + QQuickPopup::itemChange(change, data); + + if (change == QQuickItem::ItemVisibleHasChanged) { + if (!data.boolValue) { + // Ensure that when the menu isn't visible, there's no current item + // the next time it's opened. + QQuickItem *focusItem = QQuickItemPrivate::get(d->contentItem)->subFocusItem; + if (focusItem) { + QQuickWindow *window = QQuickPopup::window(); + if (window) + QQuickWindowPrivate::get(window)->clearFocusInScope(d->contentItem, focusItem, Qt::OtherFocusReason); + } + d->setCurrentIndex(-1); + } + } +} + +void QQuickMenu::keyReleaseEvent(QKeyEvent *event) +{ + Q_D(QQuickMenu); + QQuickPopup::keyReleaseEvent(event); + if (d->contentModel->count() == 0) + return; + + // QTBUG-17051 + // Work around the fact that ListView has no way of distinguishing between + // mouse and keyboard interaction, thanks to the "interactive" bool in Flickable. + // What we actually want is to have a way to always allow keyboard interaction but + // only allow flicking with the mouse when there are too many menu items to be + // shown at once. + switch (event->key()) { + case Qt::Key_Up: + if (d->contentItem->metaObject()->indexOfMethod("decrementCurrentIndex()") != -1) + QMetaObject::invokeMethod(d->contentItem, "decrementCurrentIndex"); + break; + + case Qt::Key_Down: + if (d->contentItem->metaObject()->indexOfMethod("incrementCurrentIndex()") != -1) + QMetaObject::invokeMethod(d->contentItem, "incrementCurrentIndex"); + break; + + default: + break; + } + + int index = d->currentIndex(); + QQuickItem *item = itemAt(index); + if (item) + item->forceActiveFocus(); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickMenu::accessibleRole() const +{ + return QAccessible::PopupMenu; +} +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +#include "moc_qquickmenu_p.cpp" diff --git a/src/quicktemplates2/qquickmenu_p.h b/src/quicktemplates2/qquickmenu_p.h new file mode 100644 index 00000000..47834a59 --- /dev/null +++ b/src/quicktemplates2/qquickmenu_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKMENU_P_H +#define QQUICKMENU_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include "qquickpopup_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickMenuItem; +class QQuickMenuPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickMenu : public QQuickPopup +{ + Q_OBJECT + Q_PROPERTY(QVariant contentModel READ contentModel CONSTANT FINAL) + Q_PROPERTY(QQmlListProperty contentData READ contentData FINAL) + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) + Q_CLASSINFO("DefaultProperty", "contentData") + +public: + explicit QQuickMenu(QObject *parent = nullptr); + + Q_INVOKABLE QQuickItem *itemAt(int index) const; + Q_INVOKABLE void addItem(QQuickItem *item); + Q_INVOKABLE void insertItem(int index, QQuickItem *item); + Q_INVOKABLE void moveItem(int from, int to); + Q_INVOKABLE void removeItem(int index); + + QVariant contentModel() const; + QQmlListProperty contentData(); + + QString title() const; + void setTitle(QString &title); + +protected: + void componentComplete() override; + void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; + void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) override; + void keyReleaseEvent(QKeyEvent *event) override; + +Q_SIGNALS: + void titleChanged(); + +protected: +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif // QT_NO_ACCESSIBILITY + +private: + Q_DISABLE_COPY(QQuickMenu) + Q_DECLARE_PRIVATE(QQuickMenu) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickMenu) + +#endif // QQUICKMENU_P_H diff --git a/src/quicktemplates2/qquickmenu_p_p.h b/src/quicktemplates2/qquickmenu_p_p.h new file mode 100644 index 00000000..bc118f14 --- /dev/null +++ b/src/quicktemplates2/qquickmenu_p_p.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKMENU_P_P_H +#define QQUICKMENU_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QQmlObjectModel; + +class Q_QUICKTEMPLATES2_EXPORT QQuickMenuPrivate : public QQuickPopupPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickMenu) + +public: + QQuickMenuPrivate(); + + QQuickItem *itemAt(int index) const; + void insertItem(int index, QQuickItem *item); + void moveItem(int from, int to); + void removeItem(int index, QQuickItem *item); + + void resizeItem(QQuickItem *item); + void resizeItems(); + + void itemChildAdded(QQuickItem *item, QQuickItem *child) override; + void itemSiblingOrderChanged(QQuickItem *item) override; + void itemParentChanged(QQuickItem *item, QQuickItem *parent) override; + void itemDestroyed(QQuickItem *item) override; + void itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &oldGeometry) override; + + void onItemPressed(); + void onItemActiveFocusChanged(); + + int currentIndex() const; + void setCurrentIndex(int index); + + static void contentData_append(QQmlListProperty *prop, QObject *obj); + static int contentData_count(QQmlListProperty *prop); + static QObject *contentData_at(QQmlListProperty *prop, int index); + static void contentData_clear(QQmlListProperty *prop); + + QQuickItem *contentItem; // TODO: cleanup + QVector contentData; + QQmlObjectModel *contentModel; + QString title; +}; + +QT_END_NAMESPACE + +#endif // QQUICKMENU_P_P_H + diff --git a/src/quicktemplates2/qquickmenuitem.cpp b/src/quicktemplates2/qquickmenuitem.cpp new file mode 100644 index 00000000..daf426e6 --- /dev/null +++ b/src/quicktemplates2/qquickmenuitem.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickmenuitem_p.h" +#include "qquickabstractbutton_p_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype MenuItem + \inherits Control + \instantiates QQuickMenuItem + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-menus + \brief A menu item within a Menu. + + MenuItem is a convenience type that implements the AbstractButton API, + providing an easy way to respond to menu items being clicked, for example. + + \code + Button { + id: fileButton + text: "File" + onClicked: menu.open() + } + Menu { + id: menu + anchor.target: fileButton + + MenuItem { + text: "New..." + } + MenuItem { + text: "Open..." + } + MenuItem { + text: "Save" + } + } + \endcode + + \labs + + \sa {Customizing MenuItem}, {Menu Controls} +*/ + +/*! + \qmlsignal void Qt.labs.controls::MenuItem::triggered() + + This signal is emitted when the menu item is triggered by the user. +*/ + +QQuickMenuItem::QQuickMenuItem(QQuickItem *parent) : + QQuickAbstractButton(parent) +{ + connect(this, &QQuickAbstractButton::clicked, this, &QQuickMenuItem::triggered); +} + +/*! + \qmlproperty bool Qt.labs.controls::MenuItem::checkable + + This property holds whether the menu item is checkable. +*/ + +void QQuickMenuItem::checkableChange() +{ + emit checkableChanged(); +} + +QFont QQuickMenuItem::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::MenuItemFont); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickMenuItem::accessibleRole() const +{ + return QAccessible::MenuItem; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickmenuitem_p.h b/src/quicktemplates2/qquickmenuitem_p.h new file mode 100644 index 00000000..999a6445 --- /dev/null +++ b/src/quicktemplates2/qquickmenuitem_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKMENUITEM_P_H +#define QQUICKMENUITEM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickMenuItemPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickMenuItem : public QQuickAbstractButton +{ + Q_OBJECT + Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY checkableChanged FINAL) + +public: + explicit QQuickMenuItem(QQuickItem *parent = nullptr); + +Q_SIGNALS: + void checkableChanged(); + void triggered(); + +protected: + void checkableChange() override; + QFont defaultFont() const override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickMenuItem) + Q_DECLARE_PRIVATE(QQuickMenuItem) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickMenuItem) + +#endif // QQUICKMENUITEM_P_H diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp new file mode 100644 index 00000000..4977d08d --- /dev/null +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickoverlay_p.h" +#include "qquickpopup_p_p.h" +#include "qquickdrawer_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickOverlayPrivate : public QQuickItemPrivate +{ + Q_DECLARE_PUBLIC(QQuickOverlay) + +public: + QQuickOverlayPrivate(); + + void popupAboutToShow(); + void popupAboutToHide(); + void drawerPositionChange(); + void resizeBackground(); + + QQuickItem *background; + QVector drawers; + QVector popups; + QPointer mouseGrabberPopup; + int modalPopups; +}; + +void QQuickOverlayPrivate::popupAboutToShow() +{ + Q_Q(QQuickOverlay); + if (!background) + return; + + QQuickPopup *popup = qobject_cast(q->sender()); + if (!popup || !popup->isModal()) + return; + + // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors + QQmlProperty::write(background, QStringLiteral("opacity"), 1.0); +} + +void QQuickOverlayPrivate::popupAboutToHide() +{ + Q_Q(QQuickOverlay); + if (!background || modalPopups > 1) + return; + + QQuickPopup *popup = qobject_cast(q->sender()); + if (!popup || !popup->isModal()) + return; + + // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors + QQmlProperty::write(background, QStringLiteral("opacity"), 0.0); +} + +void QQuickOverlayPrivate::drawerPositionChange() +{ + Q_Q(QQuickOverlay); + QQuickDrawer *drawer = qobject_cast(q->sender()); + if (!background || !drawer || !drawer->isModal()) + return; + + // call QQuickItem::setOpacity() directly to avoid triggering QML Behaviors + // which would make the fading feel laggy compared to the drawer movement + background->setOpacity(drawer->position()); +} + +void QQuickOverlayPrivate::resizeBackground() +{ + Q_Q(QQuickOverlay); + background->setWidth(q->width()); + background->setHeight(q->height()); +} + +QQuickOverlayPrivate::QQuickOverlayPrivate() : + background(nullptr), + modalPopups(0) +{ +} + +QQuickOverlay::QQuickOverlay(QQuickItem *parent) + : QQuickItem(*(new QQuickOverlayPrivate), parent) +{ + setAcceptedMouseButtons(Qt::AllButtons); + setFiltersChildMouseEvents(true); + setVisible(false); +} + + +QQuickItem *QQuickOverlay::background() const +{ + Q_D(const QQuickOverlay); + return d->background; +} + +void QQuickOverlay::setBackground(QQuickItem *background) +{ + Q_D(QQuickOverlay); + if (d->background == background) + return; + + delete d->background; + d->background = background; + if (background) { + background->setOpacity(0.0); + background->setParentItem(this); + if (qFuzzyIsNull(background->z())) + background->setZ(-1); + if (isComponentComplete()) + d->resizeBackground(); + } + emit backgroundChanged(); +} + +void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) +{ + Q_D(QQuickOverlay); + QQuickItem::itemChange(change, data); + + QQuickPopup *popup = nullptr; + if (change == ItemChildAddedChange || change == ItemChildRemovedChange) { + popup = qobject_cast(data.item->parent()); + setVisible(!childItems().isEmpty()); + } + if (!popup) + return; + + if (change == ItemChildAddedChange) { + d->popups.append(popup); + + QQuickDrawer *drawer = qobject_cast(popup); + if (drawer) { + QObjectPrivate::connect(drawer, &QQuickDrawer::positionChanged, d, &QQuickOverlayPrivate::drawerPositionChange); + d->drawers.append(drawer); + } else { + if (popup->isModal()) + ++d->modalPopups; + + QObjectPrivate::connect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); + QObjectPrivate::connect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); + } + } else if (change == ItemChildRemovedChange) { + d->popups.removeOne(popup); + + QQuickDrawer *drawer = qobject_cast(popup); + if (drawer) { + QObjectPrivate::disconnect(drawer, &QQuickDrawer::positionChanged, d, &QQuickOverlayPrivate::drawerPositionChange); + d->drawers.removeOne(drawer); + } else { + if (popup->isModal()) + --d->modalPopups; + + QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); + QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); + } + } +} + +void QQuickOverlay::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickOverlay); + QQuickItem::geometryChanged(newGeometry, oldGeometry); + if (d->background) + d->resizeBackground(); +} + +bool QQuickOverlay::event(QEvent *event) +{ + Q_D(QQuickOverlay); + switch (event->type()) { + case QEvent::MouseButtonPress: + emit pressed(); + for (auto it = d->popups.crbegin(), end = d->popups.crend(); it != end; ++it) { + if ((*it)->overlayEvent(this, event)) { + d->mouseGrabberPopup = *it; + return true; + } + } + break; + case QEvent::MouseMove: + if (d->mouseGrabberPopup) { + if (d->mouseGrabberPopup->overlayEvent(this, event)) + return true; + } else { + for (auto it = d->popups.crbegin(), end = d->popups.crend(); it != end; ++it) { + if ((*it)->overlayEvent(this, event)) + return true; + } + } + break; + case QEvent::MouseButtonRelease: + emit released(); + if (d->mouseGrabberPopup) { + QQuickPopup *grabber = d->mouseGrabberPopup; + d->mouseGrabberPopup = nullptr; + if (grabber->overlayEvent(this, event)) + return true; + } else { + for (auto it = d->popups.crbegin(), end = d->popups.crend(); it != end; ++it) { + if ((*it)->overlayEvent(this, event)) + return true; + } + } + break; + default: + break; + } + + return QQuickItem::event(event); +} + +bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event) +{ + Q_D(QQuickOverlay); + if (d->modalPopups == 0) + return false; + // TODO Filter touch events + if (event->type() != QEvent::MouseButtonPress) + return false; + while (item->parentItem() != this) + item = item->parentItem(); + + const QList sortedChildren = d->paintOrderChildItems(); + for (auto it = sortedChildren.rbegin(), end = sortedChildren.rend(); it != end; ++it) { + QQuickItem *popupItem = *it; + if (popupItem == item) + break; + + QQuickPopup *popup = qobject_cast(popupItem->parent()); + if (popup && popup->overlayEvent(item, event)) + return true; + } + + return false; +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickoverlay_p.h b/src/quicktemplates2/qquickoverlay_p.h new file mode 100644 index 00000000..0ea51aea --- /dev/null +++ b/src/quicktemplates2/qquickoverlay_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKOVERLAY_P_H +#define QQUICKOVERLAY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickOverlayPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickOverlay : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL) + +public: + explicit QQuickOverlay(QQuickItem *parent = nullptr); + + QQuickItem *background() const; + void setBackground(QQuickItem *background); + +Q_SIGNALS: + void backgroundChanged(); + void pressed(); + void released(); + +protected: + void itemChange(ItemChange change, const ItemChangeData &data) override; + void geometryChanged(const QRectF &oldGeometry, const QRectF &newGeometry) override; + + bool event(QEvent *event) override; + bool childMouseEventFilter(QQuickItem *item, QEvent *event) override; + +private: + Q_DISABLE_COPY(QQuickOverlay) + Q_DECLARE_PRIVATE(QQuickOverlay) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickOverlay) + +#endif // QQUICKOVERLAY_P_H diff --git a/src/quicktemplates2/qquickpage.cpp b/src/quicktemplates2/qquickpage.cpp new file mode 100644 index 00000000..8e0b542f --- /dev/null +++ b/src/quicktemplates2/qquickpage.cpp @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpage_p.h" +#include "qquickcontrol_p_p.h" +#include "qquicktoolbar_p.h" +#include "qquicktabbar_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Page + \inherits Control + \instantiates QQuickPage + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-containers + \brief A control that makes it convenient to add a header and footer to a page. + + Page is a container control which makes it convenient to add + a \l header and \l footer item to a page. + + \image qtquickcontrols-page-wireframe.png + + The following example snippet illustrates how to use a page-specific + toolbar header and an application-wide tabbar footer. + + \qml + import Qt.labs.controls 1.0 + + ApplicationWindow { + visible: true + + StackView { + anchors.fill: parent + + initialItem: Page { + header: ToolBar { + // ... + } + } + } + + footer: TabBar { + // ... + } + } + \endqml + + \sa ApplicationWindow, {Container Controls} +*/ + +class QQuickPagePrivate : public QQuickControlPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickPage) + +public: + QQuickPagePrivate(); + + void relayout(); + + void itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect) override; + void itemVisibilityChanged(QQuickItem *item) override; + void itemImplicitWidthChanged(QQuickItem *item) override; + void itemImplicitHeightChanged(QQuickItem *item) override; + + QQuickItem *header; + QQuickItem *footer; +}; + +QQuickPagePrivate::QQuickPagePrivate() : header(nullptr), footer(nullptr) +{ +} + +void QQuickPagePrivate::relayout() +{ + Q_Q(QQuickPage); + QQuickItem *content = q->contentItem(); + const qreal hh = header ? header->height() : 0; + const qreal fh = footer ? footer->height() : 0; + + content->setY(hh + q->topPadding()); + content->setX(q->leftPadding()); + content->setWidth(q->availableWidth()); + content->setHeight(q->availableHeight() - hh - fh); + + if (header) + header->setWidth(q->width()); + + if (footer) { + footer->setY(q->height() - fh); + footer->setWidth(q->width()); + } +} + +void QQuickPagePrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect) +{ + Q_UNUSED(item) + Q_UNUSED(newRect) + Q_UNUSED(oldRect) + relayout(); +} + +void QQuickPagePrivate::itemVisibilityChanged(QQuickItem *item) +{ + Q_UNUSED(item); + relayout(); +} + +void QQuickPagePrivate::itemImplicitWidthChanged(QQuickItem *item) +{ + Q_UNUSED(item); + relayout(); +} + +void QQuickPagePrivate::itemImplicitHeightChanged(QQuickItem *item) +{ + Q_UNUSED(item); + relayout(); +} + +QQuickPage::QQuickPage(QQuickItem *parent) : + QQuickControl(*(new QQuickPagePrivate), parent) +{ + setFlag(ItemIsFocusScope); + setAcceptedMouseButtons(Qt::AllButtons); +} + +/*! + \qmlproperty Item Qt.labs.controls::Page::header + + This property holds the page header item. The header item is positioned to + the top, and resized to the width of the page. The default value is \c null. + + \note Assigning a ToolBar or TabBar as a page header sets the respective + \l ToolBar::position or \l TabBar::position property automatically to \c Header. + + \sa footer, ApplicationWindow::header +*/ +QQuickItem *QQuickPage::header() const +{ + Q_D(const QQuickPage); + return d->header; +} + +void QQuickPage::setHeader(QQuickItem *header) +{ + Q_D(QQuickPage); + if (d->header == header) + return; + + if (d->header) { + QQuickItemPrivate::get(d->header)->removeItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | + QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight); + d->header->setParentItem(nullptr); + } + d->header = header; + if (header) { + header->setParentItem(this); + QQuickItemPrivate *p = QQuickItemPrivate::get(header); + p->addItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | + QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight); + if (qFuzzyIsNull(header->z())) + header->setZ(1); + if (QQuickToolBar *toolBar = qobject_cast(header)) + toolBar->setPosition(QQuickToolBar::Header); + else if (QQuickTabBar *tabBar = qobject_cast(header)) + tabBar->setPosition(QQuickTabBar::Header); + } + if (isComponentComplete()) + d->relayout(); + emit headerChanged(); +} + +/*! + \qmlproperty Item Qt.labs.controls::Page::footer + + This property holds the page footer item. The footer item is positioned to + the bottom, and resized to the width of the page. The default value is \c null. + + \note Assigning a ToolBar or TabBar as a page footer sets the respective + \l ToolBar::position or \l TabBar::position property automatically to \c Footer. + + \sa header, ApplicationWindow::footer +*/ +QQuickItem *QQuickPage::footer() const +{ + Q_D(const QQuickPage); + return d->footer; +} + +void QQuickPage::setFooter(QQuickItem *footer) +{ + Q_D(QQuickPage); + if (d->footer == footer) + return; + + if (d->footer) { + QQuickItemPrivate::get(d->footer)->removeItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | + QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight); + d->footer->setParentItem(nullptr); + } + d->footer = footer; + if (footer) { + footer->setParentItem(this); + QQuickItemPrivate *p = QQuickItemPrivate::get(footer); + p->addItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | + QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight); + if (qFuzzyIsNull(footer->z())) + footer->setZ(1); + if (QQuickToolBar *toolBar = qobject_cast(footer)) + toolBar->setPosition(QQuickToolBar::Footer); + else if (QQuickTabBar *tabBar = qobject_cast(footer)) + tabBar->setPosition(QQuickTabBar::Footer); + } + if (isComponentComplete()) + d->relayout(); + emit footerChanged(); +} + +/*! + \qmlproperty list Qt.labs.controls::Page::contentData + \default + + This property holds the list of content data. + + \sa Item::data +*/ +QQmlListProperty QQuickPage::contentData() +{ + Q_D(QQuickPage); + return QQmlListProperty(d->contentItem, nullptr, + QQuickItemPrivate::data_append, + QQuickItemPrivate::data_count, + QQuickItemPrivate::data_at, + QQuickItemPrivate::data_clear); +} + +/*! + \qmlproperty list Qt.labs.controls::Page::contentChildren + + This property holds the list of content children. + + \sa Item::children +*/ +QQmlListProperty QQuickPage::contentChildren() +{ + Q_D(QQuickPage); + return QQmlListProperty(d->contentItem, nullptr, + QQuickItemPrivate::children_append, + QQuickItemPrivate::children_count, + QQuickItemPrivate::children_at, + QQuickItemPrivate::children_clear); +} + +void QQuickPage::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + QQuickControl::contentItemChange(newItem, oldItem); + if (oldItem) + disconnect(oldItem, &QQuickItem::childrenChanged, this, &QQuickPage::contentChildrenChanged); + if (newItem) + connect(newItem, &QQuickItem::childrenChanged, this, &QQuickPage::contentChildrenChanged); + emit contentChildrenChanged(); +} + +void QQuickPage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickPage); + QQuickControl::geometryChanged(newGeometry, oldGeometry); + d->relayout(); +} + +void QQuickPage::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) +{ + Q_D(QQuickPage); + QQuickControl::paddingChange(newPadding, oldPadding); + d->relayout(); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickPage::accessibleRole() const +{ + return QAccessible::PageTab; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickpage_p.h b/src/quicktemplates2/qquickpage_p.h new file mode 100644 index 00000000..950b72e6 --- /dev/null +++ b/src/quicktemplates2/qquickpage_p.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPAGE_P_H +#define QQUICKPAGE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickPagePrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickPage : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(QQuickItem *header READ header WRITE setHeader NOTIFY headerChanged FINAL) + Q_PROPERTY(QQuickItem *footer READ footer WRITE setFooter NOTIFY footerChanged FINAL) + Q_PROPERTY(QQmlListProperty contentData READ contentData FINAL) + Q_PROPERTY(QQmlListProperty contentChildren READ contentChildren NOTIFY contentChildrenChanged FINAL) + Q_CLASSINFO("DefaultProperty", "contentData") + +public: + explicit QQuickPage(QQuickItem *parent = nullptr); + + QQuickItem *header() const; + void setHeader(QQuickItem *header); + + QQuickItem *footer() const; + void setFooter(QQuickItem *footer); + + QQmlListProperty contentData(); + QQmlListProperty contentChildren(); + +Q_SIGNALS: + void headerChanged(); + void footerChanged(); + void contentChildrenChanged(); + +protected: + void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickPage) + Q_DECLARE_PRIVATE(QQuickPage) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPage) + +#endif // QQUICKPAGE_P_H diff --git a/src/quicktemplates2/qquickpageindicator.cpp b/src/quicktemplates2/qquickpageindicator.cpp new file mode 100644 index 00000000..f49909cc --- /dev/null +++ b/src/quicktemplates2/qquickpageindicator.cpp @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpageindicator_p.h" +#include "qquickcontrol_p_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype PageIndicator + \inherits Control + \instantiates QQuickPageIndicator + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-indicators + \brief Indicates the currently active page. + + PageIndicator is used to indicate the currently active page + in a container of multiple pages. PageIndicator consists of + delegate items that present pages. + + \image qtquickcontrols-pageindicator.png + + \snippet qtquickcontrols-pageindicator.qml 1 + + \labs + + \sa SwipeView, {Customizing PageIndicator}, {Indicator Controls} +*/ + +class QQuickPageIndicatorPrivate : public QQuickControlPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickPageIndicator) + +public: + QQuickPageIndicatorPrivate() : count(0), currentIndex(0), + interactive(false), delegate(nullptr), pressedItem(nullptr) + { + } + + QQuickItem *itemAt(const QPoint &pos) const; + void updatePressed(bool pressed, const QPoint &pos = QPoint()); + void setContextProperty(QQuickItem *item, const QString &name, const QVariant &value); + + void itemChildAdded(QQuickItem *, QQuickItem *child); + + int count; + int currentIndex; + bool interactive; + QQmlComponent *delegate; + QQuickItem *pressedItem; +}; + +QQuickItem *QQuickPageIndicatorPrivate::itemAt(const QPoint &pos) const +{ + Q_Q(const QQuickPageIndicator); + if (!contentItem || !q->contains(pos)) + return nullptr; + + QPointF contentPos = q->mapToItem(contentItem, pos); + QQuickItem *item = contentItem->childAt(contentPos.x(), contentPos.y()); + while (item && item->parentItem() != contentItem) + item = item->parentItem(); + if (item && !QQuickItemPrivate::get(item)->isTransparentForPositioner()) + return item; + + // find the nearest + qreal distance = qInf(); + QQuickItem *nearest = nullptr; + const auto childItems = contentItem->childItems(); + for (QQuickItem *child : childItems) { + if (QQuickItemPrivate::get(child)->isTransparentForPositioner()) + continue; + + QPointF center = child->boundingRect().center(); + QPointF pt = contentItem->mapToItem(child, contentPos); + + qreal len = QLineF(center, pt).length(); + if (len < distance) { + distance = len; + nearest = child; + } + } + return nearest; +} + +void QQuickPageIndicatorPrivate::updatePressed(bool pressed, const QPoint &pos) +{ + QQuickItem *prevItem = pressedItem; + pressedItem = pressed ? itemAt(pos) : nullptr; + if (prevItem != pressedItem) { + setContextProperty(prevItem, QStringLiteral("pressed"), false); + setContextProperty(pressedItem, QStringLiteral("pressed"), pressed); + } +} + +void QQuickPageIndicatorPrivate::setContextProperty(QQuickItem *item, const QString &name, const QVariant &value) +{ + QQmlContext *context = qmlContext(item); + if (context && context->isValid()) { + context = context->parentContext(); + if (context && context->isValid()) + context->setContextProperty(name, value); + } +} + +void QQuickPageIndicatorPrivate::itemChildAdded(QQuickItem *, QQuickItem *child) +{ + if (!QQuickItemPrivate::get(child)->isTransparentForPositioner()) + setContextProperty(child, QStringLiteral("pressed"), false); +} + +QQuickPageIndicator::QQuickPageIndicator(QQuickItem *parent) : + QQuickControl(*(new QQuickPageIndicatorPrivate), parent) +{ +} + +/*! + \qmlproperty int Qt.labs.controls::PageIndicator::count + + This property holds the number of pages. +*/ +int QQuickPageIndicator::count() const +{ + Q_D(const QQuickPageIndicator); + return d->count; +} + +void QQuickPageIndicator::setCount(int count) +{ + Q_D(QQuickPageIndicator); + if (d->count == count) + return; + + d->count = count; + emit countChanged(); +} + +/*! + \qmlproperty int Qt.labs.controls::PageIndicator::currentIndex + + This property holds the index of the current page. +*/ +int QQuickPageIndicator::currentIndex() const +{ + Q_D(const QQuickPageIndicator); + return d->currentIndex; +} + +void QQuickPageIndicator::setCurrentIndex(int index) +{ + Q_D(QQuickPageIndicator); + if (d->currentIndex == index) + return; + + d->currentIndex = index; + emit currentIndexChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::PageIndicator::interactive + + This property holds whether the control is interactive. An interactive page indicator + reacts to presses and automatically changes the \l {currentIndex}{current index} + appropriately. + + The default value is \c false. +*/ +bool QQuickPageIndicator::isInteractive() const +{ + Q_D(const QQuickPageIndicator); + return d->interactive; +} + +void QQuickPageIndicator::setInteractive(bool interactive) +{ + Q_D(QQuickPageIndicator); + if (d->interactive == interactive) + return; + + d->interactive = interactive; + setAcceptedMouseButtons(interactive ? Qt::LeftButton : Qt::NoButton); + emit interactiveChanged(); +} + +/*! + \qmlproperty Component Qt.labs.controls::PageIndicator::delegate + + This property holds a delegate that presents a page. + + The following properties are available in the context of each delegate: + \table + \row \li \b index : int \li The index of the item + \row \li \b pressed : bool \li Whether the item is pressed + \endtable +*/ +QQmlComponent *QQuickPageIndicator::delegate() const +{ + Q_D(const QQuickPageIndicator); + return d->delegate; +} + +void QQuickPageIndicator::setDelegate(QQmlComponent *delegate) +{ + Q_D(QQuickPageIndicator); + if (d->delegate == delegate) + return; + + d->delegate = delegate; + emit delegateChanged(); +} + +void QQuickPageIndicator::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_D(QQuickPageIndicator); + QQuickControl::contentItemChange(newItem, oldItem); + if (oldItem) + QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Children); + if (newItem) + QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Children); +} + +void QQuickPageIndicator::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickPageIndicator); + if (d->interactive) { + d->updatePressed(true, event->pos()); + event->accept(); + } +} + +void QQuickPageIndicator::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickPageIndicator); + if (d->interactive) { + d->updatePressed(true, event->pos()); + event->accept(); + } +} + +void QQuickPageIndicator::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickPageIndicator); + if (d->interactive) { + if (d->pressedItem) + setCurrentIndex(d->contentItem->childItems().indexOf(d->pressedItem)); + d->updatePressed(false); + event->accept(); + } +} + +void QQuickPageIndicator::mouseUngrabEvent() +{ + Q_D(QQuickPageIndicator); + if (d->interactive) + d->updatePressed(false); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickPageIndicator::accessibleRole() const +{ + return QAccessible::Indicator; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickpageindicator_p.h b/src/quicktemplates2/qquickpageindicator_p.h new file mode 100644 index 00000000..96c12170 --- /dev/null +++ b/src/quicktemplates2/qquickpageindicator_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPAGEINDICATOR_P_H +#define QQUICKPAGEINDICATOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQmlComponent; +class QQuickPageIndicatorPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickPageIndicator : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged FINAL) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL) + Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged FINAL) + Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL) + +public: + explicit QQuickPageIndicator(QQuickItem *parent = nullptr); + + int count() const; + void setCount(int count); + + int currentIndex() const; + void setCurrentIndex(int index); + + bool isInteractive() const; + void setInteractive(bool interactive); + + QQmlComponent *delegate() const; + void setDelegate(QQmlComponent *delegate); + +Q_SIGNALS: + void countChanged(); + void currentIndexChanged(); + void interactiveChanged(); + void delegateChanged(); + +protected: + void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; + + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseUngrabEvent() override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickPageIndicator) + Q_DECLARE_PRIVATE(QQuickPageIndicator) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPageIndicator) + +#endif // QQUICKPAGEINDICATOR_P_H diff --git a/src/quicktemplates2/qquickpane.cpp b/src/quicktemplates2/qquickpane.cpp new file mode 100644 index 00000000..f5588d86 --- /dev/null +++ b/src/quicktemplates2/qquickpane.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpane_p.h" +#include "qquickpane_p_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Pane + \inherits Control + \instantiates QQuickPane + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-containers + \brief Provides a background matching with the application style and theme. + + Pane provides a background color that matches with the application style + and theme. Pane does not provide a layout of its own, but requires you to + position its contents, for instance by creating a \l RowLayout or a + \l ColumnLayout. + + Items declared as children of a Pane are automatically parented to the + Pane's contentItem. Items created dynamically need to be explicitly + parented to the contentItem. + + If only a single item is used within a Pane, it will resize to fit the + implicit size of its contained item. This makes it particularly suitable + for use together with layouts. + + \image qtquickcontrols-pane.png + + \snippet qtquickcontrols-pane.qml 1 + + \labs + + \sa {Customizing Pane}, {Container Controls} +*/ + +QQuickPanePrivate::QQuickPanePrivate() : contentWidth(0), contentHeight(0) +{ +} + +QQuickPane::QQuickPane(QQuickItem *parent) : + QQuickControl(*(new QQuickPanePrivate), parent) +{ + setFlag(QQuickItem::ItemIsFocusScope); + setAcceptedMouseButtons(Qt::AllButtons); +} + +QQuickPane::QQuickPane(QQuickPanePrivate &dd, QQuickItem *parent) : + QQuickControl(dd, parent) +{ + setFlag(QQuickItem::ItemIsFocusScope); + setAcceptedMouseButtons(Qt::AllButtons); +} + +/*! + \qmlproperty real Qt.labs.controls::Pane::contentWidth + + This property holds the content width. It is used for calculating the + total implicit width of the pane. + + \note If only a single item is used within the pane, the implicit width + of its contained item is used as the content width. +*/ +qreal QQuickPane::contentWidth() const +{ + Q_D(const QQuickPane); + return d->contentWidth; +} + +void QQuickPane::setContentWidth(qreal width) +{ + Q_D(QQuickPane); + if (qFuzzyCompare(d->contentWidth, width)) + return; + + d->contentWidth = width; + emit contentWidthChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::Pane::contentHeight + + This property holds the content height. It is used for calculating the + total implicit height of the pane. + + \note If only a single item is used within the pane, the implicit height + of its contained item is used as the content height. +*/ +qreal QQuickPane::contentHeight() const +{ + Q_D(const QQuickPane); + return d->contentHeight; +} + +void QQuickPane::setContentHeight(qreal height) +{ + Q_D(QQuickPane); + if (qFuzzyCompare(d->contentHeight, height)) + return; + + d->contentHeight = height; + emit contentHeightChanged(); +} + +/*! + \qmlproperty list Qt.labs.controls::Pane::contentData + \default + + This property holds the list of content data. + + \sa Item::data +*/ +QQmlListProperty QQuickPane::contentData() +{ + Q_D(QQuickPane); + return QQmlListProperty(d->contentItem, nullptr, + QQuickItemPrivate::data_append, + QQuickItemPrivate::data_count, + QQuickItemPrivate::data_at, + QQuickItemPrivate::data_clear); +} + +/*! + \qmlproperty list Qt.labs.controls::Pane::contentChildren + + This property holds the list of content children. + + \sa Item::children +*/ +QQmlListProperty QQuickPane::contentChildren() +{ + Q_D(QQuickPane); + return QQmlListProperty(d->contentItem, nullptr, + QQuickItemPrivate::children_append, + QQuickItemPrivate::children_count, + QQuickItemPrivate::children_at, + QQuickItemPrivate::children_clear); +} + +void QQuickPane::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + QQuickControl::contentItemChange(newItem, oldItem); + if (oldItem) + disconnect(oldItem, &QQuickItem::childrenChanged, this, &QQuickPane::contentChildrenChanged); + if (newItem) + connect(newItem, &QQuickItem::childrenChanged, this, &QQuickPane::contentChildrenChanged); + emit contentChildrenChanged(); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickPane::accessibleRole() const +{ + return QAccessible::Pane; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickpane_p.h b/src/quicktemplates2/qquickpane_p.h new file mode 100644 index 00000000..519ea706 --- /dev/null +++ b/src/quicktemplates2/qquickpane_p.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPANE_P_H +#define QQUICKPANE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickPanePrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickPane : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged FINAL) + Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged FINAL) + Q_PROPERTY(QQmlListProperty contentData READ contentData FINAL) + Q_PROPERTY(QQmlListProperty contentChildren READ contentChildren NOTIFY contentChildrenChanged FINAL) + Q_CLASSINFO("DefaultProperty", "contentData") + +public: + explicit QQuickPane(QQuickItem *parent = nullptr); + + qreal contentWidth() const; + void setContentWidth(qreal width); + + qreal contentHeight() const; + void setContentHeight(qreal height); + + QQmlListProperty contentData(); + QQmlListProperty contentChildren(); + +Q_SIGNALS: + void contentWidthChanged(); + void contentHeightChanged(); + void contentChildrenChanged(); + +protected: + QQuickPane(QQuickPanePrivate &dd, QQuickItem *parent); + + void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickPane) + Q_DECLARE_PRIVATE(QQuickPane) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPane) + +#endif // QQUICKPANE_P_H diff --git a/src/quicktemplates2/qquickpane_p_p.h b/src/quicktemplates2/qquickpane_p_p.h new file mode 100644 index 00000000..f99a8928 --- /dev/null +++ b/src/quicktemplates2/qquickpane_p_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPANE_P_P_H +#define QQUICKPANE_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickPane; + +class Q_QUICKTEMPLATES2_EXPORT QQuickPanePrivate : public QQuickControlPrivate +{ + Q_DECLARE_PUBLIC(QQuickPane) + +public: + QQuickPanePrivate(); + + qreal contentWidth; + qreal contentHeight; +}; + +QT_END_NAMESPACE + +#endif // QQUICKPANE_P_P_H diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp new file mode 100644 index 00000000..be3c720c --- /dev/null +++ b/src/quicktemplates2/qquickpopup.cpp @@ -0,0 +1,1851 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpopup_p.h" +#include "qquickpopup_p_p.h" +#include "qquickapplicationwindow_p.h" +#include "qquickoverlay_p.h" +#include "qquickcontrol_p_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Popup + \inherits QtObject + \instantiates QQuickPopup + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-popups + \brief The base type of popup-like user interface controls. + + Popup is the base type of popup-like user interface controls. It can be + used with Window or ApplicationWindow. + + \qml + import QtQuick.Window 2.2 + import Qt.labs.controls 1.0 + + Window { + id: window + width: 400 + height: 400 + visible: true + + Button { + text: "Open" + onClicked: popup.open() + } + + Popup { + id: popup + x: 100 + y: 100 + width: 200 + height: 300 + modal: true + focus: true + closePolicy: Popup.OnEscape | Popup.OnPressOutsideParent + } + } + \endqml + + In order to ensure that a popup is displayed above other items in the + scene, it is recommended to use ApplicationWindow. ApplicationWindow also + provides background dimming effects. + + \labs +*/ + +static const QQuickItemPrivate::ChangeTypes AncestorChangeTypes = QQuickItemPrivate::Geometry + | QQuickItemPrivate::Parent + | QQuickItemPrivate::Children; + +static const QQuickItemPrivate::ChangeTypes ItemChangeTypes = QQuickItemPrivate::Geometry + | QQuickItemPrivate::Parent + | QQuickItemPrivate::Destroyed; + +QQuickPopupPrivate::QQuickPopupPrivate() + : QObjectPrivate() + , focus(false) + , modal(false) + , visible(false) + , complete(false) + , hasTopMargin(false) + , hasLeftMargin(false) + , hasRightMargin(false) + , hasBottomMargin(false) + , x(0) + , y(0) + , margins(0) + , topMargin(0) + , leftMargin(0) + , rightMargin(0) + , bottomMargin(0) + , contentWidth(0) + , contentHeight(0) + , closePolicy(QQuickPopup::OnEscape | QQuickPopup::OnPressOutside) + , parentItem(nullptr) + , enter(nullptr) + , exit(nullptr) + , popupItem(nullptr) + , positioner(this) + , transitionManager(this) +{ +} + +void QQuickPopupPrivate::init() +{ + Q_Q(QQuickPopup); + popupItem = new QQuickPopupItem(q); + q->setParentItem(qobject_cast(parent)); + QObject::connect(popupItem, &QQuickControl::paddingChanged, q, &QQuickPopup::paddingChanged); +} + +bool QQuickPopupPrivate::tryClose(QQuickItem *item, QMouseEvent *event) +{ + Q_Q(QQuickPopup); + const bool isPress = event->type() == QEvent::MouseButtonPress; + const bool onOutside = closePolicy.testFlag(isPress ? QQuickPopup::OnPressOutside : QQuickPopup::OnReleaseOutside); + const bool onOutsideParent = closePolicy.testFlag(isPress ? QQuickPopup::OnPressOutsideParent : QQuickPopup::OnReleaseOutsideParent); + if (onOutside || onOutsideParent) { + if (!popupItem->contains(item->mapToItem(popupItem, event->pos()))) { + if (!onOutsideParent || !parentItem || !parentItem->contains(item->mapToItem(parentItem, event->pos()))) { + q->close(); + return true; + } + } + } + return false; +} + +void QQuickPopupPrivate::prepareEnterTransition(bool notify) +{ + Q_Q(QQuickPopup); + QQuickWindow *quickWindow = q->window(); + if (!quickWindow) { + qmlInfo(q) << "cannot find any window to open popup in."; + return; + } + + QQuickApplicationWindow *applicationWindow = qobject_cast(quickWindow); + if (!applicationWindow) { + quickWindow->installEventFilter(q); + popupItem->setZ(10001); // DefaultWindowDecoration+1 + popupItem->setParentItem(quickWindow->contentItem()); + } else { + popupItem->setParentItem(applicationWindow->overlay()); + } + + if (notify) + emit q->aboutToShow(); + visible = notify; + popupItem->setVisible(true); + positioner.setParentItem(parentItem); + emit q->visibleChanged(); +} + +void QQuickPopupPrivate::prepareExitTransition() +{ + Q_Q(QQuickPopup); + QQuickWindow *quickWindow = q->window(); + if (quickWindow && !qobject_cast(quickWindow)) + quickWindow->removeEventFilter(q); + if (focus) + popupItem->setFocus(false); + emit q->aboutToHide(); +} + +void QQuickPopupPrivate::finalizeEnterTransition() +{ + if (focus) + popupItem->setFocus(true); +} + +void QQuickPopupPrivate::finalizeExitTransition(bool hide) +{ + Q_Q(QQuickPopup); + positioner.setParentItem(nullptr); + if (hide) { + popupItem->setParentItem(nullptr); + popupItem->setVisible(false); + } + + visible = false; + emit q->visibleChanged(); +} + +QMarginsF QQuickPopupPrivate::getMargins() const +{ + Q_Q(const QQuickPopup); + return QMarginsF(q->leftMargin(), q->topMargin(), q->rightMargin(), q->bottomMargin()); +} + +void QQuickPopupPrivate::setTopMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->topMargin(); + topMargin = value; + hasTopMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->topMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(leftMargin, oldMargin, rightMargin, bottomMargin)); + } +} + +void QQuickPopupPrivate::setLeftMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->leftMargin(); + leftMargin = value; + hasLeftMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->leftMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(oldMargin, topMargin, rightMargin, bottomMargin)); + } +} + +void QQuickPopupPrivate::setRightMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->rightMargin(); + rightMargin = value; + hasRightMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->rightMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(leftMargin, topMargin, oldMargin, bottomMargin)); + } +} + +void QQuickPopupPrivate::setBottomMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->bottomMargin(); + bottomMargin = value; + hasBottomMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->bottomMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(leftMargin, topMargin, rightMargin, oldMargin)); + } +} + +class QQuickPopupItemPrivate : public QQuickControlPrivate +{ + Q_DECLARE_PUBLIC(QQuickPopupItem) + +public: + QQuickPopupItemPrivate(QQuickPopup *popup); + + void implicitWidthChanged() override; + void implicitHeightChanged() override; + + void resolveFont() override; + + QQuickPopup *popup; +}; + +QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup) : popup(popup) +{ + isTabFence = true; +} + +void QQuickPopupItemPrivate::implicitWidthChanged() +{ + QQuickControlPrivate::implicitWidthChanged(); + emit popup->implicitWidthChanged(); +} + +void QQuickPopupItemPrivate::implicitHeightChanged() +{ + QQuickControlPrivate::implicitHeightChanged(); + emit popup->implicitHeightChanged(); +} + +void QQuickPopupItemPrivate::resolveFont() +{ + if (QQuickApplicationWindow *window = qobject_cast(popup->window())) + inheritFont(window->font()); +} + +QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup) : + QQuickControl(*(new QQuickPopupItemPrivate(popup)), nullptr) +{ + setParent(popup); + setVisible(false); + setFlag(ItemIsFocusScope); + setAcceptedMouseButtons(Qt::AllButtons); +} + +bool QQuickPopupItem::childMouseEventFilter(QQuickItem *child, QEvent *event) +{ + Q_D(QQuickPopupItem); + return d->popup->childMouseEventFilter(child, event); +} + +void QQuickPopupItem::focusInEvent(QFocusEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->focusInEvent(event); +} + +void QQuickPopupItem::focusOutEvent(QFocusEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->focusOutEvent(event); +} + +void QQuickPopupItem::keyPressEvent(QKeyEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->keyPressEvent(event); +} + +void QQuickPopupItem::keyReleaseEvent(QKeyEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->keyReleaseEvent(event); +} + +void QQuickPopupItem::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->mousePressEvent(event); +} + +void QQuickPopupItem::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->mouseMoveEvent(event); +} + +void QQuickPopupItem::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->mouseReleaseEvent(event); +} + +void QQuickPopupItem::mouseDoubleClickEvent(QMouseEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->mouseDoubleClickEvent(event); +} + +void QQuickPopupItem::mouseUngrabEvent() +{ + Q_D(QQuickPopupItem); + d->popup->mouseUngrabEvent(); +} + +void QQuickPopupItem::wheelEvent(QWheelEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->wheelEvent(event); +} + +void QQuickPopupItem::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_D(QQuickPopupItem); + QQuickControl::contentItemChange(newItem, oldItem); + d->popup->contentItemChange(newItem, oldItem); +} + +void QQuickPopupItem::fontChange(const QFont &newFont, const QFont &oldFont) +{ + Q_D(QQuickPopupItem); + QQuickControl::fontChange(newFont, oldFont); + d->popup->fontChange(newFont, oldFont); +} + +void QQuickPopupItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickPopupItem); + QQuickControl::geometryChanged(newGeometry, oldGeometry); + d->popup->geometryChanged(newGeometry, oldGeometry); +} + +void QQuickPopupItem::localeChange(const QLocale &newLocale, const QLocale &oldLocale) +{ + Q_D(QQuickPopupItem); + QQuickControl::localeChange(newLocale, oldLocale); + d->popup->localeChange(newLocale, oldLocale); +} + +void QQuickPopupItem::itemChange(ItemChange change, const ItemChangeData &data) +{ + Q_D(QQuickPopupItem); + QQuickControl::itemChange(change, data); + d->popup->itemChange(change, data); +} + +void QQuickPopupItem::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) +{ + Q_D(QQuickPopupItem); + QQuickControl::paddingChange(newPadding, oldPadding); + d->popup->paddingChange(newPadding, oldPadding); +} + +QFont QQuickPopupItem::defaultFont() const +{ + Q_D(const QQuickPopupItem); + return d->popup->defaultFont(); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickPopupItem::accessibleRole() const +{ + Q_D(const QQuickPopupItem); + return d->popup->accessibleRole(); +} +#endif // QT_NO_ACCESSIBILITY + +QQuickPopupPositioner::QQuickPopupPositioner(QQuickPopupPrivate *popup) : + m_parentItem(nullptr), + m_popup(popup) +{ +} + +QQuickPopupPositioner::~QQuickPopupPositioner() +{ + if (m_parentItem) { + QQuickItemPrivate::get(m_parentItem)->removeItemChangeListener(this, ItemChangeTypes); + removeAncestorListeners(m_parentItem->parentItem()); + } +} + +QQuickItem *QQuickPopupPositioner::parentItem() const +{ + return m_parentItem; +} + +void QQuickPopupPositioner::setParentItem(QQuickItem *parent) +{ + if (m_parentItem == parent) + return; + + if (m_parentItem) { + QQuickItemPrivate::get(m_parentItem)->removeItemChangeListener(this, ItemChangeTypes); + removeAncestorListeners(m_parentItem->parentItem()); + } + + m_parentItem = parent; + + if (!parent) + return; + + QQuickItemPrivate::get(parent)->addItemChangeListener(this, ItemChangeTypes); + addAncestorListeners(parent->parentItem()); + + if (m_popup->popupItem->isVisible()) + m_popup->reposition(); +} + +void QQuickPopupPositioner::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) +{ + if (m_parentItem && m_popup->popupItem->isVisible()) + m_popup->reposition(); +} + +void QQuickPopupPositioner::itemParentChanged(QQuickItem *, QQuickItem *parent) +{ + addAncestorListeners(parent); +} + +void QQuickPopupPositioner::itemChildRemoved(QQuickItem *item, QQuickItem *child) +{ + if (isAncestor(child)) + removeAncestorListeners(item); +} + +void QQuickPopupPositioner::itemDestroyed(QQuickItem *item) +{ + Q_ASSERT(m_parentItem == item); + + m_parentItem = nullptr; + m_popup->parentItem = nullptr; + QQuickItemPrivate::get(item)->removeItemChangeListener(this, ItemChangeTypes); + removeAncestorListeners(item->parentItem()); +} + +void QQuickPopupPrivate::reposition() +{ + Q_Q(QQuickPopup); + const qreal w = popupItem->width(); + const qreal h = popupItem->height(); + const qreal iw = popupItem->implicitWidth(); + const qreal ih = popupItem->implicitHeight(); + + bool adjusted = false; + QRectF rect(x, y, iw > 0 ? iw : w, ih > 0 ? ih : h); + if (parentItem) { + rect = parentItem->mapRectToScene(rect); + + QQuickWindow *window = q->window(); + if (window) { + const QMarginsF margins = getMargins(); + const QRectF bounds = QRectF(0, 0, window->width(), window->height()).marginsRemoved(margins); + + // push inside the margins + if (margins.top() > 0 && rect.top() < bounds.top()) + rect.moveTop(margins.top()); + if (margins.bottom() > 0 && rect.bottom() > bounds.bottom()) + rect.moveBottom(bounds.bottom()); + if (margins.left() > 0 && rect.left() < bounds.left()) + rect.moveLeft(margins.left()); + if (margins.right() > 0 && rect.right() > bounds.right()) + rect.moveRight(bounds.right()); + + if (rect.top() < bounds.top() || rect.bottom() > bounds.bottom()) { + // if the popup doesn't fit inside the window, try flipping it around (below <-> above) + const QRectF flipped = parentItem->mapRectToScene(QRectF(x, parentItem->height() - y - rect.height(), rect.width(), rect.height())); + if (flipped.top() >= bounds.top() && flipped.bottom() < bounds.bottom()) { + adjusted = true; + rect = flipped; + } else if (ih > 0) { + // neither the flipped around geometry fits inside the window, choose + // whichever side (above vs. below) fits larger part of the popup + const QRectF primary = rect.intersected(bounds); + const QRectF secondary = flipped.intersected(bounds); + + if (primary.height() > secondary.height()) { + rect.setY(primary.y()); + rect.setHeight(primary.height()); + } else { + rect.setY(secondary.y()); + rect.setHeight(secondary.height()); + } + adjusted = true; + } + } + } + } + + popupItem->setPosition(rect.topLeft()); + if (adjusted && ih > 0) + popupItem->setHeight(rect.height()); +} + +void QQuickPopupPositioner::removeAncestorListeners(QQuickItem *item) +{ + if (item == m_parentItem) + return; + + QQuickItem *p = item; + while (p) { + QQuickItemPrivate::get(p)->removeItemChangeListener(this, AncestorChangeTypes); + p = p->parentItem(); + } +} + +void QQuickPopupPositioner::addAncestorListeners(QQuickItem *item) +{ + if (item == m_parentItem) + return; + + QQuickItem *p = item; + while (p) { + QQuickItemPrivate::get(p)->addItemChangeListener(this, AncestorChangeTypes); + p = p->parentItem(); + } +} + +// TODO: use QQuickItem::isAncestorOf() in dev/5.7 +bool QQuickPopupPositioner::isAncestor(QQuickItem *item) const +{ + if (!m_parentItem) + return false; + + QQuickItem *parent = m_parentItem; + while (parent) { + if (parent == item) + return true; + parent = parent->parentItem(); + } + return false; +} + +QQuickPopupTransitionManager::QQuickPopupTransitionManager(QQuickPopupPrivate *popup) + : QQuickTransitionManager() + , state(Off) + , popup(popup) +{ +} + +void QQuickPopupTransitionManager::transitionEnter() +{ + if (state == Enter && isRunning()) + return; + + state = Enter; + popup->prepareEnterTransition(); + transition(popup->enterActions, popup->enter, popup->q_func()); +} + +void QQuickPopupTransitionManager::transitionExit() +{ + if (state == Exit && isRunning()) + return; + + state = Exit; + popup->prepareExitTransition(); + transition(popup->exitActions, popup->exit, popup->q_func()); +} + +void QQuickPopupTransitionManager::finished() +{ + if (state == Enter) + popup->finalizeEnterTransition(); + else if (state == Exit) + popup->finalizeExitTransition(); + + state = Off; +} + +QQuickPopup::QQuickPopup(QObject *parent) + : QObject(*(new QQuickPopupPrivate), parent) +{ + Q_D(QQuickPopup); + d->init(); +} + +QQuickPopup::QQuickPopup(QQuickPopupPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ + Q_D(QQuickPopup); + d->init(); +} + +QQuickPopup::~QQuickPopup() +{ + Q_D(QQuickPopup); + d->positioner.setParentItem(nullptr); + delete d->popupItem; +} + +/*! + \qmlmethod void Qt.labs.controls::Popup::open() + + Opens the popup. +*/ +void QQuickPopup::open() +{ + Q_D(QQuickPopup); + if (d->visible) + return; + + if (d->complete) + d->transitionManager.transitionEnter(); +} + +/*! + \qmlmethod void Qt.labs.controls::Popup::close() + + Closes the popup. +*/ +void QQuickPopup::close() +{ + Q_D(QQuickPopup); + if (!d->visible) + return; + + if (d->complete) + d->transitionManager.transitionExit(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::x + + This property holds the x-coordinate of the popup. +*/ +qreal QQuickPopup::x() const +{ + Q_D(const QQuickPopup); + return d->x; +} + +void QQuickPopup::setX(qreal x) +{ + Q_D(QQuickPopup); + if (qFuzzyCompare(d->x, x)) + return; + + d->x = x; + if (d->popupItem->isVisible()) + d->reposition(); + emit xChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::y + + This property holds the y-coordinate of the popup. +*/ +qreal QQuickPopup::y() const +{ + Q_D(const QQuickPopup); + return d->y; +} + +void QQuickPopup::setY(qreal y) +{ + Q_D(QQuickPopup); + if (qFuzzyCompare(d->y, y)) + return; + + d->y = y; + if (d->popupItem->isVisible()) + d->reposition(); + emit yChanged(); +} + +QPointF QQuickPopup::position() const +{ + Q_D(const QQuickPopup); + return QPointF(d->x, d->y); +} + +void QQuickPopup::setPosition(const QPointF &pos) +{ + Q_D(QQuickPopup); + const bool xChange = !qFuzzyCompare(d->x, pos.x()); + const bool yChange = !qFuzzyCompare(d->y, pos.y()); + if (!xChange && !yChange) + return; + + d->x = pos.x(); + d->y = pos.y(); + if (d->popupItem->isVisible()) + d->reposition(); + if (xChange) + emit xChanged(); + if (yChange) + emit yChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::z + + This property holds the z-value of the popup. Z-value determines + the stacking order of popups. The default z-value is \c 0. +*/ +qreal QQuickPopup::z() const +{ + Q_D(const QQuickPopup); + return d->popupItem->z(); +} + +void QQuickPopup::setZ(qreal z) +{ + Q_D(QQuickPopup); + if (qFuzzyCompare(z, d->popupItem->z())) + return; + d->popupItem->setZ(z); + emit zChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::width + + This property holds the width of the popup. +*/ +qreal QQuickPopup::width() const +{ + Q_D(const QQuickPopup); + return d->popupItem->width(); +} + +void QQuickPopup::setWidth(qreal width) +{ + Q_D(QQuickPopup); + d->popupItem->setWidth(width); +} + +void QQuickPopup::resetWidth() +{ + Q_D(QQuickPopup); + d->popupItem->resetWidth(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::height + + This property holds the height of the popup. +*/ +qreal QQuickPopup::height() const +{ + Q_D(const QQuickPopup); + return d->popupItem->height(); +} + +void QQuickPopup::setHeight(qreal height) +{ + Q_D(QQuickPopup); + d->popupItem->setHeight(height); +} + +void QQuickPopup::resetHeight() +{ + Q_D(QQuickPopup); + d->popupItem->resetHeight(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::implicitWidth + + This property holds the implicit width of the popup. +*/ +qreal QQuickPopup::implicitWidth() const +{ + Q_D(const QQuickPopup); + return d->popupItem->implicitWidth(); +} + +void QQuickPopup::setImplicitWidth(qreal width) +{ + Q_D(QQuickPopup); + d->popupItem->setImplicitWidth(width); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::implicitHeight + + This property holds the implicit height of the popup. +*/ +qreal QQuickPopup::implicitHeight() const +{ + Q_D(const QQuickPopup); + return d->popupItem->implicitHeight(); +} + +void QQuickPopup::setImplicitHeight(qreal height) +{ + Q_D(QQuickPopup); + d->popupItem->setImplicitHeight(height); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::contentWidth + + This property holds the content width. It is used for calculating the + total implicit width of the Popup. + + \note If only a single item is used within the Popup, the implicit width + of its contained item is used as the content width. +*/ +qreal QQuickPopup::contentWidth() const +{ + Q_D(const QQuickPopup); + return d->contentWidth; +} + +void QQuickPopup::setContentWidth(qreal width) +{ + Q_D(QQuickPopup); + if (qFuzzyCompare(d->contentWidth, width)) + return; + + d->contentWidth = width; + emit contentWidthChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::contentHeight + + This property holds the content height. It is used for calculating the + total implicit height of the Popup. + + \note If only a single item is used within the Popup, the implicit height + of its contained item is used as the content height. +*/ +qreal QQuickPopup::contentHeight() const +{ + Q_D(const QQuickPopup); + return d->contentHeight; +} + +void QQuickPopup::setContentHeight(qreal height) +{ + Q_D(QQuickPopup); + if (qFuzzyCompare(d->contentHeight, height)) + return; + + d->contentHeight = height; + emit contentHeightChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::availableWidth + \readonly + + This property holds the width available after deducting horizontal padding. + + \sa padding, leftPadding, rightPadding +*/ +qreal QQuickPopup::availableWidth() const +{ + Q_D(const QQuickPopup); + return d->popupItem->availableWidth(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::availableHeight + \readonly + + This property holds the height available after deducting vertical padding. + + \sa padding, topPadding, bottomPadding +*/ +qreal QQuickPopup::availableHeight() const +{ + Q_D(const QQuickPopup); + return d->popupItem->availableHeight(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::margins + + This property holds the default margins around the popup. + + \sa topMargin, leftMargin, rightMargin, bottomMargin +*/ +qreal QQuickPopup::margins() const +{ + Q_D(const QQuickPopup); + return d->margins; +} + +void QQuickPopup::setMargins(qreal margins) +{ + Q_D(QQuickPopup); + if (qFuzzyCompare(d->margins, margins)) + return; + QMarginsF oldMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin()); + d->margins = margins; + emit marginsChanged(); + QMarginsF newMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin()); + if (!qFuzzyCompare(newMargins.top(), oldMargins.top())) + emit topMarginChanged(); + if (!qFuzzyCompare(newMargins.left(), oldMargins.left())) + emit leftMarginChanged(); + if (!qFuzzyCompare(newMargins.right(), oldMargins.right())) + emit rightMarginChanged(); + if (!qFuzzyCompare(newMargins.bottom(), oldMargins.bottom())) + emit bottomMarginChanged(); + marginsChange(newMargins, oldMargins); +} + +void QQuickPopup::resetMargins() +{ + setMargins(0); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::topMargin + + This property holds the top margin around the popup. + + \sa margins, bottomMargin +*/ +qreal QQuickPopup::topMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasTopMargin) + return d->topMargin; + return d->margins; +} + +void QQuickPopup::setTopMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setTopMargin(margin); +} + +void QQuickPopup::resetTopMargin() +{ + Q_D(QQuickPopup); + d->setTopMargin(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::leftMargin + + This property holds the left margin around the popup. + + \sa margins, rightMargin +*/ +qreal QQuickPopup::leftMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasLeftMargin) + return d->leftMargin; + return d->margins; +} + +void QQuickPopup::setLeftMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setLeftMargin(margin); +} + +void QQuickPopup::resetLeftMargin() +{ + Q_D(QQuickPopup); + d->setLeftMargin(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::rightMargin + + This property holds the right margin around the popup. + + \sa margins, leftMargin +*/ +qreal QQuickPopup::rightMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasRightMargin) + return d->rightMargin; + return d->margins; +} + +void QQuickPopup::setRightMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setRightMargin(margin); +} + +void QQuickPopup::resetRightMargin() +{ + Q_D(QQuickPopup); + d->setRightMargin(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::bottomMargin + + This property holds the bottom margin around the popup. + + \sa margins, topMargin +*/ +qreal QQuickPopup::bottomMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasBottomMargin) + return d->bottomMargin; + return d->margins; +} + +void QQuickPopup::setBottomMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setBottomMargin(margin); +} + +void QQuickPopup::resetBottomMargin() +{ + Q_D(QQuickPopup); + d->setBottomMargin(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::padding + + This property holds the default padding. + + \sa availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding +*/ +qreal QQuickPopup::padding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->padding(); +} + +void QQuickPopup::setPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setPadding(padding); +} + +void QQuickPopup::resetPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetPadding(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::topPadding + + This property holds the top padding. + + \sa padding, bottomPadding, availableHeight +*/ +qreal QQuickPopup::topPadding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->topPadding(); +} + +void QQuickPopup::setTopPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setTopPadding(padding); +} + +void QQuickPopup::resetTopPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetTopPadding(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::leftPadding + + This property holds the left padding. + + \sa padding, rightPadding, availableWidth +*/ +qreal QQuickPopup::leftPadding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->leftPadding(); +} + +void QQuickPopup::setLeftPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setLeftPadding(padding); +} + +void QQuickPopup::resetLeftPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetLeftPadding(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::rightPadding + + This property holds the right padding. + + \sa padding, leftPadding, availableWidth +*/ +qreal QQuickPopup::rightPadding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->rightPadding(); +} + +void QQuickPopup::setRightPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setRightPadding(padding); +} + +void QQuickPopup::resetRightPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetRightPadding(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::bottomPadding + + This property holds the bottom padding. + + \sa padding, topPadding, availableHeight +*/ +qreal QQuickPopup::bottomPadding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->bottomPadding(); +} + +void QQuickPopup::setBottomPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setBottomPadding(padding); +} + +void QQuickPopup::resetBottomPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetBottomPadding(); +} + +/*! + \qmlproperty Locale Qt.labs.controls::Popup::locale + + This property holds the locale of the popup. + + \sa {LayoutMirroring}{LayoutMirroring} +*/ +QLocale QQuickPopup::locale() const +{ + Q_D(const QQuickPopup); + return d->popupItem->locale(); +} + +void QQuickPopup::setLocale(const QLocale &locale) +{ + Q_D(QQuickPopup); + d->popupItem->setLocale(locale); +} + +void QQuickPopup::resetLocale() +{ + Q_D(QQuickPopup); + d->popupItem->resetLocale(); +} + +/*! + \qmlproperty font Qt.labs.controls::Popup::font + + This property holds the font currently set for the popup. +*/ +QFont QQuickPopup::font() const +{ + Q_D(const QQuickPopup); + return d->popupItem->font(); +} + +void QQuickPopup::setFont(const QFont &font) +{ + Q_D(QQuickPopup); + d->popupItem->setFont(font); +} + +void QQuickPopup::resetFont() +{ + Q_D(QQuickPopup); + d->popupItem->resetFont(); +} + +QQuickWindow *QQuickPopup::window() const +{ + Q_D(const QQuickPopup); + if (!d->parentItem) + return nullptr; + + return d->parentItem->window(); +} + +QQuickItem *QQuickPopup::popupItem() const +{ + Q_D(const QQuickPopup); + return d->popupItem; +} + +/*! + \qmlproperty Item Qt.labs.popups::Popup::parent + + This property holds the parent item. +*/ +QQuickItem *QQuickPopup::parentItem() const +{ + Q_D(const QQuickPopup); + return d->parentItem; +} + +void QQuickPopup::setParentItem(QQuickItem *parent) +{ + Q_D(QQuickPopup); + if (d->parentItem == parent) + return; + + QQuickWindow *oldWindow = window(); + + d->parentItem = parent; + if (d->positioner.parentItem()) + d->positioner.setParentItem(parent); + if (parent) { + QQuickControlPrivate *p = QQuickControlPrivate::get(d->popupItem); + p->resolveFont(); + if (QQuickApplicationWindow *window = qobject_cast(parent->window())) + p->updateLocale(window->locale(), false); // explicit=false + } + emit parentChanged(); + + QQuickWindow *newWindow = window(); + if (oldWindow != newWindow) + emit windowChanged(newWindow); +} + +/*! + \qmlproperty Item Qt.labs.popups::Popup::background + + This property holds the background item. + + \note If the background item has no explicit size specified, it automatically + follows the popup's size. In most cases, there is no need to specify + width or height for a background item. +*/ +QQuickItem *QQuickPopup::background() const +{ + Q_D(const QQuickPopup); + return d->popupItem->background(); +} + +void QQuickPopup::setBackground(QQuickItem *background) +{ + Q_D(QQuickPopup); + if (d->popupItem->background() == background) + return; + + d->popupItem->setBackground(background); + emit backgroundChanged(); +} + +/*! + \qmlproperty Item Qt.labs.controls::Popup::contentItem + + This property holds the content item of the popup. + + The content item is the visual implementation of the popup. When the + popup is made visible, the content item is automatically reparented to + the \l {ApplicationWindow::overlay}{overlay item} of its application + window. +*/ +QQuickItem *QQuickPopup::contentItem() const +{ + Q_D(const QQuickPopup); + return d->popupItem->contentItem(); +} + +void QQuickPopup::setContentItem(QQuickItem *item) +{ + Q_D(QQuickPopup); + d->popupItem->setContentItem(item); +} + +/*! + \qmlproperty list Qt.labs.controls::Popup::contentData + \default + + This property holds the list of content data. + + \sa Item::data +*/ +QQmlListProperty QQuickPopup::contentData() +{ + Q_D(QQuickPopup); + return QQmlListProperty(d->popupItem->contentItem(), nullptr, + QQuickItemPrivate::data_append, + QQuickItemPrivate::data_count, + QQuickItemPrivate::data_at, + QQuickItemPrivate::data_clear); +} + +/*! + \qmlproperty list Qt.labs.controls::Popup::contentChildren + + This property holds the list of content children. + + \sa Item::children +*/ +QQmlListProperty QQuickPopup::contentChildren() +{ + Q_D(QQuickPopup); + return QQmlListProperty(d->popupItem->contentItem(), nullptr, + QQuickItemPrivate::children_append, + QQuickItemPrivate::children_count, + QQuickItemPrivate::children_at, + QQuickItemPrivate::children_clear); +} + +/*! + \qmlproperty bool Qt.labs.controls::Popup::clip + + This property holds whether clipping is enabled. The default value is \c false. +*/ +bool QQuickPopup::clip() const +{ + Q_D(const QQuickPopup); + return d->popupItem->clip(); +} + +void QQuickPopup::setClip(bool clip) +{ + Q_D(QQuickPopup); + if (clip == d->popupItem->clip()) + return; + d->popupItem->setClip(clip); + emit clipChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::Popup::focus + + This property holds whether the popup has focus. The default value is \c false. +*/ +bool QQuickPopup::hasFocus() const +{ + Q_D(const QQuickPopup); + return d->focus; +} + +void QQuickPopup::setFocus(bool focus) +{ + Q_D(QQuickPopup); + if (d->focus == focus) + return; + d->focus = focus; + emit focusChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::Popup::activeFocus + \readonly + + This property holds whether the popup has active focus. +*/ +bool QQuickPopup::hasActiveFocus() const +{ + Q_D(const QQuickPopup); + return d->popupItem->hasActiveFocus(); +} + +/*! + \qmlproperty bool Qt.labs.controls::Popup::modal + + This property holds whether the popup is modal. The default value is \c false. +*/ +bool QQuickPopup::isModal() const +{ + Q_D(const QQuickPopup); + return d->modal; +} + +void QQuickPopup::setModal(bool modal) +{ + Q_D(QQuickPopup); + if (d->modal == modal) + return; + d->modal = modal; + emit modalChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::Popup::visible + + This property holds whether the popup is visible. The default value is \c false. +*/ +bool QQuickPopup::isVisible() const +{ + Q_D(const QQuickPopup); + return d->visible && d->popupItem->isVisible(); +} + +void QQuickPopup::setVisible(bool visible) +{ + Q_D(QQuickPopup); + if (d->visible == visible) + return; + + d->visible = visible; + if (d->complete) { + if (visible) + d->transitionManager.transitionEnter(); + else + d->transitionManager.transitionExit(); + } +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::opacity + + This property holds the opacity of the popup. The default value is \c 1.0. +*/ +qreal QQuickPopup::opacity() const +{ + Q_D(const QQuickPopup); + return d->popupItem->opacity(); +} + +void QQuickPopup::setOpacity(qreal opacity) +{ + Q_D(QQuickPopup); + d->popupItem->setOpacity(opacity); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::scale + + This property holds the scale factor of the popup. The default value is \c 1.0. +*/ +qreal QQuickPopup::scale() const +{ + Q_D(const QQuickPopup); + return d->popupItem->scale(); +} + +void QQuickPopup::setScale(qreal scale) +{ + Q_D(QQuickPopup); + if (qFuzzyCompare(scale, d->popupItem->scale())) + return; + d->popupItem->setScale(scale); + emit scaleChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::Popup::closePolicy + + This property determines the circumstances under which the popup closes. + The flags can be combined to allow several ways of closing the popup. + + The available values are: + \value Popup.NoAutoClose The popup will only close when manually instructed to do so. + \value Popup.OnPressOutside The popup will close when the mouse is pressed outside of it. + \value Popup.OnPressOutsideParent The popup will close when the mouse is pressed outside of its parent. + \value Popup.OnReleaseOutside The popup will close when the mouse is released outside of it. + \value Popup.OnReleaseOutsideParent The popup will close when the mouse is released outside of its parent. + \value Popup.OnEscape The popup will close when the escape key is pressed while the popup + has active focus. + + The default value is \c {Popup.OnEscape | Popup.OnPressOutside}. +*/ +QQuickPopup::ClosePolicy QQuickPopup::closePolicy() const +{ + Q_D(const QQuickPopup); + return d->closePolicy; +} + +void QQuickPopup::setClosePolicy(ClosePolicy policy) +{ + Q_D(QQuickPopup); + if (d->closePolicy == policy) + return; + d->closePolicy = policy; + emit closePolicyChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::Popup::transformOrigin + + This property holds the origin point for transformations in enter and exit transitions. + + Nine transform origins are available, as shown in the image below. + The default transform origin is \c Popup.Center. + + \image qtquickcontrols-popup-transformorigin.png + + \sa enter, exit, Item::transformOrigin +*/ +QQuickPopup::TransformOrigin QQuickPopup::transformOrigin() const +{ + Q_D(const QQuickPopup); + return static_cast(d->popupItem->transformOrigin()); +} + +void QQuickPopup::setTransformOrigin(TransformOrigin origin) +{ + Q_D(QQuickPopup); + d->popupItem->setTransformOrigin(static_cast(origin)); +} + +/*! + \qmlproperty Transition Qt.labs.controls::Popup::enter + + This property holds the transition that is applied to the content item + when the popup is opened and enters the screen. +*/ +QQuickTransition *QQuickPopup::enter() const +{ + Q_D(const QQuickPopup); + return d->enter; +} + +void QQuickPopup::setEnter(QQuickTransition *transition) +{ + Q_D(QQuickPopup); + if (d->enter == transition) + return; + d->enter = transition; + emit enterChanged(); +} + +/*! + \qmlproperty Transition Qt.labs.controls::Popup::exit + + This property holds the transition that is applied to the content item + when the popup is closed and exits the screen. +*/ +QQuickTransition *QQuickPopup::exit() const +{ + Q_D(const QQuickPopup); + return d->exit; +} + +void QQuickPopup::setExit(QQuickTransition *transition) +{ + Q_D(QQuickPopup); + if (d->exit == transition) + return; + d->exit = transition; + emit exitChanged(); +} + +bool QQuickPopup::filtersChildMouseEvents() const +{ + Q_D(const QQuickPopup); + return d->popupItem->filtersChildMouseEvents(); +} + +void QQuickPopup::setFiltersChildMouseEvents(bool filter) +{ + Q_D(QQuickPopup); + d->popupItem->setFiltersChildMouseEvents(filter); +} + +void QQuickPopup::classBegin() +{ +} + +void QQuickPopup::componentComplete() +{ + Q_D(QQuickPopup); + d->complete = true; + if (!parentItem()) + setParentItem(qobject_cast(parent())); + if (d->visible) + d->transitionManager.transitionEnter(); +} + +bool QQuickPopup::isComponentComplete() const +{ + Q_D(const QQuickPopup); + return d->complete; +} + +bool QQuickPopup::eventFilter(QObject *object, QEvent *event) +{ + if (QQuickWindow *window = qobject_cast(object)) + return overlayEvent(window->contentItem(), event); + return false; +} + +bool QQuickPopup::childMouseEventFilter(QQuickItem *child, QEvent *event) +{ + Q_UNUSED(child); + Q_UNUSED(event); + return false; +} + +void QQuickPopup::focusInEvent(QFocusEvent *event) +{ + event->accept(); +} + +void QQuickPopup::focusOutEvent(QFocusEvent *event) +{ + event->accept(); +} + +void QQuickPopup::keyPressEvent(QKeyEvent *event) +{ + Q_D(QQuickPopup); + event->accept(); + + if (hasActiveFocus() && (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab)) + QQuickItemPrivate::focusNextPrev(d->popupItem, event->key() == Qt::Key_Tab); + + if (event->key() != Qt::Key_Escape) + return; + + if (d->closePolicy.testFlag(OnEscape)) + close(); +} + +void QQuickPopup::keyReleaseEvent(QKeyEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mousePressEvent(QMouseEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mouseMoveEvent(QMouseEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mouseReleaseEvent(QMouseEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mouseDoubleClickEvent(QMouseEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mouseUngrabEvent() +{ +} + +bool QQuickPopup::overlayEvent(QQuickItem *item, QEvent *event) +{ + Q_D(QQuickPopup); + switch (event->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::MouseMove: + case QEvent::Wheel: + if (d->modal) + event->accept(); + return d->modal; + + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + if (d->modal) + event->accept(); + d->tryClose(item, static_cast(event)); + return d->modal; + + default: + return false; + } +} + +void QQuickPopup::wheelEvent(QWheelEvent *event) +{ + event->accept(); +} + +void QQuickPopup::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_UNUSED(newItem); + Q_UNUSED(oldItem); + emit contentItemChanged(); +} + +void QQuickPopup::fontChange(const QFont &newFont, const QFont &oldFont) +{ + Q_UNUSED(newFont); + Q_UNUSED(oldFont); + emit fontChanged(); +} + +void QQuickPopup::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickPopup); + d->reposition(); + if (!qFuzzyCompare(newGeometry.width(), oldGeometry.width())) { + emit widthChanged(); + emit availableWidthChanged(); + } + if (!qFuzzyCompare(newGeometry.height(), oldGeometry.height())) { + emit heightChanged(); + emit availableHeightChanged(); + } +} + +void QQuickPopup::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) +{ + Q_UNUSED(data); + + switch (change) { + case QQuickItem::ItemActiveFocusHasChanged: + emit activeFocusChanged(); + break; + case QQuickItem::ItemOpacityHasChanged: + emit opacityChanged(); + break; + default: + break; + } +} + +void QQuickPopup::localeChange(const QLocale &newLocale, const QLocale &oldLocale) +{ + Q_UNUSED(newLocale); + Q_UNUSED(oldLocale); + emit localeChanged(); +} + +void QQuickPopup::marginsChange(const QMarginsF &newMargins, const QMarginsF &oldMargins) +{ + Q_D(QQuickPopup); + Q_UNUSED(newMargins); + Q_UNUSED(oldMargins); + d->reposition(); +} + +void QQuickPopup::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) +{ + const bool tp = !qFuzzyCompare(newPadding.top(), oldPadding.top()); + const bool lp = !qFuzzyCompare(newPadding.left(), oldPadding.left()); + const bool rp = !qFuzzyCompare(newPadding.right(), oldPadding.right()); + const bool bp = !qFuzzyCompare(newPadding.bottom(), oldPadding.bottom()); + + if (tp) + emit topPaddingChanged(); + if (lp) + emit leftPaddingChanged(); + if (rp) + emit rightPaddingChanged(); + if (bp) + emit bottomPaddingChanged(); + + if (lp || rp) + emit availableWidthChanged(); + if (tp || bp) + emit availableHeightChanged(); +} + +QFont QQuickPopup::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::SystemFont); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickPopup::accessibleRole() const +{ + return QAccessible::LayeredPane; +} +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +#include "moc_qquickpopup_p.cpp" diff --git a/src/quicktemplates2/qquickpopup_p.h b/src/quicktemplates2/qquickpopup_p.h new file mode 100644 index 00000000..a0ba5359 --- /dev/null +++ b/src/quicktemplates2/qquickpopup_p.h @@ -0,0 +1,368 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPOPUP_P_H +#define QQUICKPOPUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef QT_NO_ACCESSIBILITY +#include +#endif + +QT_BEGIN_NAMESPACE + +class QQuickWindow; +class QQuickPopupPrivate; +class QQuickTransition; + +class Q_QUICKTEMPLATES2_EXPORT QQuickPopup : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged FINAL) + Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged FINAL) + Q_PROPERTY(qreal z READ z WRITE setZ NOTIFY zChanged FINAL) + Q_PROPERTY(qreal width READ width WRITE setWidth RESET resetWidth NOTIFY widthChanged FINAL) + Q_PROPERTY(qreal height READ height WRITE setHeight RESET resetHeight NOTIFY heightChanged FINAL) + Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged FINAL) + Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged FINAL) + Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged FINAL) + Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged FINAL) + Q_PROPERTY(qreal availableWidth READ availableWidth NOTIFY availableWidthChanged FINAL) + Q_PROPERTY(qreal availableHeight READ availableHeight NOTIFY availableHeightChanged FINAL) + Q_PROPERTY(qreal margins READ margins WRITE setMargins RESET resetMargins NOTIFY marginsChanged FINAL) + Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin RESET resetTopMargin NOTIFY topMarginChanged FINAL) + Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin RESET resetLeftMargin NOTIFY leftMarginChanged FINAL) + Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin RESET resetRightMargin NOTIFY rightMarginChanged FINAL) + Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin RESET resetBottomMargin NOTIFY bottomMarginChanged FINAL) + Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged FINAL) + Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged FINAL) + Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged FINAL) + Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged FINAL) + Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged FINAL) + Q_PROPERTY(QLocale locale READ locale WRITE setLocale RESET resetLocale NOTIFY localeChanged FINAL) + Q_PROPERTY(QFont font READ font WRITE setFont RESET resetFont NOTIFY fontChanged FINAL) + Q_PROPERTY(QQuickItem *parent READ parentItem WRITE setParentItem NOTIFY parentChanged FINAL) + Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL) + Q_PROPERTY(QQuickItem *contentItem READ contentItem WRITE setContentItem NOTIFY contentItemChanged FINAL) + Q_PROPERTY(QQmlListProperty contentData READ contentData FINAL) + Q_PROPERTY(QQmlListProperty contentChildren READ contentChildren NOTIFY contentChildrenChanged FINAL) + Q_PROPERTY(bool clip READ clip WRITE setClip NOTIFY clipChanged FINAL) + Q_PROPERTY(bool focus READ hasFocus WRITE setFocus NOTIFY focusChanged FINAL) + Q_PROPERTY(bool activeFocus READ hasActiveFocus NOTIFY activeFocusChanged FINAL) + Q_PROPERTY(bool modal READ isModal WRITE setModal NOTIFY modalChanged FINAL) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL) + Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged FINAL) + Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged FINAL) + Q_PROPERTY(ClosePolicy closePolicy READ closePolicy WRITE setClosePolicy NOTIFY closePolicyChanged FINAL) + Q_PROPERTY(TransformOrigin transformOrigin READ transformOrigin WRITE setTransformOrigin) + Q_PROPERTY(QQuickTransition *enter READ enter WRITE setEnter NOTIFY enterChanged FINAL) + Q_PROPERTY(QQuickTransition *exit READ exit WRITE setExit NOTIFY exitChanged FINAL) + Q_CLASSINFO("DefaultProperty", "contentData") + +public: + explicit QQuickPopup(QObject *parent = nullptr); + ~QQuickPopup(); + + qreal x() const; + void setX(qreal x); + + qreal y() const; + void setY(qreal y); + + QPointF position() const; + void setPosition(const QPointF &pos); + + qreal z() const; + void setZ(qreal z); + + qreal width() const; + void setWidth(qreal width); + void resetWidth(); + + qreal height() const; + void setHeight(qreal height); + void resetHeight(); + + qreal implicitWidth() const; + void setImplicitWidth(qreal width); + + qreal implicitHeight() const; + void setImplicitHeight(qreal height); + + qreal contentWidth() const; + void setContentWidth(qreal width); + + qreal contentHeight() const; + void setContentHeight(qreal height); + + qreal availableWidth() const; + qreal availableHeight() const; + + qreal margins() const; + void setMargins(qreal margins); + void resetMargins(); + + qreal topMargin() const; + void setTopMargin(qreal margin); + void resetTopMargin(); + + qreal leftMargin() const; + void setLeftMargin(qreal margin); + void resetLeftMargin(); + + qreal rightMargin() const; + void setRightMargin(qreal margin); + void resetRightMargin(); + + qreal bottomMargin() const; + void setBottomMargin(qreal margin); + void resetBottomMargin(); + + qreal padding() const; + void setPadding(qreal padding); + void resetPadding(); + + qreal topPadding() const; + void setTopPadding(qreal padding); + void resetTopPadding(); + + qreal leftPadding() const; + void setLeftPadding(qreal padding); + void resetLeftPadding(); + + qreal rightPadding() const; + void setRightPadding(qreal padding); + void resetRightPadding(); + + qreal bottomPadding() const; + void setBottomPadding(qreal padding); + void resetBottomPadding(); + + QLocale locale() const; + void setLocale(const QLocale &locale); + void resetLocale(); + + QFont font() const; + void setFont(const QFont &font); + void resetFont(); + + QQuickWindow *window() const; + QQuickItem *popupItem() const; + + QQuickItem *parentItem() const; + void setParentItem(QQuickItem *parent); + + QQuickItem *background() const; + void setBackground(QQuickItem *background); + + QQuickItem *contentItem() const; + void setContentItem(QQuickItem *item); + + QQmlListProperty contentData(); + QQmlListProperty contentChildren(); + + bool clip() const; + void setClip(bool clip); + + bool hasFocus() const; + void setFocus(bool focus); + + bool hasActiveFocus() const; + + bool isModal() const; + void setModal(bool modal); + + bool isVisible() const; + void setVisible(bool visible); + + qreal opacity() const; + void setOpacity(qreal opacity); + + qreal scale() const; + void setScale(qreal scale); + + enum ClosePolicyFlag { + NoAutoClose = 0x00, + OnPressOutside = 0x01, + OnPressOutsideParent = 0x02, + OnReleaseOutside = 0x04, + OnReleaseOutsideParent = 0x08, + OnEscape = 0x10 + }; + Q_DECLARE_FLAGS(ClosePolicy, ClosePolicyFlag) + Q_FLAG(ClosePolicy) + + ClosePolicy closePolicy() const; + void setClosePolicy(ClosePolicy policy); + + // keep in sync with Item.TransformOrigin + enum TransformOrigin { + TopLeft, Top, TopRight, + Left, Center, Right, + BottomLeft, Bottom, BottomRight + }; + Q_ENUM(TransformOrigin) + + TransformOrigin transformOrigin() const; + void setTransformOrigin(TransformOrigin); + + QQuickTransition *enter() const; + void setEnter(QQuickTransition *transition); + + QQuickTransition *exit() const; + void setExit(QQuickTransition *transition); + + bool filtersChildMouseEvents() const; + void setFiltersChildMouseEvents(bool filter); + +public Q_SLOTS: + void open(); + void close(); + +Q_SIGNALS: + void xChanged(); + void yChanged(); + void zChanged(); + void widthChanged(); + void heightChanged(); + void implicitWidthChanged(); + void implicitHeightChanged(); + void contentWidthChanged(); + void contentHeightChanged(); + void availableWidthChanged(); + void availableHeightChanged(); + void marginsChanged(); + void topMarginChanged(); + void leftMarginChanged(); + void rightMarginChanged(); + void bottomMarginChanged(); + void paddingChanged(); + void topPaddingChanged(); + void leftPaddingChanged(); + void rightPaddingChanged(); + void bottomPaddingChanged(); + void fontChanged(); + void localeChanged(); + void parentChanged(); + void backgroundChanged(); + void contentItemChanged(); + void contentChildrenChanged(); + void clipChanged(); + void focusChanged(); + void activeFocusChanged(); + void modalChanged(); + void visibleChanged(); + void opacityChanged(); + void scaleChanged(); + void closePolicyChanged(); + void enterChanged(); + void exitChanged(); + void windowChanged(QQuickWindow *window); + + void aboutToShow(); + void aboutToHide(); + +protected: + QQuickPopup(QQuickPopupPrivate &dd, QObject *parent); + + void classBegin() override; + void componentComplete() override; + bool isComponentComplete() const; + + bool eventFilter(QObject *object, QEvent *event) override; + virtual bool childMouseEventFilter(QQuickItem *child, QEvent *event); + virtual void focusInEvent(QFocusEvent *event); + virtual void focusOutEvent(QFocusEvent *event); + virtual void keyPressEvent(QKeyEvent *event); + virtual void keyReleaseEvent(QKeyEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void mouseDoubleClickEvent(QMouseEvent *event); + virtual void mouseUngrabEvent(); + virtual bool overlayEvent(QQuickItem *item, QEvent *event); + virtual void wheelEvent(QWheelEvent *event); + + virtual void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem); + virtual void fontChange(const QFont &newFont, const QFont &oldFont); + virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); + virtual void localeChange(const QLocale &newLocale, const QLocale &oldLocale); + virtual void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data); + virtual void marginsChange(const QMarginsF &newMargins, const QMarginsF &oldMargins); + virtual void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding); + + virtual QFont defaultFont() const; + +#ifndef QT_NO_ACCESSIBILITY + virtual QAccessible::Role accessibleRole() const; +#endif + +private: + Q_DISABLE_COPY(QQuickPopup) + Q_DECLARE_PRIVATE(QQuickPopup) + friend class QQuickPopupItem; + friend class QQuickOverlay; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickPopup::ClosePolicy) + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPopup) + +#endif // QQUICKPOPUP_P_H diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h new file mode 100644 index 00000000..577c4b51 --- /dev/null +++ b/src/quicktemplates2/qquickpopup_p_p.h @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPOPUP_P_P_H +#define QQUICKPOPUP_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickpopup_p.h" +#include "qquickcontrol_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickTransition; +class QQuickTransitionManager; +class QQuickPopup; +class QQuickPopupPrivate; +class QQuickPopupItemPrivate; + +class QQuickPopupTransitionManager : public QQuickTransitionManager +{ +public: + QQuickPopupTransitionManager(QQuickPopupPrivate *popup); + + void transitionEnter(); + void transitionExit(); + +protected: + void finished() override; + +private: + enum TransitionState { + Off, Enter, Exit + }; + + TransitionState state; + QQuickPopupPrivate *popup; +}; + +class QQuickPopupItem : public QQuickControl +{ + Q_OBJECT + +public: + explicit QQuickPopupItem(QQuickPopup *popup); + +protected: + bool childMouseEventFilter(QQuickItem *child, QEvent *event) override; + void focusInEvent(QFocusEvent *event) override; + void focusOutEvent(QFocusEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + void mouseUngrabEvent() override; + void wheelEvent(QWheelEvent *event) override; + + void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; + void fontChange(const QFont &newFont, const QFont &oldFont) override; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + void localeChange(const QLocale &newLocale, const QLocale &oldLocale) override; + void itemChange(ItemChange change, const ItemChangeData &data) override; + void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) override; + + QFont defaultFont() const override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DECLARE_PRIVATE(QQuickPopupItem) +}; + +class QQuickPopupPositioner : public QQuickItemChangeListener +{ +public: + explicit QQuickPopupPositioner(QQuickPopupPrivate *popup); + ~QQuickPopupPositioner(); + + QQuickItem *parentItem() const; + void setParentItem(QQuickItem *parent); + +protected: + void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &); + void itemParentChanged(QQuickItem *, QQuickItem *parent); + void itemChildRemoved(QQuickItem *, QQuickItem *child); + void itemDestroyed(QQuickItem *item); + +private: + void removeAncestorListeners(QQuickItem *item); + void addAncestorListeners(QQuickItem *item); + + bool isAncestor(QQuickItem *item) const; + + QQuickItem *m_parentItem; + QQuickPopupPrivate *m_popup; +}; + +class QQuickPopupPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QQuickPopup) + +public: + QQuickPopupPrivate(); + + static QQuickPopupPrivate *get(QQuickPopup *popup) + { + return popup->d_func(); + } + + void init(); + bool tryClose(QQuickItem *item, QMouseEvent *event); + virtual void reposition(); + + virtual void prepareEnterTransition(bool notify = true); + virtual void prepareExitTransition(); + virtual void finalizeEnterTransition(); + virtual void finalizeExitTransition(bool hide = true); + + QMarginsF getMargins() const; + + void setTopMargin(qreal value, bool reset = false); + void setLeftMargin(qreal value, bool reset = false); + void setRightMargin(qreal value, bool reset = false); + void setBottomMargin(qreal value, bool reset = false); + + bool focus; + bool modal; + bool visible; + bool complete; + bool hasTopMargin; + bool hasLeftMargin; + bool hasRightMargin; + bool hasBottomMargin; + qreal x; + qreal y; + qreal margins; + qreal topMargin; + qreal leftMargin; + qreal rightMargin; + qreal bottomMargin; + qreal contentWidth; + qreal contentHeight; + QQuickPopup::ClosePolicy closePolicy; + QQuickItem *parentItem; + QQuickTransition *enter; + QQuickTransition *exit; + QQuickPopupItem *popupItem; + QQuickPopupPositioner positioner; + QList enterActions; + QList exitActions; + QQuickPopupTransitionManager transitionManager; + + friend class QQuickPopupTransitionManager; +}; + +QT_END_NAMESPACE + +#endif // QQUICKPOPUP_P_P_H diff --git a/src/quicktemplates2/qquickpresshandler.cpp b/src/quicktemplates2/qquickpresshandler.cpp new file mode 100644 index 00000000..e505ab7d --- /dev/null +++ b/src/quicktemplates2/qquickpresshandler.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpresshandler_p_p.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QQuickPressHandler::QQuickPressHandler() + : control(nullptr) + , longPress(false) + , pressAndHoldSignalIndex(-1) + , delayedMousePressEvent(nullptr) +{ } + +void QQuickPressHandler::mousePressEvent(QMouseEvent *event) +{ + longPress = false; + pressPos = event->localPos(); + if (Qt::LeftButton == (event->buttons() & Qt::LeftButton)) { + timer.start(QGuiApplication::styleHints()->mousePressAndHoldInterval(), control); + delayedMousePressEvent = new QMouseEvent(event->type(), event->pos(), event->button(), event->buttons(), event->modifiers()); + } else { + timer.stop(); + } +} + +void QQuickPressHandler::mouseMoveEvent(QMouseEvent *event) +{ + if (qAbs(int(event->localPos().x() - pressPos.x())) > QGuiApplication::styleHints()->startDragDistance()) + timer.stop(); +} + +void QQuickPressHandler::mouseReleaseEvent(QMouseEvent *) +{ + if (!longPress) + timer.stop(); +} + +void QQuickPressHandler::timerEvent(QTimerEvent *) +{ + timer.stop(); + clearDelayedMouseEvent(); + + if (pressAndHoldSignalIndex == -1) + pressAndHoldSignalIndex = control->metaObject()->indexOfSignal("pressAndHold(QQuickMouseEvent*)"); + Q_ASSERT(pressAndHoldSignalIndex != -1); + + longPress = QObjectPrivate::get(control)->isSignalConnected(pressAndHoldSignalIndex); + if (longPress) { + QQuickMouseEvent mev(pressPos.x(), pressPos.y(), Qt::LeftButton, Qt::LeftButton, + QGuiApplication::keyboardModifiers(), false/*isClick*/, true/*wasHeld*/); + mev.setAccepted(true); + // Use fast signal invocation since we already got its index + QQuickMouseEvent *mevPtr = &mev; + void *args[] = { nullptr, &mevPtr }; + QMetaObject::metacall(control, QMetaObject::InvokeMetaMethod, pressAndHoldSignalIndex, args); + if (!mev.isAccepted()) + longPress = false; + } +} + +void QQuickPressHandler::clearDelayedMouseEvent() +{ + if (delayedMousePressEvent) { + delete delayedMousePressEvent; + delayedMousePressEvent = 0; + } +} + +bool QQuickPressHandler::isActive() +{ + return !(timer.isActive() || longPress); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickpresshandler_p_p.h b/src/quicktemplates2/qquickpresshandler_p_p.h new file mode 100644 index 00000000..526695e0 --- /dev/null +++ b/src/quicktemplates2/qquickpresshandler_p_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPRESSHANDLER_P_P_H +#define QQUICKPRESSHANDLER_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickItem; +class QMouseEvent; +class QTimerEvent; + +struct QQuickPressHandler +{ + QQuickPressHandler(); + + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void timerEvent(QTimerEvent *event); + + void clearDelayedMouseEvent(); + bool isActive(); + + QQuickItem *control; + QBasicTimer timer; + QPointF pressPos; + bool longPress; + int pressAndHoldSignalIndex; + QMouseEvent *delayedMousePressEvent; +}; + +QT_END_NAMESPACE + +#endif // QQUICKPRESSHANDLER_P_P_H diff --git a/src/quicktemplates2/qquickprogressbar.cpp b/src/quicktemplates2/qquickprogressbar.cpp new file mode 100644 index 00000000..779f2468 --- /dev/null +++ b/src/quicktemplates2/qquickprogressbar.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickprogressbar_p.h" +#include "qquickcontrol_p_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ProgressBar + \inherits Control + \instantiates QQuickProgressBar + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-indicators + \brief Indicates the progress of an operation. + + ProgressBar indicates the progress of an operation. The value should be updated + regularly. The range is defined by \l from and \l to, which both can contain any value. + + \table + \row \li \image qtquickcontrols-progressbar-normal.png + \li A progress bar in its normal state. + \row \li \image qtquickcontrols-progressbar-disabled.png + \li A progress bar that is disabled. + \endtable + + \code + ProgressBar { + value: 0.5 + } + \endcode + + \labs + + \sa {Customizing ProgressBar} +*/ + +class QQuickProgressBarPrivate : public QQuickControlPrivate +{ +public: + QQuickProgressBarPrivate() : from(0), to(1.0), value(0), indeterminate(false) + { + } + + qreal from; + qreal to; + qreal value; + bool indeterminate; +}; + +QQuickProgressBar::QQuickProgressBar(QQuickItem *parent) : + QQuickControl(*(new QQuickProgressBarPrivate), parent) +{ +} + +/*! + \qmlproperty real Qt.labs.controls::ProgressBar::from + + This property holds the starting value for the progress. The default value is \c 0.0. + + \sa to, value +*/ +qreal QQuickProgressBar::from() const +{ + Q_D(const QQuickProgressBar); + return d->from; +} + +void QQuickProgressBar::setFrom(qreal from) +{ + Q_D(QQuickProgressBar); + if (qFuzzyCompare(d->from, from)) + return; + + d->from = from; + emit fromChanged(); + emit positionChanged(); + emit visualPositionChanged(); + if (isComponentComplete()) + setValue(d->value); +} + +/*! + \qmlproperty real Qt.labs.controls::ProgressBar::to + + This property holds the end value for the progress. The default value is \c 1.0. + + \sa from, value +*/ +qreal QQuickProgressBar::to() const +{ + Q_D(const QQuickProgressBar); + return d->to; +} + +void QQuickProgressBar::setTo(qreal to) +{ + Q_D(QQuickProgressBar); + if (qFuzzyCompare(d->to, to)) + return; + + d->to = to; + emit toChanged(); + emit positionChanged(); + emit visualPositionChanged(); + if (isComponentComplete()) + setValue(d->value); +} + +/*! + \qmlproperty real Qt.labs.controls::ProgressBar::value + + This property holds the progress value. The default value is \c 0.0. + + \sa from, to, position +*/ +qreal QQuickProgressBar::value() const +{ + Q_D(const QQuickProgressBar); + return d->value; +} + +void QQuickProgressBar::setValue(qreal value) +{ + Q_D(QQuickProgressBar); + if (isComponentComplete()) + value = d->from > d->to ? qBound(d->to, value, d->from) : qBound(d->from, value, d->to); + + if (qFuzzyCompare(d->value, value)) + return; + + d->value = value; + emit valueChanged(); + emit positionChanged(); + emit visualPositionChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::ProgressBar::position + \readonly + + This property holds the logical position of the progress. + + The position is defined as a percentage of the value, scaled to + \c {0.0 - 1.0}. For visualizing the progress, the right-to-left + aware \l visualPosition should be used instead. + + \sa value, visualPosition +*/ +qreal QQuickProgressBar::position() const +{ + Q_D(const QQuickProgressBar); + if (qFuzzyCompare(d->from, d->to)) + return 0; + return (d->value - d->from) / (d->to - d->from); +} + +/*! + \qmlproperty real Qt.labs.controls::ProgressBar::visualPosition + \readonly + + This property holds the visual position of the progress. + + The position is defined as a percentage of the value, scaled to \c {0.0 - 1.0}. + When the control is \l {Control::mirrored}{mirrored}, \c visuaPosition is equal + to \c {1.0 - position}. This makes \c visualPosition suitable for visualizing + the progress, taking right-to-left support into account. + + \sa position, value +*/ +qreal QQuickProgressBar::visualPosition() const +{ + if (isMirrored()) + return 1.0 - position(); + return position(); +} + +/*! + \qmlproperty bool Qt.labs.controls::ProgressBar::indeterminate + + This property holds whether the progress bar is in indeterminate mode. + A progress bar in indeterminate mode displays that an operation is in progress, but it + doesn't show how much progress has been made. + + See below for an example: + \image qtquickcontrols-progressbar-indeterminate.png + +*/ +bool QQuickProgressBar::isIndeterminate() const +{ + Q_D(const QQuickProgressBar); + return d->indeterminate; +} + +void QQuickProgressBar::setIndeterminate(bool indeterminate) +{ + Q_D(QQuickProgressBar); + if (d->indeterminate == indeterminate) + return; + + d->indeterminate = indeterminate; + emit indeterminateChanged(); +} + +void QQuickProgressBar::mirrorChange() +{ + QQuickControl::mirrorChange(); + if (!qFuzzyCompare(position(), qreal(0.5))) + emit visualPositionChanged(); +} + +void QQuickProgressBar::componentComplete() +{ + Q_D(QQuickProgressBar); + QQuickControl::componentComplete(); + setValue(d->value); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickProgressBar::accessibleRole() const +{ + return QAccessible::ProgressBar; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickprogressbar_p.h b/src/quicktemplates2/qquickprogressbar_p.h new file mode 100644 index 00000000..4d81c706 --- /dev/null +++ b/src/quicktemplates2/qquickprogressbar_p.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPROGRESSBAR_P_H +#define QQUICKPROGRESSBAR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickProgressBarPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickProgressBar : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged FINAL) + Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged FINAL) + Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged FINAL) + Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL) + Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL) + Q_PROPERTY(bool indeterminate READ isIndeterminate WRITE setIndeterminate NOTIFY indeterminateChanged FINAL) + +public: + explicit QQuickProgressBar(QQuickItem *parent = nullptr); + + qreal from() const; + void setFrom(qreal from); + + qreal to() const; + void setTo(qreal to); + + qreal value() const; + void setValue(qreal value); + + qreal position() const; + qreal visualPosition() const; + + bool isIndeterminate() const; + void setIndeterminate(bool indeterminate); + +Q_SIGNALS: + void fromChanged(); + void toChanged(); + void valueChanged(); + void positionChanged(); + void visualPositionChanged(); + void indeterminateChanged(); + +protected: + void mirrorChange() override; + void componentComplete() override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickProgressBar) + Q_DECLARE_PRIVATE(QQuickProgressBar) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickProgressBar) + +#endif // QQUICKPROGRESSBAR_P_H diff --git a/src/quicktemplates2/qquickradiobutton.cpp b/src/quicktemplates2/qquickradiobutton.cpp new file mode 100644 index 00000000..93a3c4a7 --- /dev/null +++ b/src/quicktemplates2/qquickradiobutton.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickradiobutton_p.h" +#include "qquickcontrol_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype RadioButton + \inherits AbstractButton + \instantiates QQuickRadioButton + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-buttons + \brief An option button that can be toggled on or off. + + RadioButton presents an option button that can be toggled on (checked) or + off (unchecked). Radio buttons are typically used to select one option + from a set of options. + + \table + \row \li \image qtquickcontrols-radiobutton-normal.png + \li A radio button in its normal state. + \row \li \image qtquickcontrols-radiobutton-checked.png + \li A radio button that is checked. + \row \li \image qtquickcontrols-radiobutton-focused.png + \li A radio button that has active focus. + \row \li \image qtquickcontrols-radiobutton-disabled.png + \li A radio button that is disabled. + \endtable + + Radio buttons are \l {AbstractButton::autoExclusive}{auto-exclusive} + by default. Only one button can be checked at any time amongst radio + buttons that belong to the same parent item; checking another button + automatically unchecks the previously checked one. + + \code + ColumnLayout { + RadioButton { + checked: true + text: qsTr("First") + } + RadioButton { + text: qsTr("Second") + } + RadioButton { + text: qsTr("Third") + } + } + \endcode + + \labs + + \sa ButtonGroup, {Customizing RadioButton}, {Button Controls} +*/ + +QQuickRadioButton::QQuickRadioButton(QQuickItem *parent) : + QQuickAbstractButton(parent) +{ + setCheckable(true); + setAutoExclusive(true); +} + +QFont QQuickRadioButton::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::RadioButtonFont); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickRadioButton::accessibleRole() const +{ + return QAccessible::RadioButton; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickradiobutton_p.h b/src/quicktemplates2/qquickradiobutton_p.h new file mode 100644 index 00000000..1ddba7c9 --- /dev/null +++ b/src/quicktemplates2/qquickradiobutton_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKRADIOBUTTON_P_H +#define QQUICKRADIOBUTTON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class Q_QUICKTEMPLATES2_EXPORT QQuickRadioButton : public QQuickAbstractButton +{ + Q_OBJECT + +public: + explicit QQuickRadioButton(QQuickItem *parent = nullptr); + +protected: + QFont defaultFont() const override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickRadioButton) + +#endif // QQUICKRADIOBUTTON_P_H diff --git a/src/quicktemplates2/qquickradiodelegate.cpp b/src/quicktemplates2/qquickradiodelegate.cpp new file mode 100644 index 00000000..e70044e7 --- /dev/null +++ b/src/quicktemplates2/qquickradiodelegate.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickradiodelegate_p.h" +#include "qquickabstractbutton_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype RadioDelegate + \inherits ItemDelegate + \instantiates QQuickRadioDelegate + \inqmlmodule Qt.labs.controls + \ingroup qtlabscontrols-delegates + \brief An item delegate that can be checked or unchecked. + + \image qtquickcontrols-radiodelegate.gif + + RadioDelegate presents an item delegate that can be toggled on (checked) or + off (unchecked). Radio delegates are typically used to select one option + from a set of options. + + The state of the radio delegate can be set with the + \l {AbstractButton::}{checked} property. + + \code + ButtonGroup { + id: buttonGroup + } + + ListView { + model: ["Option 1", "Option 2", "Option 3"] + delegate: RadioDelegate { + text: modelData + checked: index == 0 + ButtonGroup.group: buttonGroup + } + } + \endcode + + \labs + + \sa {Customizing RadioDelegate}, {Delegate Controls} +*/ + +QQuickRadioDelegate::QQuickRadioDelegate(QQuickItem *parent) : + QQuickItemDelegate(parent) +{ + setCheckable(true); + setAutoExclusive(true); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickRadioDelegate::accessibleRole() const +{ + return QAccessible::RadioButton; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickradiodelegate_p.h b/src/quicktemplates2/qquickradiodelegate_p.h new file mode 100644 index 00000000..b428bd37 --- /dev/null +++ b/src/quicktemplates2/qquickradiodelegate_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKRADIODELEGATE_P_H +#define QQUICKRADIODELEGATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickRadioDelegatePrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickRadioDelegate : public QQuickItemDelegate +{ + Q_OBJECT + +public: + explicit QQuickRadioDelegate(QQuickItem *parent = nullptr); + +protected: +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickRadioDelegate) + +#endif // QQUICKRADIODELEGATE_P_H diff --git a/src/quicktemplates2/qquickrangeslider.cpp b/src/quicktemplates2/qquickrangeslider.cpp new file mode 100644 index 00000000..19ce5e19 --- /dev/null +++ b/src/quicktemplates2/qquickrangeslider.cpp @@ -0,0 +1,927 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickrangeslider_p.h" +#include "qquickcontrol_p_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype RangeSlider + \inherits Control + \instantiates QQuickRangeSlider + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-input + \brief A slider control used to select a range of values. + + \image qtquickcontrols-rangeslider.gif + + RangeSlider is used to select a range specified by two values, by sliding + each handle along a track. + + \table + \row \li \image qtquickcontrols-rangeslider-normal.png + \li A range slider in its normal state. + \row \li \image qtquickcontrols-rangeslider-first-handle-focused.png + \li A range slider whose first handle has active focus. + \row \li \image qtquickcontrols-rangeslider-second-handle-focused.png + \li A range slider whose second handle has active focus. + \row \li \image qtquickcontrols-rangeslider-disabled.png + \li A range slider that is disabled. + \endtable + + \code + RangeSlider { + first.value: 0.25 + second.value: 0.75 + } + \endcode + + \labs + + \sa {Customizing RangeSlider}, {Input Controls} +*/ + +class QQuickRangeSliderNodePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QQuickRangeSliderNode) +public: + QQuickRangeSliderNodePrivate(qreal value, QQuickRangeSlider *slider) : + value(value), + isPendingValue(false), + pendingValue(0), + position(0), + handle(nullptr), + slider(slider), + pressed(false) + { + } + + bool isFirst() const; + + void setPosition(qreal position, bool ignoreOtherPosition = false); + void updatePosition(bool ignoreOtherPosition = false); + + static QQuickRangeSliderNodePrivate *get(QQuickRangeSliderNode *node); + +private: + friend class QQuickRangeSlider; + + qreal value; + bool isPendingValue; + qreal pendingValue; + qreal position; + QQuickItem *handle; + QQuickRangeSlider *slider; + bool pressed; +}; + +bool QQuickRangeSliderNodePrivate::isFirst() const +{ + return this == get(slider->first()); +} + +void QQuickRangeSliderNodePrivate::setPosition(qreal position, bool ignoreOtherPosition) +{ + Q_Q(QQuickRangeSliderNode); + + const qreal min = isFirst() || ignoreOtherPosition ? 0.0 : qMax(0.0, slider->first()->position()); + const qreal max = !isFirst() || ignoreOtherPosition ? 1.0 : qMin(1.0, slider->second()->position()); + position = qBound(min, position, max); + if (!qFuzzyCompare(this->position, position)) { + this->position = position; + emit q->positionChanged(); + emit q->visualPositionChanged(); + } +} + +void QQuickRangeSliderNodePrivate::updatePosition(bool ignoreOtherPosition) +{ + qreal pos = 0; + if (!qFuzzyCompare(slider->from(), slider->to())) + pos = (value - slider->from()) / (slider->to() - slider->from()); + setPosition(pos, ignoreOtherPosition); +} + +QQuickRangeSliderNodePrivate *QQuickRangeSliderNodePrivate::get(QQuickRangeSliderNode *node) +{ + return node->d_func(); +} + +QQuickRangeSliderNode::QQuickRangeSliderNode(qreal value, QQuickRangeSlider *slider) : + QObject(*(new QQuickRangeSliderNodePrivate(value, slider)), slider) +{ +} + +QQuickRangeSliderNode::~QQuickRangeSliderNode() +{ +} + +qreal QQuickRangeSliderNode::value() const +{ + Q_D(const QQuickRangeSliderNode); + return d->value; +} + +void QQuickRangeSliderNode::setValue(qreal value) +{ + Q_D(QQuickRangeSliderNode); + if (!d->slider->isComponentComplete()) { + d->pendingValue = value; + d->isPendingValue = true; + return; + } + + // First, restrict the first value to be within to and from. + const qreal smaller = qMin(d->slider->to(), d->slider->from()); + const qreal larger = qMax(d->slider->to(), d->slider->from()); + value = qBound(smaller, value, larger); + + // Then, ensure that it doesn't go past the other value, + // a check that depends on whether or not the range is inverted. + const bool invertedRange = d->slider->from() > d->slider->to(); + if (d->isFirst()) { + if (invertedRange) { + if (value < d->slider->second()->value()) + value = d->slider->second()->value(); + } else { + if (value > d->slider->second()->value()) + value = d->slider->second()->value(); + } + } else { + if (invertedRange) { + if (value > d->slider->first()->value()) + value = d->slider->first()->value(); + } else { + if (value < d->slider->first()->value()) + value = d->slider->first()->value(); + } + } + + if (!qFuzzyCompare(d->value, value)) { + d->value = value; + d->updatePosition(); + emit valueChanged(); + } +} + +qreal QQuickRangeSliderNode::position() const +{ + Q_D(const QQuickRangeSliderNode); + return d->position; +} + +qreal QQuickRangeSliderNode::visualPosition() const +{ + Q_D(const QQuickRangeSliderNode); + if (d->slider->orientation() == Qt::Vertical || d->slider->isMirrored()) + return 1.0 - d->position; + return d->position; +} + +QQuickItem *QQuickRangeSliderNode::handle() const +{ + Q_D(const QQuickRangeSliderNode); + return d->handle; +} + +void QQuickRangeSliderNode::setHandle(QQuickItem *handle) +{ + Q_D(QQuickRangeSliderNode); + if (d->handle == handle) + return; + + delete d->handle; + d->handle = handle; + if (handle) { + if (!handle->parentItem()) + handle->setParentItem(d->slider); + + QQuickItem *firstHandle = d->slider->first()->handle(); + QQuickItem *secondHandle = d->slider->second()->handle(); + if (firstHandle && secondHandle) { + // The order of property assignments in QML is undefined, + // but we need the first handle to be before the second due + // to focus order constraints, so check for that here. + const QList childItems = d->slider->childItems(); + const int firstIndex = childItems.indexOf(firstHandle); + const int secondIndex = childItems.indexOf(secondHandle); + if (firstIndex != -1 && secondIndex != -1 && firstIndex > secondIndex) { + firstHandle->stackBefore(secondHandle); + // Ensure we have some way of knowing which handle is above + // the other when it comes to mouse presses, and also that + // they are rendered in the correct order. + secondHandle->setZ(secondHandle->z() + 1); + } + } + + handle->setActiveFocusOnTab(true); + } + emit handleChanged(); +} + +bool QQuickRangeSliderNode::isPressed() const +{ + Q_D(const QQuickRangeSliderNode); + return d->pressed; +} + +void QQuickRangeSliderNode::setPressed(bool pressed) +{ + Q_D(QQuickRangeSliderNode); + if (d->pressed == pressed) + return; + + d->pressed = pressed; + d->slider->setAccessibleProperty("pressed", pressed || d->slider->second()->isPressed()); + emit pressedChanged(); +} + +void QQuickRangeSliderNode::increase() +{ + Q_D(QQuickRangeSliderNode); + qreal step = qFuzzyIsNull(d->slider->stepSize()) ? 0.1 : d->slider->stepSize(); + setValue(d->value + step); +} + +void QQuickRangeSliderNode::decrease() +{ + Q_D(QQuickRangeSliderNode); + qreal step = qFuzzyIsNull(d->slider->stepSize()) ? 0.1 : d->slider->stepSize(); + setValue(d->value - step); +} + +static const qreal defaultFrom = 0.0; +static const qreal defaultTo = 1.0; + +class QQuickRangeSliderPrivate : public QQuickControlPrivate +{ + Q_DECLARE_PUBLIC(QQuickRangeSlider) + +public: + QQuickRangeSliderPrivate() : + from(defaultFrom), + to(defaultTo), + stepSize(0), + first(nullptr), + second(nullptr), + orientation(Qt::Horizontal), + snapMode(QQuickRangeSlider::NoSnap) + { + } + + qreal from; + qreal to; + qreal stepSize; + QQuickRangeSliderNode *first; + QQuickRangeSliderNode *second; + QPoint pressPoint; + Qt::Orientation orientation; + QQuickRangeSlider::SnapMode snapMode; +}; + +static qreal valueAt(const QQuickRangeSlider *slider, qreal position) +{ + return slider->from() + (slider->to() - slider->from()) * position; +} + +static qreal snapPosition(const QQuickRangeSlider *slider, qreal position) +{ + const qreal range = slider->from() + (slider->to() - slider->from()); + if (qFuzzyIsNull(range)) + return position; + + const qreal effectiveStep = slider->stepSize() / range; + if (qFuzzyIsNull(effectiveStep)) + return position; + + return qRound(position / effectiveStep) * effectiveStep; +} + +static qreal positionAt(const QQuickRangeSlider *slider, QQuickItem *handle, const QPoint &point) +{ + if (slider->orientation() == Qt::Horizontal) { + const qreal hw = handle ? handle->width() : 0; + const qreal offset = hw / 2; + const qreal extent = slider->availableWidth() - hw; + if (!qFuzzyIsNull(extent)) { + if (slider->isMirrored()) + return (slider->width() - point.x() - slider->rightPadding() - offset) / extent; + return (point.x() - slider->leftPadding() - offset) / extent; + } + } else { + const qreal hh = handle ? handle->height() : 0; + const qreal offset = hh / 2; + const qreal extent = slider->availableHeight() - hh; + if (!qFuzzyIsNull(extent)) + return (slider->height() - point.y() - slider->bottomPadding() - offset) / extent; + } + return 0; +} + +QQuickRangeSlider::QQuickRangeSlider(QQuickItem *parent) : + QQuickControl(*(new QQuickRangeSliderPrivate), parent) +{ + Q_D(QQuickRangeSlider); + d->first = new QQuickRangeSliderNode(0.0, this); + d->second = new QQuickRangeSliderNode(1.0, this); + + setAcceptedMouseButtons(Qt::LeftButton); + setFlag(QQuickItem::ItemIsFocusScope); +} + +/*! + \qmlproperty real Qt.labs.controls::RangeSlider::from + + This property holds the starting value for the range. The default value is \c 0.0. + + \sa to, first.value, second.value +*/ +qreal QQuickRangeSlider::from() const +{ + Q_D(const QQuickRangeSlider); + return d->from; +} + +void QQuickRangeSlider::setFrom(qreal from) +{ + Q_D(QQuickRangeSlider); + if (qFuzzyCompare(d->from, from)) + return; + + d->from = from; + emit fromChanged(); + + if (isComponentComplete()) { + d->first->setValue(d->first->value()); + d->second->setValue(d->second->value()); + } +} + +/*! + \qmlproperty real Qt.labs.controls::RangeSlider::to + + This property holds the end value for the range. The default value is \c 1.0. + + \sa from, first.value, second.value +*/ +qreal QQuickRangeSlider::to() const +{ + Q_D(const QQuickRangeSlider); + return d->to; +} + +void QQuickRangeSlider::setTo(qreal to) +{ + Q_D(QQuickRangeSlider); + if (qFuzzyCompare(d->to, to)) + return; + + d->to = to; + emit toChanged(); + + if (isComponentComplete()) { + d->first->setValue(d->first->value()); + d->second->setValue(d->second->value()); + } +} + +/*! + \qmlpropertygroup Qt.labs.controls::RangeSlider::first + \qmlproperty real Qt.labs.controls::RangeSlider::first.value + \qmlproperty real Qt.labs.controls::RangeSlider::first.position + \qmlproperty real Qt.labs.controls::RangeSlider::first.visualPosition + \qmlproperty Item Qt.labs.controls::RangeSlider::first.handle + \qmlproperty bool Qt.labs.controls::RangeSlider::first.pressed + + \table + \header + \li Property + \li Description + \row + \li value + \li This property holds the value of the first handle in the range + \c from - \c to. + + If \l to is greater than \l from, the value of the first handle + must be greater than the second, and vice versa. + + Unlike \l {first.position}{position}, value is not updated while the + handle is dragged, but rather when it has been released. + + The default value is \c 0.0. + \row + \li handle + \li This property holds the first handle item. + \row + \li visualPosition + \li This property holds the visual position of the first handle. + + The position is defined as a percentage of the control's size, scaled to + \c {0.0 - 1.0}. When the control is \l {Control::mirrored}{mirrored}, the + value is equal to \c {1.0 - position}. This makes the value suitable for + visualizing the slider, taking right-to-left support into account. + \row + \li position + \li This property holds the logical position of the first handle. + + The position is defined as a percentage of the control's size, scaled + to \c {0.0 - 1.0}. Unlike \l {first.value}{value}, position is + continuously updated while the handle is dragged. For visualizing a + slider, the right-to-left aware + \l {first.visualPosition}{visualPosition} should be used instead. + \row + \li pressed + \li This property holds whether the first handle is pressed. + \endtable + + \sa first.increase(), first.decrease() +*/ +QQuickRangeSliderNode *QQuickRangeSlider::first() const +{ + Q_D(const QQuickRangeSlider); + return d->first; +} + +/*! + \qmlpropertygroup Qt.labs.controls::RangeSlider::second + \qmlproperty real Qt.labs.controls::RangeSlider::second.value + \qmlproperty real Qt.labs.controls::RangeSlider::second.position + \qmlproperty real Qt.labs.controls::RangeSlider::second.visualPosition + \qmlproperty Item Qt.labs.controls::RangeSlider::second.handle + \qmlproperty bool Qt.labs.controls::RangeSlider::second.pressed + + \table + \header + \li Property + \li Description + \row + \li value + \li This property holds the value of the second handle in the range + \c from - \c to. + + If \l to is greater than \l from, the value of the first handle + must be greater than the second, and vice versa. + + Unlike \l {second.position}{position}, value is not updated while the + handle is dragged, but rather when it has been released. + + The default value is \c 0.0. + \row + \li handle + \li This property holds the second handle item. + \row + \li visualPosition + \li This property holds the visual position of the second handle. + + The position is defined as a percentage of the control's size, scaled to + \c {0.0 - 1.0}. When the control is \l {Control::mirrored}{mirrored}, the + value is equal to \c {1.0 - position}. This makes the value suitable for + visualizing the slider, taking right-to-left support into account. + \row + \li position + \li This property holds the logical position of the second handle. + + The position is defined as a percentage of the control's size, scaled + to \c {0.0 - 1.0}. Unlike \l {second.value}{value}, position is + continuously updated while the handle is dragged. For visualizing a + slider, the right-to-left aware + \l {second.visualPosition}{visualPosition} should be used instead. + \row + \li pressed + \li This property holds whether the second handle is pressed. + \endtable + + \sa second.increase(), second.decrease() +*/ +QQuickRangeSliderNode *QQuickRangeSlider::second() const +{ + Q_D(const QQuickRangeSlider); + return d->second; +} + +/*! + \qmlproperty real Qt.labs.controls::RangeSlider::stepSize + + This property holds the step size. The default value is \c 0.0. + + \sa snapMode, first.increase(), first.decrease() +*/ +qreal QQuickRangeSlider::stepSize() const +{ + Q_D(const QQuickRangeSlider); + return d->stepSize; +} + +void QQuickRangeSlider::setStepSize(qreal step) +{ + Q_D(QQuickRangeSlider); + if (qFuzzyCompare(d->stepSize, step)) + return; + + d->stepSize = step; + emit stepSizeChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::RangeSlider::snapMode + + This property holds the snap mode. + + Possible values: + \value RangeSlider.NoSnap The slider does not snap (default). + \value RangeSlider.SnapAlways The slider snaps while the handle is dragged. + \value RangeSlider.SnapOnRelease The slider does not snap while being dragged, but only after the handle is released. + + \sa stepSize +*/ +QQuickRangeSlider::SnapMode QQuickRangeSlider::snapMode() const +{ + Q_D(const QQuickRangeSlider); + return d->snapMode; +} + +void QQuickRangeSlider::setSnapMode(SnapMode mode) +{ + Q_D(QQuickRangeSlider); + if (d->snapMode == mode) + return; + + d->snapMode = mode; + emit snapModeChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::RangeSlider::orientation + + This property holds the orientation. + + Possible values: + \value Qt.Horizontal Horizontal (default) + \value Qt.Vertical Vertical +*/ +Qt::Orientation QQuickRangeSlider::orientation() const +{ + Q_D(const QQuickRangeSlider); + return d->orientation; +} + +void QQuickRangeSlider::setOrientation(Qt::Orientation orientation) +{ + Q_D(QQuickRangeSlider); + if (d->orientation == orientation) + return; + + d->orientation = orientation; + emit orientationChanged(); +} + +/*! + \qmlmethod void Qt.labs.controls::RangeSlider::setValues(real firstValue, real secondValue) + + Sets \l first.value and \l second.value with the given arguments. + + If \a to is larger than \a from and \a firstValue is larger than + \a secondValue, \a firstValue will be clamped to \a secondValue. + + If \a from is larger than \a to and \a secondValue is larger than + \a firstValue, \a secondValue will be clamped to \a firstValue. + + This function may be necessary to set the first and second values + after the control has been completed, as there is a circular + dependency between firstValue and secondValue which can cause + assigned values to be clamped to each other. + + \sa stepSize +*/ +void QQuickRangeSlider::setValues(qreal firstValue, qreal secondValue) +{ + Q_D(QQuickRangeSlider); + // Restrict the values to be within to and from. + const qreal smaller = qMin(d->to, d->from); + const qreal larger = qMax(d->to, d->from); + firstValue = qBound(smaller, firstValue, larger); + secondValue = qBound(smaller, secondValue, larger); + + if (d->from > d->to) { + // If the from and to values are reversed, the secondValue + // might be less than the first value, which is not allowed. + if (secondValue > firstValue) + secondValue = firstValue; + } else { + // Otherwise, clamp first to second if it's too large. + if (firstValue > secondValue) + firstValue = secondValue; + } + + // Then set both values. If they didn't change, no change signal will be emitted. + QQuickRangeSliderNodePrivate *firstPrivate = QQuickRangeSliderNodePrivate::get(d->first); + if (firstValue != firstPrivate->value) { + firstPrivate->value = firstValue; + emit d->first->valueChanged(); + } + + QQuickRangeSliderNodePrivate *secondPrivate = QQuickRangeSliderNodePrivate::get(d->second); + if (secondValue != secondPrivate->value) { + secondPrivate->value = secondValue; + emit d->second->valueChanged(); + } + + // After we've set both values, then we can update the positions. + // If we don't do this last, the positions may be incorrect. + firstPrivate->updatePosition(true); + secondPrivate->updatePosition(); +} + +void QQuickRangeSlider::focusInEvent(QFocusEvent *event) +{ + Q_D(QQuickRangeSlider); + QQuickControl::focusInEvent(event); + + // The active focus ends up to RangeSlider when using forceActiveFocus() + // or QML KeyNavigation. We must forward the focus to one of the handles, + // because RangeSlider handles key events for the focused handle. If + // neither handle has active focus, RangeSlider doesn't do anything. + QQuickItem *handle = nextItemInFocusChain(); + // QQuickItem::nextItemInFocusChain() only works as desired with + // Qt::TabFocusAllControls. otherwise pick the first handle + if (!handle || handle == this) + handle = d->first->handle(); + if (handle) + handle->forceActiveFocus(event->reason()); +} + +void QQuickRangeSlider::keyPressEvent(QKeyEvent *event) +{ + Q_D(QQuickRangeSlider); + QQuickControl::keyPressEvent(event); + + QQuickRangeSliderNode *focusNode = d->first->handle()->hasActiveFocus() + ? d->first : (d->second->handle()->hasActiveFocus() ? d->second : nullptr); + if (!focusNode) + return; + + if (d->orientation == Qt::Horizontal) { + if (event->key() == Qt::Key_Left) { + focusNode->setPressed(true); + if (isMirrored()) + focusNode->increase(); + else + focusNode->decrease(); + event->accept(); + } else if (event->key() == Qt::Key_Right) { + focusNode->setPressed(true); + if (isMirrored()) + focusNode->decrease(); + else + focusNode->increase(); + event->accept(); + } + } else { + if (event->key() == Qt::Key_Up) { + focusNode->setPressed(true); + focusNode->increase(); + event->accept(); + } else if (event->key() == Qt::Key_Down) { + focusNode->setPressed(true); + focusNode->decrease(); + event->accept(); + } + } +} + +void QQuickRangeSlider::keyReleaseEvent(QKeyEvent *event) +{ + Q_D(QQuickRangeSlider); + QQuickControl::keyReleaseEvent(event); + d->first->setPressed(false); + d->second->setPressed(false); +} + +void QQuickRangeSlider::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickRangeSlider); + QQuickControl::mousePressEvent(event); + d->pressPoint = event->pos(); + + QQuickItem *firstHandle = d->first->handle(); + QQuickItem *secondHandle = d->second->handle(); + const bool firstHit = firstHandle && firstHandle->contains(mapToItem(firstHandle, d->pressPoint)); + const bool secondHit = secondHandle && secondHandle->contains(mapToItem(secondHandle, d->pressPoint)); + QQuickRangeSliderNode *hitNode = nullptr; + QQuickRangeSliderNode *otherNode = nullptr; + + if (firstHit && secondHit) { + // choose highest + hitNode = firstHandle->z() > secondHandle->z() ? d->first : d->second; + otherNode = firstHandle->z() > secondHandle->z() ? d->second : d->first; + } else if (firstHit) { + hitNode = d->first; + otherNode = d->second; + } else if (secondHit) { + hitNode = d->second; + otherNode = d->first; + } else { + // find the nearest + const qreal firstDistance = QLineF(firstHandle->boundingRect().center(), + mapToItem(firstHandle, event->pos())).length(); + const qreal secondDistance = QLineF(secondHandle->boundingRect().center(), + mapToItem(secondHandle, event->pos())).length(); + + if (qFuzzyCompare(firstDistance, secondDistance)) { + // same distance => choose the one that can be moved towards the press position + const bool inverted = d->from > d->to; + const qreal pos = positionAt(this, firstHandle, event->pos()); + if ((!inverted && pos < d->first->position()) || (inverted && pos > d->first->position())) { + hitNode = d->first; + otherNode = d->second; + } else { + hitNode = d->second; + otherNode = d->first; + } + } else if (firstDistance < secondDistance) { + hitNode = d->first; + otherNode = d->second; + } else { + hitNode = d->second; + otherNode = d->first; + } + } + + if (hitNode) { + hitNode->setPressed(true); + hitNode->handle()->setZ(1); + } + if (otherNode) + otherNode->handle()->setZ(0); +} + +void QQuickRangeSlider::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickRangeSlider); + QQuickControl::mouseMoveEvent(event); + if (!keepMouseGrab()) { + if (d->orientation == Qt::Horizontal) + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(event->pos().x() - d->pressPoint.x(), Qt::XAxis, event)); + else + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(event->pos().y() - d->pressPoint.y(), Qt::YAxis, event)); + } + if (keepMouseGrab()) { + QQuickRangeSliderNode *pressedNode = d->first->isPressed() ? d->first : (d->second->isPressed() ? d->second : nullptr); + if (pressedNode) { + qreal pos = positionAt(this, pressedNode->handle(), event->pos()); + if (d->snapMode == SnapAlways) + pos = snapPosition(this, pos); + QQuickRangeSliderNodePrivate::get(pressedNode)->setPosition(pos); + } + } +} + +void QQuickRangeSlider::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickRangeSlider); + QQuickControl::mouseReleaseEvent(event); + + d->pressPoint = QPoint(); + if (!keepMouseGrab()) + return; + + QQuickRangeSliderNode *pressedNode = d->first->isPressed() ? d->first : (d->second->isPressed() ? d->second : nullptr); + if (!pressedNode) + return; + + qreal pos = positionAt(this, pressedNode->handle(), event->pos()); + if (d->snapMode != NoSnap) + pos = snapPosition(this, pos); + qreal val = valueAt(this, pos); + if (!qFuzzyCompare(val, pressedNode->value())) + pressedNode->setValue(val); + else if (d->snapMode != NoSnap) + QQuickRangeSliderNodePrivate::get(pressedNode)->setPosition(pos); + setKeepMouseGrab(false); + pressedNode->setPressed(false); +} + +void QQuickRangeSlider::mouseUngrabEvent() +{ + Q_D(QQuickRangeSlider); + QQuickControl::mouseUngrabEvent(); + d->pressPoint = QPoint(); + d->first->setPressed(false); + d->second->setPressed(false); +} + +void QQuickRangeSlider::mirrorChange() +{ + Q_D(QQuickRangeSlider); + QQuickControl::mirrorChange(); + emit d->first->visualPositionChanged(); + emit d->second->visualPositionChanged(); +} + +void QQuickRangeSlider::componentComplete() +{ + Q_D(QQuickRangeSlider); + QQuickControl::componentComplete(); + + QQuickRangeSliderNodePrivate *firstPrivate = QQuickRangeSliderNodePrivate::get(d->first); + QQuickRangeSliderNodePrivate *secondPrivate = QQuickRangeSliderNodePrivate::get(d->second); + + if (firstPrivate->isPendingValue || secondPrivate->isPendingValue + || !qFuzzyCompare(d->from, defaultFrom) || !qFuzzyCompare(d->to, defaultTo)) { + // Properties were set while we were loading. To avoid clamping issues that occur when setting the + // values of first and second overriding values set by the user, set them all at once at the end. + // Another reason that we must set these values here is that the from and to values might have made the old range invalid. + setValues(firstPrivate->isPendingValue ? firstPrivate->pendingValue : firstPrivate->value, + secondPrivate->isPendingValue ? secondPrivate->pendingValue : secondPrivate->value); + + firstPrivate->pendingValue = 0; + firstPrivate->isPendingValue = false; + secondPrivate->pendingValue = 0; + secondPrivate->isPendingValue = false; + } else { + // If there was no pending data, we must still update the positions, + // as first.setValue()/second.setValue() won't be called as part of default construction. + // Don't need to ignore the second position when updating the first position here, + // as our default values are guaranteed to be valid. + firstPrivate->updatePosition(); + secondPrivate->updatePosition(); + } +} + +/*! + \qmlmethod void Qt.labs.controls::RangeSlider::first.increase() + + Increases the value of the handle by stepSize, or \c 0.1 if stepSize is not defined. + + \sa first +*/ + +/*! + \qmlmethod void Qt.labs.controls::RangeSlider::first.decrease() + + Decreases the value of the handle by stepSize, or \c 0.1 if stepSize is not defined. + + \sa first +*/ + +/*! + \qmlmethod void Qt.labs.controls::RangeSlider::second.increase() + + Increases the value of the handle by stepSize, or \c 0.1 if stepSize is not defined. + + \sa second +*/ + +/*! + \qmlmethod void Qt.labs.controls::RangeSlider::second.decrease() + + Decreases the value of the handle by stepSize, or \c 0.1 if stepSize is not defined. + + \sa second +*/ + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickRangeSlider::accessibleRole() const +{ + return QAccessible::Slider; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickrangeslider_p.h b/src/quicktemplates2/qquickrangeslider_p.h new file mode 100644 index 00000000..009116c9 --- /dev/null +++ b/src/quicktemplates2/qquickrangeslider_p.h @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKRANGESLIDER_H +#define QQUICKRANGESLIDER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickRangeSliderPrivate; +class QQuickRangeSliderNode; + +class Q_QUICKTEMPLATES2_EXPORT QQuickRangeSlider : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged FINAL) + Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged FINAL) + Q_PROPERTY(QQuickRangeSliderNode *first READ first CONSTANT) + Q_PROPERTY(QQuickRangeSliderNode *second READ second CONSTANT) + Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL) + Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged FINAL) + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL) + +public: + explicit QQuickRangeSlider(QQuickItem *parent = nullptr); + + qreal from() const; + void setFrom(qreal from); + + qreal to() const; + void setTo(qreal to); + + QQuickRangeSliderNode *first() const; + QQuickRangeSliderNode *second() const; + + qreal stepSize() const; + void setStepSize(qreal step); + + enum SnapMode { + NoSnap, + SnapAlways, + SnapOnRelease + }; + Q_ENUM(SnapMode) + + SnapMode snapMode() const; + void setSnapMode(SnapMode mode); + + Qt::Orientation orientation() const; + void setOrientation(Qt::Orientation orientation); + + Q_INVOKABLE void setValues(qreal firstValue, qreal secondValue); + +Q_SIGNALS: + void fromChanged(); + void toChanged(); + void stepSizeChanged(); + void snapModeChanged(); + void orientationChanged(); + +protected: + void focusInEvent(QFocusEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseUngrabEvent() override; + void mirrorChange() override; + void componentComplete() override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + friend class QQuickRangeSliderNode; + + Q_DISABLE_COPY(QQuickRangeSlider) + Q_DECLARE_PRIVATE(QQuickRangeSlider) +}; + +class QQuickRangeSliderNodePrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickRangeSliderNode : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged FINAL) + Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL) + Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL) + Q_PROPERTY(QQuickItem *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL) + Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL) + +public: + explicit QQuickRangeSliderNode(qreal value, QQuickRangeSlider *slider); + ~QQuickRangeSliderNode(); + + qreal value() const; + void setValue(qreal value); + + qreal position() const; + qreal visualPosition() const; + + QQuickItem *handle() const; + void setHandle(QQuickItem *handle); + + bool isPressed() const; + void setPressed(bool pressed); + +public Q_SLOTS: + void increase(); + void decrease(); + +Q_SIGNALS: + void valueChanged(); + void positionChanged(); + void visualPositionChanged(); + void handleChanged(); + void pressedChanged(); + +private: + Q_DISABLE_COPY(QQuickRangeSliderNode) + Q_DECLARE_PRIVATE(QQuickRangeSliderNode) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickRangeSlider) + +#endif // QQUICKRANGESLIDER_H diff --git a/src/quicktemplates2/qquickscrollbar.cpp b/src/quicktemplates2/qquickscrollbar.cpp new file mode 100644 index 00000000..f8ce76ab --- /dev/null +++ b/src/quicktemplates2/qquickscrollbar.cpp @@ -0,0 +1,620 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickscrollbar_p.h" +#include "qquickcontrol_p_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ScrollBar + \inherits Control + \instantiates QQuickScrollBar + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-indicators + \brief An interactive scroll bar control. + + ScrollBar is an interactive bar that can be used to scroll to a specific + position. A scroll bar can be either \l vertical or \l horizontal, and can + be attached to any \l Flickable, such as \l ListView and \l GridView. + + \image qtquickcontrols-scrollbar.png + + \code + Flickable { + // ... + ScrollBar.vertical: ScrollBar { } + } + \endcode + + \note When ScrollBar is attached \l {ScrollBar::vertical}{vertically} or + \l {ScrollBar::horizontal}{horizontally} to a Flickable, its geometry and + the following properties are automatically set and updated as appropriate: + \list + \li \l orientation + \li \l position + \li \l size + \li \l active + \endlist + + Notice that ScrollBar does not filter key events of the Flickable it is + attached to. The following example illustrates how to implement scrolling + with up and down keys: + + \code + Flickable { + focus: true + + Keys.onUpPressed: scrollBar.decrease() + Keys.onDownPressed: scrollBar.increase() + + ScrollBar.vertical: ScrollBar { id: scrollBar } + } + \endcode + + Horizontal and vertical scroll bars do not share the \l active state with + each other by default. In order to keep both bars visible whilst scrolling + to either direction, establish a two-way binding between the active states + as presented by the following example: + + \snippet qtquickcontrols-scrollbar-active.qml 1 + + \labs + + \sa ScrollIndicator, {Customizing ScrollBar}, {Indicator Controls} +*/ + +class QQuickScrollBarPrivate : public QQuickControlPrivate +{ + Q_DECLARE_PUBLIC(QQuickScrollBar) + +public: + QQuickScrollBarPrivate() : size(0), position(0), stepSize(0), offset(0), + active(false), pressed(false), moving(false), + orientation(Qt::Vertical) + { + } + + static QQuickScrollBarPrivate *get(QQuickScrollBar *bar) + { + return bar->d_func(); + } + + qreal positionAt(const QPoint &point) const; + + void resizeContent() override; + + qreal size; + qreal position; + qreal stepSize; + qreal offset; + bool active; + bool pressed; + bool moving; + Qt::Orientation orientation; +}; + +qreal QQuickScrollBarPrivate::positionAt(const QPoint &point) const +{ + Q_Q(const QQuickScrollBar); + if (orientation == Qt::Horizontal) + return (point.x() - q->leftPadding()) / q->availableWidth(); + else + return (point.y() - q->topPadding()) / q->availableHeight(); +} + +void QQuickScrollBarPrivate::resizeContent() +{ + Q_Q(QQuickScrollBar); + if (!contentItem) + return; + + if (orientation == Qt::Horizontal) { + contentItem->setPosition(QPointF(q->leftPadding() + position * q->availableWidth(), q->topPadding())); + contentItem->setSize(QSizeF(q->availableWidth() * size, q->availableHeight())); + } else { + contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding() + position * q->availableHeight())); + contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight() * size)); + } +} + +QQuickScrollBar::QQuickScrollBar(QQuickItem *parent) : + QQuickControl(*(new QQuickScrollBarPrivate), parent) +{ + setKeepMouseGrab(true); + setAcceptedMouseButtons(Qt::LeftButton); +} + +QQuickScrollBarAttached *QQuickScrollBar::qmlAttachedProperties(QObject *object) +{ + QQuickFlickable *flickable = qobject_cast(object); + if (flickable) + return new QQuickScrollBarAttached(flickable); + + qWarning() << "ScrollBar must be attached to a Flickable" << object; + return nullptr; +} + +/*! + \qmlproperty real Qt.labs.controls::ScrollBar::size + + This property holds the size of the scroll bar, scaled to \c {0.0 - 1.0}. + + \sa {Flickable::visibleArea.heightRatio}{Flickable::visibleArea} +*/ +qreal QQuickScrollBar::size() const +{ + Q_D(const QQuickScrollBar); + return d->size; +} + +void QQuickScrollBar::setSize(qreal size) +{ + Q_D(QQuickScrollBar); + size = qBound(0.0, size, 1.0 - d->position); + if (qFuzzyCompare(d->size, size)) + return; + + d->size = size; + if (isComponentComplete()) + d->resizeContent(); + emit sizeChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::ScrollBar::position + + This property holds the position of the scroll bar, scaled to \c {0.0 - 1.0}. + + \sa {Flickable::visibleArea.yPosition}{Flickable::visibleArea} +*/ +qreal QQuickScrollBar::position() const +{ + Q_D(const QQuickScrollBar); + return d->position; +} + +void QQuickScrollBar::setPosition(qreal position) +{ + Q_D(QQuickScrollBar); + position = qBound(0.0, position, 1.0 - d->size); + if (qFuzzyCompare(d->position, position)) + return; + + d->position = position; + if (isComponentComplete()) + d->resizeContent(); + emit positionChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::ScrollBar::stepSize + + This property holds the step size. The default value is \c 0.0. + + \sa increase(), decrease() +*/ +qreal QQuickScrollBar::stepSize() const +{ + Q_D(const QQuickScrollBar); + return d->stepSize; +} + +void QQuickScrollBar::setStepSize(qreal step) +{ + Q_D(QQuickScrollBar); + if (qFuzzyCompare(d->stepSize, step)) + return; + + d->stepSize = step; + emit stepSizeChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::ScrollBar::active + + This property holds whether the scroll bar is active, i.e. when it's \l pressed + or the attached Flickable is \l {Flickable::moving}{moving}. +*/ +bool QQuickScrollBar::isActive() const +{ + Q_D(const QQuickScrollBar); + return d->active; +} + +void QQuickScrollBar::setActive(bool active) +{ + Q_D(QQuickScrollBar); + if (d->active == active) + return; + + d->active = active; + emit activeChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::ScrollBar::pressed + + This property holds whether the scroll bar is pressed. +*/ +bool QQuickScrollBar::isPressed() const +{ + Q_D(const QQuickScrollBar); + return d->pressed; +} + +void QQuickScrollBar::setPressed(bool pressed) +{ + Q_D(QQuickScrollBar); + if (d->pressed == pressed) + return; + + d->pressed = pressed; + setAccessibleProperty("pressed", pressed); + setActive(d->pressed || d->moving); + emit pressedChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::ScrollBar::orientation + + This property holds the orientation of the scroll bar. + + Possible values: + \value Qt.Horizontal Horizontal + \value Qt.Vertical Vertical (default) +*/ +Qt::Orientation QQuickScrollBar::orientation() const +{ + Q_D(const QQuickScrollBar); + return d->orientation; +} + +void QQuickScrollBar::setOrientation(Qt::Orientation orientation) +{ + Q_D(QQuickScrollBar); + if (d->orientation == orientation) + return; + + d->orientation = orientation; + if (isComponentComplete()) + d->resizeContent(); + emit orientationChanged(); +} + +/*! + \qmlmethod void Qt.labs.controls::ScrollBar::increase() + + Increases the position by \l stepSize or \c 0.1 if stepSize is \c 0.0. + + \sa stepSize +*/ +void QQuickScrollBar::increase() +{ + Q_D(QQuickScrollBar); + qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize; + setActive(true); + setPosition(d->position + step); + setActive(false); +} + +/*! + \qmlmethod void Qt.labs.controls::ScrollBar::decrease() + + Decreases the position by \l stepSize or \c 0.1 if stepSize is \c 0.0. + + \sa stepSize +*/ +void QQuickScrollBar::decrease() +{ + Q_D(QQuickScrollBar); + qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize; + setActive(true); + setPosition(d->position - step); + setActive(false); +} + +void QQuickScrollBar::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickScrollBar); + QQuickControl::mousePressEvent(event); + d->offset = d->positionAt(event->pos()) - d->position; + if (d->offset < 0 || d->offset > d->size) + d->offset = d->size / 2; + setPressed(true); +} + +void QQuickScrollBar::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickScrollBar); + QQuickControl::mouseMoveEvent(event); + setPosition(qBound(0.0, d->positionAt(event->pos()) - d->offset, 1.0 - d->size)); +} + +void QQuickScrollBar::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickScrollBar); + QQuickControl::mouseReleaseEvent(event); + setPosition(qBound(0.0, d->positionAt(event->pos()) - d->offset, 1.0 - d->size)); + d->offset = 0.0; + setPressed(false); +} + +#ifndef QT_NO_ACCESSIBILITY +void QQuickScrollBar::accessibilityActiveChanged(bool active) +{ + QQuickControl::accessibilityActiveChanged(active); + + Q_D(QQuickScrollBar); + if (active) + setAccessibleProperty("pressed", d->pressed); +} + +QAccessible::Role QQuickScrollBar::accessibleRole() const +{ + return QAccessible::ScrollBar; +} +#endif + +class QQuickScrollBarAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener +{ +public: + QQuickScrollBarAttachedPrivate(QQuickFlickable *flickable) : flickable(flickable), horizontal(nullptr), vertical(nullptr) { } + + void activateHorizontal(); + void activateVertical(); + void scrollHorizontal(); + void scrollVertical(); + + void layoutHorizontal(bool move = true); + void layoutVertical(bool move = true); + + void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override; + + QQuickFlickable *flickable; + QQuickScrollBar *horizontal; + QQuickScrollBar *vertical; +}; + +void QQuickScrollBarAttachedPrivate::activateHorizontal() +{ + QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(horizontal); + p->moving = flickable->isMovingHorizontally(); + horizontal->setActive(p->moving || p->pressed); +} + +void QQuickScrollBarAttachedPrivate::activateVertical() +{ + QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(vertical); + p->moving = flickable->isMovingVertically(); + vertical->setActive(p->moving || p->pressed); +} + +// TODO: QQuickFlickable::maxXYExtent() +class QQuickFriendlyFlickable : public QQuickFlickable +{ + friend class QQuickScrollBarAttachedPrivate; +}; + +void QQuickScrollBarAttachedPrivate::scrollHorizontal() +{ + QQuickFriendlyFlickable *f = reinterpret_cast(flickable); + + const qreal viewwidth = f->width(); + const qreal maxxextent = -f->maxXExtent() + f->minXExtent(); + qreal cx = horizontal->position() * (maxxextent + viewwidth) - f->minXExtent(); + if (!qIsNaN(cx) && !qFuzzyCompare(cx, flickable->contentX())) + flickable->setContentX(cx); +} + +void QQuickScrollBarAttachedPrivate::scrollVertical() +{ + QQuickFriendlyFlickable *f = reinterpret_cast(flickable); + + const qreal viewheight = f->height(); + const qreal maxyextent = -f->maxYExtent() + f->minYExtent(); + qreal cy = vertical->position() * (maxyextent + viewheight) - f->minYExtent(); + if (!qIsNaN(cy) && !qFuzzyCompare(cy, flickable->contentY())) + flickable->setContentY(cy); +} + +void QQuickScrollBarAttachedPrivate::layoutHorizontal(bool move) +{ + Q_ASSERT(horizontal && flickable); + horizontal->setWidth(flickable->width()); + if (move) + horizontal->setY(flickable->height() - horizontal->height()); +} + +void QQuickScrollBarAttachedPrivate::layoutVertical(bool move) +{ + Q_ASSERT(vertical && flickable); + vertical->setHeight(flickable->height()); + if (move && !QQuickItemPrivate::get(vertical)->isMirrored()) + vertical->setX(flickable->width() - vertical->width()); +} + +void QQuickScrollBarAttachedPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_UNUSED(item); + Q_UNUSED(newGeometry); + if (horizontal && horizontal->height() > 0) { + bool move = qFuzzyIsNull(horizontal->y()) || qFuzzyCompare(horizontal->y(), oldGeometry.height() - horizontal->height()); + layoutHorizontal(move); + } + if (vertical && vertical->width() > 0) { + bool move = qFuzzyIsNull(vertical->x()) || qFuzzyCompare(vertical->x(), oldGeometry.width() - vertical->width()); + layoutVertical(move); + } +} + +QQuickScrollBarAttached::QQuickScrollBarAttached(QQuickFlickable *flickable) : + QObject(*(new QQuickScrollBarAttachedPrivate(flickable)), flickable) +{ + Q_D(QQuickScrollBarAttached); + QQuickItemPrivate *p = QQuickItemPrivate::get(flickable); + p->updateOrAddGeometryChangeListener(d, QQuickItemPrivate::SizeChange); +} + +QQuickScrollBarAttached::~QQuickScrollBarAttached() +{ + Q_D(QQuickScrollBarAttached); + if (d->horizontal) + QQuickItemPrivate::get(d->horizontal)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); + if (d->vertical) + QQuickItemPrivate::get(d->vertical)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); +} + +/*! + \qmlattachedproperty ScrollBar Qt.labs.controls::ScrollBar::horizontal + + This property attaches a horizontal scroll bar to a \l Flickable. + + \code + Flickable { + contentWidth: 2000 + ScrollBar.horizontal: ScrollBar { } + } + \endcode +*/ +QQuickScrollBar *QQuickScrollBarAttached::horizontal() const +{ + Q_D(const QQuickScrollBarAttached); + return d->horizontal; +} + +void QQuickScrollBarAttached::setHorizontal(QQuickScrollBar *horizontal) +{ + Q_D(QQuickScrollBarAttached); + if (d->horizontal == horizontal) + return; + + if (d->horizontal) { + QQuickItemPrivate::get(d->horizontal)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); + QObjectPrivate::disconnect(d->horizontal, &QQuickScrollBar::positionChanged, d, &QQuickScrollBarAttachedPrivate::scrollHorizontal); + QObjectPrivate::disconnect(d->flickable, &QQuickFlickable::movingHorizontallyChanged, d, &QQuickScrollBarAttachedPrivate::activateHorizontal); + + // TODO: export QQuickFlickableVisibleArea + QObject *area = d->flickable->property("visibleArea").value(); + disconnect(area, SIGNAL(widthRatioChanged(qreal)), d->horizontal, SLOT(setSize(qreal))); + disconnect(area, SIGNAL(xPositionChanged(qreal)), d->horizontal, SLOT(setPosition(qreal))); + } + + d->horizontal = horizontal; + + if (horizontal) { + if (!horizontal->parentItem()) + horizontal->setParentItem(d->flickable); + horizontal->setOrientation(Qt::Horizontal); + + QQuickItemPrivate::get(horizontal)->updateOrAddGeometryChangeListener(d, QQuickItemPrivate::SizeChange); + QObjectPrivate::connect(horizontal, &QQuickScrollBar::positionChanged, d, &QQuickScrollBarAttachedPrivate::scrollHorizontal); + QObjectPrivate::connect(d->flickable, &QQuickFlickable::movingHorizontallyChanged, d, &QQuickScrollBarAttachedPrivate::activateHorizontal); + + // TODO: export QQuickFlickableVisibleArea + QObject *area = d->flickable->property("visibleArea").value(); + connect(area, SIGNAL(widthRatioChanged(qreal)), horizontal, SLOT(setSize(qreal))); + connect(area, SIGNAL(xPositionChanged(qreal)), horizontal, SLOT(setPosition(qreal))); + + d->layoutHorizontal(); + horizontal->setSize(area->property("widthRatio").toReal()); + horizontal->setPosition(area->property("xPosition").toReal()); + } + emit horizontalChanged(); +} + +/*! + \qmlattachedproperty ScrollBar Qt.labs.controls::ScrollBar::vertical + + This property attaches a vertical scroll bar to a \l Flickable. + + \code + Flickable { + contentHeight: 2000 + ScrollBar.vertical: ScrollBar { } + } + \endcode +*/ +QQuickScrollBar *QQuickScrollBarAttached::vertical() const +{ + Q_D(const QQuickScrollBarAttached); + return d->vertical; +} + +void QQuickScrollBarAttached::setVertical(QQuickScrollBar *vertical) +{ + Q_D(QQuickScrollBarAttached); + if (d->vertical == vertical) + return; + + if (d->vertical) { + QQuickItemPrivate::get(d->vertical)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); + QObjectPrivate::disconnect(d->vertical, &QQuickScrollBar::positionChanged, d, &QQuickScrollBarAttachedPrivate::scrollVertical); + QObjectPrivate::disconnect(d->flickable, &QQuickFlickable::movingVerticallyChanged, d, &QQuickScrollBarAttachedPrivate::activateVertical); + + // TODO: export QQuickFlickableVisibleArea + QObject *area = d->flickable->property("visibleArea").value(); + disconnect(area, SIGNAL(heightRatioChanged(qreal)), d->vertical, SLOT(setSize(qreal))); + disconnect(area, SIGNAL(yPositionChanged(qreal)), d->vertical, SLOT(setPosition(qreal))); + } + + d->vertical = vertical; + + if (vertical) { + if (!vertical->parentItem()) + vertical->setParentItem(d->flickable); + vertical->setOrientation(Qt::Vertical); + + QQuickItemPrivate::get(vertical)->updateOrAddGeometryChangeListener(d, QQuickItemPrivate::SizeChange); + QObjectPrivate::connect(vertical, &QQuickScrollBar::positionChanged, d, &QQuickScrollBarAttachedPrivate::scrollVertical); + QObjectPrivate::connect(d->flickable, &QQuickFlickable::movingVerticallyChanged, d, &QQuickScrollBarAttachedPrivate::activateVertical); + + // TODO: export QQuickFlickableVisibleArea + QObject *area = d->flickable->property("visibleArea").value(); + connect(area, SIGNAL(heightRatioChanged(qreal)), vertical, SLOT(setSize(qreal))); + connect(area, SIGNAL(yPositionChanged(qreal)), vertical, SLOT(setPosition(qreal))); + + d->layoutVertical(); + vertical->setSize(area->property("heightRatio").toReal()); + vertical->setPosition(area->property("yPosition").toReal()); + } + emit verticalChanged(); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickscrollbar_p.h b/src/quicktemplates2/qquickscrollbar_p.h new file mode 100644 index 00000000..0a86ac95 --- /dev/null +++ b/src/quicktemplates2/qquickscrollbar_p.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSCROLLBAR_P_H +#define QQUICKSCROLLBAR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickFlickable; +class QQuickScrollBarAttached; +class QQuickScrollBarPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickScrollBar : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(qreal size READ size WRITE setSize NOTIFY sizeChanged FINAL) + Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL) + Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL) + Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged FINAL) + Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL) + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL) + +public: + explicit QQuickScrollBar(QQuickItem *parent = nullptr); + + static QQuickScrollBarAttached *qmlAttachedProperties(QObject *object); + + qreal size() const; + qreal position() const; + + qreal stepSize() const; + void setStepSize(qreal step); + + bool isActive() const; + void setActive(bool active); + + bool isPressed() const; + void setPressed(bool pressed); + + Qt::Orientation orientation() const; + void setOrientation(Qt::Orientation orientation); + +public Q_SLOTS: + void increase(); + void decrease(); + void setSize(qreal size); + void setPosition(qreal position); + +Q_SIGNALS: + void sizeChanged(); + void positionChanged(); + void stepSizeChanged(); + void activeChanged(); + void pressedChanged(); + void orientationChanged(); + +protected: + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + +#ifndef QT_NO_ACCESSIBILITY + void accessibilityActiveChanged(bool active) override; + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickScrollBar) + Q_DECLARE_PRIVATE(QQuickScrollBar) +}; + +class QQuickScrollBarAttachedPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickScrollBarAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQuickScrollBar *horizontal READ horizontal WRITE setHorizontal NOTIFY horizontalChanged FINAL) + Q_PROPERTY(QQuickScrollBar *vertical READ vertical WRITE setVertical NOTIFY verticalChanged FINAL) + +public: + explicit QQuickScrollBarAttached(QQuickFlickable *flickable); + ~QQuickScrollBarAttached(); + + QQuickScrollBar *horizontal() const; + void setHorizontal(QQuickScrollBar *horizontal); + + QQuickScrollBar *vertical() const; + void setVertical(QQuickScrollBar *vertical); + +Q_SIGNALS: + void horizontalChanged(); + void verticalChanged(); + +private: + Q_DISABLE_COPY(QQuickScrollBarAttached) + Q_DECLARE_PRIVATE(QQuickScrollBarAttached) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickScrollBar) +QML_DECLARE_TYPEINFO(QQuickScrollBar, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QQUICKSCROLLBAR_P_H diff --git a/src/quicktemplates2/qquickscrollindicator.cpp b/src/quicktemplates2/qquickscrollindicator.cpp new file mode 100644 index 00000000..619c9b4b --- /dev/null +++ b/src/quicktemplates2/qquickscrollindicator.cpp @@ -0,0 +1,429 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickscrollindicator_p.h" +#include "qquickcontrol_p_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ScrollIndicator + \inherits Control + \instantiates QQuickScrollIndicator + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-indicators + \brief A non-interactive scroll indicator control. + + ScrollIndicator is a non-interactive indicator that indicates the current scroll + position. A scroll indicator can be either \l vertical or \l horizontal, and can + be attached to any \l Flickable, such as \l ListView and \l GridView. + + \image qtquickcontrols-scrollindicator.png + + \code + Flickable { + // ... + ScrollIndicator.vertical: ScrollIndicator { } + } + \endcode + + \note When ScrollIndicator is attached \l {ScrollIndicator::vertical}{vertically} + or \l {ScrollIndicator::horizontal}{horizontally} to a Flickable, its geometry and + the following properties are automatically set and updated as appropriate: + \list + \li \l orientation + \li \l position + \li \l size + \li \l active + \endlist + + Horizontal and vertical scroll indicators do not share the \l active state with + each other by default. In order to keep both indicators visible whilst scrolling + to either direction, establish a two-way binding between the active states as + presented by the following example: + + \snippet qtquickcontrols-scrollindicator-active.qml 1 + + \labs + + \sa ScrollBar, {Customizing ScrollIndicator}, {Indicator Controls} +*/ + +class QQuickScrollIndicatorPrivate : public QQuickControlPrivate +{ + Q_DECLARE_PUBLIC(QQuickScrollIndicator) + +public: + QQuickScrollIndicatorPrivate() : size(0), position(0), + active(false), orientation(Qt::Vertical) + { + } + + void resizeContent() override; + + qreal size; + qreal position; + bool active; + Qt::Orientation orientation; +}; + +void QQuickScrollIndicatorPrivate::resizeContent() +{ + Q_Q(QQuickScrollIndicator); + if (!contentItem) + return; + + if (orientation == Qt::Horizontal) { + contentItem->setPosition(QPointF(q->leftPadding() + position * q->availableWidth(), q->topPadding())); + contentItem->setSize(QSizeF(q->availableWidth() * size, q->availableHeight())); + } else { + contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding() + position * q->availableHeight())); + contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight() * size)); + } +} + +QQuickScrollIndicator::QQuickScrollIndicator(QQuickItem *parent) : + QQuickControl(*(new QQuickScrollIndicatorPrivate), parent) +{ +} + +QQuickScrollIndicatorAttached *QQuickScrollIndicator::qmlAttachedProperties(QObject *object) +{ + QQuickFlickable *flickable = qobject_cast(object); + if (flickable) + return new QQuickScrollIndicatorAttached(flickable); + + qWarning() << "ScrollIndicator must be attached to a Flickable" << object; + return nullptr; +} + +/*! + \qmlproperty real Qt.labs.controls::ScrollIndicator::size + + This property holds the size of the indicator, scaled to \c {0.0 - 1.0}. + + \sa {Flickable::visibleArea.heightRatio}{Flickable::visibleArea} +*/ +qreal QQuickScrollIndicator::size() const +{ + Q_D(const QQuickScrollIndicator); + return d->size; +} + +void QQuickScrollIndicator::setSize(qreal size) +{ + Q_D(QQuickScrollIndicator); + if (qFuzzyCompare(d->size, size)) + return; + + d->size = size; + if (isComponentComplete()) + d->resizeContent(); + emit sizeChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::ScrollIndicator::position + + This property holds the position of the indicator, scaled to \c {0.0 - 1.0}. + + \sa {Flickable::visibleArea.yPosition}{Flickable::visibleArea} +*/ +qreal QQuickScrollIndicator::position() const +{ + Q_D(const QQuickScrollIndicator); + return d->position; +} + +void QQuickScrollIndicator::setPosition(qreal position) +{ + Q_D(QQuickScrollIndicator); + if (qFuzzyCompare(d->position, position)) + return; + + d->position = position; + if (isComponentComplete()) + d->resizeContent(); + emit positionChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::ScrollIndicator::active + + This property holds whether the indicator is active, that is, when the + attached Flickable is \l {Flickable::moving}{moving}. +*/ +bool QQuickScrollIndicator::isActive() const +{ + Q_D(const QQuickScrollIndicator); + return d->active; +} + +void QQuickScrollIndicator::setActive(bool active) +{ + Q_D(QQuickScrollIndicator); + if (d->active == active) + return; + + d->active = active; + emit activeChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::ScrollIndicator::orientation + + This property holds the orientation of the indicator. + + Possible values: + \value Qt.Horizontal Horizontal + \value Qt.Vertical Vertical (default) +*/ +Qt::Orientation QQuickScrollIndicator::orientation() const +{ + Q_D(const QQuickScrollIndicator); + return d->orientation; +} + +void QQuickScrollIndicator::setOrientation(Qt::Orientation orientation) +{ + Q_D(QQuickScrollIndicator); + if (d->orientation == orientation) + return; + + d->orientation = orientation; + if (isComponentComplete()) + d->resizeContent(); + emit orientationChanged(); +} + +class QQuickScrollIndicatorAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener +{ +public: + QQuickScrollIndicatorAttachedPrivate(QQuickFlickable *flickable) : flickable(flickable), horizontal(nullptr), vertical(nullptr) { } + + void activateHorizontal(); + void activateVertical(); + + void layoutHorizontal(bool move = true); + void layoutVertical(bool move = true); + + void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override; + + QQuickFlickable *flickable; + QQuickScrollIndicator *horizontal; + QQuickScrollIndicator *vertical; +}; + +void QQuickScrollIndicatorAttachedPrivate::activateHorizontal() +{ + horizontal->setActive(flickable->isMovingHorizontally()); +} + +void QQuickScrollIndicatorAttachedPrivate::activateVertical() +{ + vertical->setActive(flickable->isMovingVertically()); +} + +void QQuickScrollIndicatorAttachedPrivate::layoutHorizontal(bool move) +{ + Q_ASSERT(horizontal && flickable); + horizontal->setWidth(flickable->width()); + if (move) + horizontal->setY(flickable->height() - horizontal->height()); +} + +void QQuickScrollIndicatorAttachedPrivate::layoutVertical(bool move) +{ + Q_ASSERT(vertical && flickable); + vertical->setHeight(flickable->height()); + if (move && !QQuickItemPrivate::get(vertical)->isMirrored()) + vertical->setX(flickable->width() - vertical->width()); +} + +void QQuickScrollIndicatorAttachedPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_UNUSED(item); + Q_UNUSED(newGeometry); + if (horizontal && horizontal->height() > 0) { + bool move = qFuzzyIsNull(horizontal->y()) || qFuzzyCompare(horizontal->y(), oldGeometry.height() - horizontal->height()); + layoutHorizontal(move); + } + if (vertical && vertical->width() > 0) { + bool move = qFuzzyIsNull(vertical->x()) || qFuzzyCompare(vertical->x(), oldGeometry.width() - vertical->width()); + layoutVertical(move); + } +} + +QQuickScrollIndicatorAttached::QQuickScrollIndicatorAttached(QQuickFlickable *flickable) : + QObject(*(new QQuickScrollIndicatorAttachedPrivate(flickable)), flickable) +{ + Q_D(QQuickScrollIndicatorAttached); + QQuickItemPrivate *p = QQuickItemPrivate::get(flickable); + p->updateOrAddGeometryChangeListener(d, QQuickItemPrivate::SizeChange); +} + +QQuickScrollIndicatorAttached::~QQuickScrollIndicatorAttached() +{ + Q_D(QQuickScrollIndicatorAttached); + if (d->horizontal) + QQuickItemPrivate::get(d->horizontal)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); + if (d->vertical) + QQuickItemPrivate::get(d->vertical)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); +} + +/*! + \qmlattachedproperty ScrollIndicator Qt.labs.controls::ScrollIndicator::horizontal + + This property attaches a horizontal scroll indicator to a \l Flickable. + + \code + Flickable { + contentWidth: 2000 + ScrollIndicator.horizontal: ScrollIndicator { } + } + \endcode +*/ +QQuickScrollIndicator *QQuickScrollIndicatorAttached::horizontal() const +{ + Q_D(const QQuickScrollIndicatorAttached); + return d->horizontal; +} + +void QQuickScrollIndicatorAttached::setHorizontal(QQuickScrollIndicator *horizontal) +{ + Q_D(QQuickScrollIndicatorAttached); + if (d->horizontal == horizontal) + return; + + if (d->horizontal) { + QQuickItemPrivate::get(d->horizontal)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); + QObjectPrivate::disconnect(d->flickable, &QQuickFlickable::movingHorizontallyChanged, d, &QQuickScrollIndicatorAttachedPrivate::activateHorizontal); + + // TODO: export QQuickFlickableVisibleArea + QObject *area = d->flickable->property("visibleArea").value(); + disconnect(area, SIGNAL(widthRatioChanged(qreal)), d->horizontal, SLOT(setSize(qreal))); + disconnect(area, SIGNAL(xPositionChanged(qreal)), d->horizontal, SLOT(setPosition(qreal))); + } + + d->horizontal = horizontal; + + if (horizontal) { + if (!horizontal->parentItem()) + horizontal->setParentItem(d->flickable); + horizontal->setOrientation(Qt::Horizontal); + + QQuickItemPrivate::get(horizontal)->updateOrAddGeometryChangeListener(d, QQuickItemPrivate::SizeChange); + QObjectPrivate::connect(d->flickable, &QQuickFlickable::movingHorizontallyChanged, d, &QQuickScrollIndicatorAttachedPrivate::activateHorizontal); + + // TODO: export QQuickFlickableVisibleArea + QObject *area = d->flickable->property("visibleArea").value(); + connect(area, SIGNAL(widthRatioChanged(qreal)), horizontal, SLOT(setSize(qreal))); + connect(area, SIGNAL(xPositionChanged(qreal)), horizontal, SLOT(setPosition(qreal))); + + d->layoutHorizontal(); + horizontal->setSize(area->property("widthRatio").toReal()); + horizontal->setPosition(area->property("xPosition").toReal()); + } + emit horizontalChanged(); +} + +/*! + \qmlattachedproperty ScrollIndicator Qt.labs.controls::ScrollIndicator::vertical + + This property attaches a vertical scroll indicator to a \l Flickable. + + \code + Flickable { + contentHeight: 2000 + ScrollIndicator.vertical: ScrollIndicator { } + } + \endcode +*/ +QQuickScrollIndicator *QQuickScrollIndicatorAttached::vertical() const +{ + Q_D(const QQuickScrollIndicatorAttached); + return d->vertical; +} + +void QQuickScrollIndicatorAttached::setVertical(QQuickScrollIndicator *vertical) +{ + Q_D(QQuickScrollIndicatorAttached); + if (d->vertical == vertical) + return; + + if (d->vertical) { + QQuickItemPrivate::get(d->vertical)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); + QObjectPrivate::disconnect(d->flickable, &QQuickFlickable::movingVerticallyChanged, d, &QQuickScrollIndicatorAttachedPrivate::activateVertical); + + // TODO: export QQuickFlickableVisibleArea + QObject *area = d->flickable->property("visibleArea").value(); + disconnect(area, SIGNAL(heightRatioChanged(qreal)), d->vertical, SLOT(setSize(qreal))); + disconnect(area, SIGNAL(yPositionChanged(qreal)), d->vertical, SLOT(setPosition(qreal))); + } + + d->vertical = vertical; + + if (vertical) { + if (!vertical->parentItem()) + vertical->setParentItem(d->flickable); + vertical->setOrientation(Qt::Vertical); + + QQuickItemPrivate::get(vertical)->updateOrAddGeometryChangeListener(d, QQuickItemPrivate::SizeChange); + QObjectPrivate::connect(d->flickable, &QQuickFlickable::movingVerticallyChanged, d, &QQuickScrollIndicatorAttachedPrivate::activateVertical); + + // TODO: export QQuickFlickableVisibleArea + QObject *area = d->flickable->property("visibleArea").value(); + connect(area, SIGNAL(heightRatioChanged(qreal)), vertical, SLOT(setSize(qreal))); + connect(area, SIGNAL(yPositionChanged(qreal)), vertical, SLOT(setPosition(qreal))); + + d->layoutVertical(); + vertical->setSize(area->property("heightRatio").toReal()); + vertical->setPosition(area->property("yPosition").toReal()); + } + emit verticalChanged(); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickScrollIndicator::accessibleRole() const +{ + return QAccessible::Indicator; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickscrollindicator_p.h b/src/quicktemplates2/qquickscrollindicator_p.h new file mode 100644 index 00000000..1af57929 --- /dev/null +++ b/src/quicktemplates2/qquickscrollindicator_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSCROLLINDICATOR_P_H +#define QQUICKSCROLLINDICATOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickFlickable; +class QQuickScrollIndicatorAttached; +class QQuickScrollIndicatorPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickScrollIndicator : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(qreal size READ size WRITE setSize NOTIFY sizeChanged FINAL) + Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL) + Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged FINAL) + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL) + +public: + explicit QQuickScrollIndicator(QQuickItem *parent = nullptr); + + static QQuickScrollIndicatorAttached *qmlAttachedProperties(QObject *object); + + qreal size() const; + qreal position() const; + + bool isActive() const; + void setActive(bool active); + + Qt::Orientation orientation() const; + void setOrientation(Qt::Orientation orientation); + +public Q_SLOTS: + void setSize(qreal size); + void setPosition(qreal position); + +Q_SIGNALS: + void sizeChanged(); + void positionChanged(); + void activeChanged(); + void orientationChanged(); + +protected: +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickScrollIndicator) + Q_DECLARE_PRIVATE(QQuickScrollIndicator) +}; + +class QQuickScrollIndicatorAttachedPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickScrollIndicatorAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQuickScrollIndicator *horizontal READ horizontal WRITE setHorizontal NOTIFY horizontalChanged FINAL) + Q_PROPERTY(QQuickScrollIndicator *vertical READ vertical WRITE setVertical NOTIFY verticalChanged FINAL) + +public: + explicit QQuickScrollIndicatorAttached(QQuickFlickable *flickable); + ~QQuickScrollIndicatorAttached(); + + QQuickScrollIndicator *horizontal() const; + void setHorizontal(QQuickScrollIndicator *horizontal); + + QQuickScrollIndicator *vertical() const; + void setVertical(QQuickScrollIndicator *vertical); + +Q_SIGNALS: + void horizontalChanged(); + void verticalChanged(); + +private: + Q_DISABLE_COPY(QQuickScrollIndicatorAttached) + Q_DECLARE_PRIVATE(QQuickScrollIndicatorAttached) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickScrollIndicator) +QML_DECLARE_TYPEINFO(QQuickScrollIndicator, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QQUICKSCROLLINDICATOR_P_H diff --git a/src/quicktemplates2/qquickslider.cpp b/src/quicktemplates2/qquickslider.cpp new file mode 100644 index 00000000..16be7677 --- /dev/null +++ b/src/quicktemplates2/qquickslider.cpp @@ -0,0 +1,585 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickslider_p.h" +#include "qquickcontrol_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Slider + \inherits Control + \instantiates QQuickSlider + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-input + \brief Selects a value by sliding a handle along a track. + + \image qtquickcontrols-slider.gif + + Slider is used to select a value by sliding a handle along a track. + + \table + \row \li \image qtquickcontrols-slider-normal.png + \li A slider in its normal state. + \row \li \image qtquickcontrols-slider-focused.png + \li A slider that has active focus. + \row \li \image qtquickcontrols-slider-disabled.png + \li A slider that is disabled. + \endtable + + \code + Slider { + value: 0.5 + } + \endcode + + \labs + + \sa {Customizing Slider}, {Input Controls} +*/ + +class QQuickSliderPrivate : public QQuickControlPrivate +{ + Q_DECLARE_PUBLIC(QQuickSlider) + +public: + QQuickSliderPrivate() : from(0), to(1), value(0), position(0), stepSize(0), pressed(false), + orientation(Qt::Horizontal), snapMode(QQuickSlider::NoSnap), + handle(nullptr) + { + } + + qreal valueAt(qreal position) const; + qreal snapPosition(qreal position) const; + qreal positionAt(const QPoint &point) const; + void setPosition(qreal position); + void updatePosition(); + + qreal from; + qreal to; + qreal value; + qreal position; + qreal stepSize; + bool pressed; + QPoint pressPoint; + Qt::Orientation orientation; + QQuickSlider::SnapMode snapMode; + QQuickItem *handle; +}; + +qreal QQuickSliderPrivate::valueAt(qreal position) const +{ + return from + (to - from) * position; +} + +qreal QQuickSliderPrivate::snapPosition(qreal position) const +{ + const qreal range = from + (to - from); + if (qFuzzyIsNull(range)) + return position; + + const qreal effectiveStep = stepSize / range; + if (qFuzzyIsNull(effectiveStep)) + return position; + + return qRound(position / effectiveStep) * effectiveStep; +} + +qreal QQuickSliderPrivate::positionAt(const QPoint &point) const +{ + Q_Q(const QQuickSlider); + if (orientation == Qt::Horizontal) { + const qreal hw = handle ? handle->width() : 0; + const qreal offset = hw / 2; + const qreal extent = q->availableWidth() - hw; + if (!qFuzzyIsNull(extent)) { + if (q->isMirrored()) + return (q->width() - point.x() - q->rightPadding() - offset) / extent; + return (point.x() - q->leftPadding() - offset) / extent; + } + } else { + const qreal hh = handle ? handle->height() : 0; + const qreal offset = hh / 2; + const qreal extent = q->availableHeight() - hh; + if (!qFuzzyIsNull(extent)) + return (q->height() - point.y() - q->bottomPadding() - offset) / extent; + } + return 0; +} + +void QQuickSliderPrivate::setPosition(qreal pos) +{ + Q_Q(QQuickSlider); + pos = qBound(0.0, pos, 1.0); + if (qFuzzyCompare(position, pos)) + return; + + position = pos; + emit q->positionChanged(); + emit q->visualPositionChanged(); +} + +void QQuickSliderPrivate::updatePosition() +{ + qreal pos = 0; + if (!qFuzzyCompare(from, to)) + pos = (value - from) / (to - from); + setPosition(pos); +} + +QQuickSlider::QQuickSlider(QQuickItem *parent) : + QQuickControl(*(new QQuickSliderPrivate), parent) +{ + setActiveFocusOnTab(true); + setAcceptedMouseButtons(Qt::LeftButton); +} + +/*! + \qmlproperty real Qt.labs.controls::Slider::from + + This property holds the starting value for the range. The default value is \c 0.0. + + \sa to, value +*/ +qreal QQuickSlider::from() const +{ + Q_D(const QQuickSlider); + return d->from; +} + +void QQuickSlider::setFrom(qreal from) +{ + Q_D(QQuickSlider); + if (qFuzzyCompare(d->from, from)) + return; + + d->from = from; + emit fromChanged(); + if (isComponentComplete()) { + setValue(d->value); + d->updatePosition(); + } +} + +/*! + \qmlproperty real Qt.labs.controls::Slider::to + + This property holds the end value for the range. The default value is \c 1.0. + + \sa from, value +*/ +qreal QQuickSlider::to() const +{ + Q_D(const QQuickSlider); + return d->to; +} + +void QQuickSlider::setTo(qreal to) +{ + Q_D(QQuickSlider); + if (qFuzzyCompare(d->to, to)) + return; + + d->to = to; + emit toChanged(); + if (isComponentComplete()) { + setValue(d->value); + d->updatePosition(); + } +} + +/*! + \qmlproperty real Qt.labs.controls::Slider::value + + This property holds the value in the range \c from - \c to. The default value is \c 0.0. + + Unlike the \l position property, the \c value is not updated while the + handle is dragged. The value is updated after the value has been chosen + and the slider has been released. + + \sa position +*/ +qreal QQuickSlider::value() const +{ + Q_D(const QQuickSlider); + return d->value; +} + +void QQuickSlider::setValue(qreal value) +{ + Q_D(QQuickSlider); + if (isComponentComplete()) + value = d->from > d->to ? qBound(d->to, value, d->from) : qBound(d->from, value, d->to); + + if (qFuzzyCompare(d->value, value)) + return; + + d->value = value; + d->updatePosition(); + emit valueChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::Slider::position + \readonly + + This property holds the logical position of the handle. + + The position is defined as a percentage of the control's size, scaled + to \c {0.0 - 1.0}. Unlike the \l value property, the \c position is + continuously updated while the handle is dragged. For visualizing a + slider, the right-to-left aware \l visualPosition should be used instead. + + \sa value, visualPosition +*/ +qreal QQuickSlider::position() const +{ + Q_D(const QQuickSlider); + return d->position; +} + +/*! + \qmlproperty real Qt.labs.controls::Slider::visualPosition + \readonly + + This property holds the visual position of the handle. + + The position is defined as a percentage of the control's size, scaled to + \c {0.0 - 1.0}. When the control is \l {Control::mirrored}{mirrored}, the + value is equal to \c {1.0 - position}. This makes the value suitable for + visualizing the slider, taking right-to-left support into account. + + \sa position +*/ +qreal QQuickSlider::visualPosition() const +{ + Q_D(const QQuickSlider); + if (d->orientation == Qt::Vertical || isMirrored()) + return 1.0 - d->position; + return d->position; +} + +/*! + \qmlproperty real Qt.labs.controls::Slider::stepSize + + This property holds the step size. The default value is \c 0.0. + + \sa snapMode, increase(), decrease() +*/ +qreal QQuickSlider::stepSize() const +{ + Q_D(const QQuickSlider); + return d->stepSize; +} + +void QQuickSlider::setStepSize(qreal step) +{ + Q_D(QQuickSlider); + if (qFuzzyCompare(d->stepSize, step)) + return; + + d->stepSize = step; + emit stepSizeChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::Slider::snapMode + + This property holds the snap mode. + + Possible values: + \value Slider.NoSnap The slider does not snap (default). + \value Slider.SnapAlways The slider snaps while the handle is dragged. + \value Slider.SnapOnRelease The slider does not snap while being dragged, but only after the handle is released. + + \sa stepSize +*/ +QQuickSlider::SnapMode QQuickSlider::snapMode() const +{ + Q_D(const QQuickSlider); + return d->snapMode; +} + +void QQuickSlider::setSnapMode(SnapMode mode) +{ + Q_D(QQuickSlider); + if (d->snapMode == mode) + return; + + d->snapMode = mode; + emit snapModeChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::Slider::pressed + + This property holds whether the slider is pressed. +*/ +bool QQuickSlider::isPressed() const +{ + Q_D(const QQuickSlider); + return d->pressed; +} + +void QQuickSlider::setPressed(bool pressed) +{ + Q_D(QQuickSlider); + if (d->pressed == pressed) + return; + + d->pressed = pressed; + setAccessibleProperty("pressed", pressed); + emit pressedChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::Slider::orientation + + This property holds the orientation. + + Possible values: + \value Qt.Horizontal Horizontal (default) + \value Qt.Vertical Vertical +*/ +Qt::Orientation QQuickSlider::orientation() const +{ + Q_D(const QQuickSlider); + return d->orientation; +} + +void QQuickSlider::setOrientation(Qt::Orientation orientation) +{ + Q_D(QQuickSlider); + if (d->orientation == orientation) + return; + + d->orientation = orientation; + emit orientationChanged(); +} + +/*! + \qmlproperty Item Qt.labs.controls::Slider::handle + + This property holds the handle item. + + \sa {Customizing Slider} +*/ +QQuickItem *QQuickSlider::handle() const +{ + Q_D(const QQuickSlider); + return d->handle; +} + +void QQuickSlider::setHandle(QQuickItem *handle) +{ + Q_D(QQuickSlider); + if (d->handle == handle) + return; + + delete d->handle; + d->handle = handle; + if (handle && !handle->parentItem()) + handle->setParentItem(this); + emit handleChanged(); +} + +/*! + \qmlmethod void Qt.labs.controls::Slider::increase() + + Increases the value by \l stepSize or \c 0.1 if stepSize is not defined. + + \sa stepSize +*/ +void QQuickSlider::increase() +{ + Q_D(QQuickSlider); + qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize; + setValue(d->value + step); +} + +/*! + \qmlmethod void Qt.labs.controls::Slider::decrease() + + Decreases the value by \l stepSize or \c 0.1 if stepSize is not defined. + + \sa stepSize +*/ +void QQuickSlider::decrease() +{ + Q_D(QQuickSlider); + qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize; + setValue(d->value - step); +} + +void QQuickSlider::keyPressEvent(QKeyEvent *event) +{ + Q_D(QQuickSlider); + QQuickControl::keyPressEvent(event); + if (d->orientation == Qt::Horizontal) { + if (event->key() == Qt::Key_Left) { + setPressed(true); + if (isMirrored()) + increase(); + else + decrease(); + event->accept(); + } else if (event->key() == Qt::Key_Right) { + setPressed(true); + if (isMirrored()) + decrease(); + else + increase(); + event->accept(); + } + } else { + if (event->key() == Qt::Key_Up) { + setPressed(true); + increase(); + event->accept(); + } else if (event->key() == Qt::Key_Down) { + setPressed(true); + decrease(); + event->accept(); + } + } +} + +void QQuickSlider::keyReleaseEvent(QKeyEvent *event) +{ + QQuickControl::keyReleaseEvent(event); + setPressed(false); +} + +void QQuickSlider::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickSlider); + QQuickControl::mousePressEvent(event); + d->pressPoint = event->pos(); + setPressed(true); +} + +void QQuickSlider::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickSlider); + QQuickControl::mouseMoveEvent(event); + if (!keepMouseGrab()) { + if (d->orientation == Qt::Horizontal) + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(event->pos().x() - d->pressPoint.x(), Qt::XAxis, event)); + else + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(event->pos().y() - d->pressPoint.y(), Qt::YAxis, event)); + } + if (keepMouseGrab()) { + qreal pos = d->positionAt(event->pos()); + if (d->snapMode == SnapAlways) + pos = d->snapPosition(pos); + d->setPosition(pos); + } +} + +void QQuickSlider::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickSlider); + QQuickControl::mouseReleaseEvent(event); + d->pressPoint = QPoint(); + if (keepMouseGrab()) { + qreal pos = d->positionAt(event->pos()); + if (d->snapMode != NoSnap) + pos = d->snapPosition(pos); + qreal val = d->valueAt(pos); + if (!qFuzzyCompare(val, d->value)) + setValue(val); + else if (d->snapMode != NoSnap) + d->setPosition(pos); + setKeepMouseGrab(false); + } + setPressed(false); +} + +void QQuickSlider::mouseUngrabEvent() +{ + Q_D(QQuickSlider); + QQuickControl::mouseUngrabEvent(); + d->pressPoint = QPoint(); + setPressed(false); +} + +void QQuickSlider::wheelEvent(QWheelEvent *event) +{ + Q_D(QQuickSlider); + QQuickControl::wheelEvent(event); + if (d->wheelEnabled) { + const qreal oldValue = d->value; + const QPointF angle = event->angleDelta(); + const qreal delta = (qFuzzyIsNull(angle.y()) ? angle.x() : angle.y()) / QWheelEvent::DefaultDeltasPerStep; + const qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize; + setValue(oldValue + step * delta); + event->setAccepted(!qFuzzyCompare(d->value, oldValue)); + } +} + +void QQuickSlider::mirrorChange() +{ + QQuickControl::mirrorChange(); + emit visualPositionChanged(); +} + +void QQuickSlider::componentComplete() +{ + Q_D(QQuickSlider); + QQuickControl::componentComplete(); + setValue(d->value); + d->updatePosition(); +} + +#ifndef QT_NO_ACCESSIBILITY +void QQuickSlider::accessibilityActiveChanged(bool active) +{ + QQuickControl::accessibilityActiveChanged(active); + + Q_D(QQuickSlider); + if (active) + setAccessibleProperty("pressed", d->pressed); +} + +QAccessible::Role QQuickSlider::accessibleRole() const +{ + return QAccessible::Slider; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickslider_p.h b/src/quicktemplates2/qquickslider_p.h new file mode 100644 index 00000000..8efa6b02 --- /dev/null +++ b/src/quicktemplates2/qquickslider_p.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSLIDER_P_H +#define QQUICKSLIDER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickSliderPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickSlider : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged FINAL) + Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged FINAL) + Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged FINAL) + Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL) + Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL) + Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL) + Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged FINAL) + Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL) + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL) + Q_PROPERTY(QQuickItem *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL) + +public: + explicit QQuickSlider(QQuickItem *parent = nullptr); + + qreal from() const; + void setFrom(qreal from); + + qreal to() const; + void setTo(qreal to); + + qreal value() const; + void setValue(qreal value); + + qreal position() const; + qreal visualPosition() const; + + qreal stepSize() const; + void setStepSize(qreal step); + + enum SnapMode { + NoSnap, + SnapAlways, + SnapOnRelease + }; + Q_ENUM(SnapMode) + + SnapMode snapMode() const; + void setSnapMode(SnapMode mode); + + bool isPressed() const; + void setPressed(bool pressed); + + Qt::Orientation orientation() const; + void setOrientation(Qt::Orientation orientation); + + QQuickItem *handle() const; + void setHandle(QQuickItem *handle); + +public Q_SLOTS: + void increase(); + void decrease(); + +Q_SIGNALS: + void fromChanged(); + void toChanged(); + void valueChanged(); + void positionChanged(); + void visualPositionChanged(); + void stepSizeChanged(); + void snapModeChanged(); + void pressedChanged(); + void orientationChanged(); + void handleChanged(); + +protected: + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseUngrabEvent() override; + void wheelEvent(QWheelEvent *event) override; + + void mirrorChange() override; + void componentComplete() override; + +#ifndef QT_NO_ACCESSIBILITY + void accessibilityActiveChanged(bool active) override; + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickSlider) + Q_DECLARE_PRIVATE(QQuickSlider) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickSlider) + +#endif // QQUICKSLIDER_P_H diff --git a/src/quicktemplates2/qquickspinbox.cpp b/src/quicktemplates2/qquickspinbox.cpp new file mode 100644 index 00000000..a18e2bde --- /dev/null +++ b/src/quicktemplates2/qquickspinbox.cpp @@ -0,0 +1,724 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickspinbox_p.h" +#include "qquickcontrol_p_p.h" + +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// copied from qabstractbutton.cpp +static const int AUTO_REPEAT_DELAY = 300; +static const int AUTO_REPEAT_INTERVAL = 100; + +/*! + \qmltype SpinBox + \inherits Control + \instantiates QQuickSpinBox + \inqmlmodule Qt.labs.controls + \ingroup input + \brief A spinbox control that allows the user to select from a set of preset values. + + \image qtquickcontrols-spinbox.png + + SpinBox allows the user to choose an integer value by clicking the up + or down indicator buttons, or by pressing up or down on the keyboard. + Optionally, SpinBox can be also made \l editable, so the user can enter + a text value in the input field. + + By default, SpinBox provides discrete values in the range of \c [0-99] + with a \l stepSize of \c 1. + + \snippet qtquickcontrols-spinbox.qml 1 + + \section2 Custom Values + + \image qtquickcontrols-spinbox-textual.png + + Even though SpinBox works on integer values, it can be customized to + accept arbitrary input values. The following snippet demonstrates how + \l validator, \l textFromValue and \l valueFromText can be used to + customize the default behavior. + + \snippet qtquickcontrols-spinbox-textual.qml 1 + + \labs + + \sa Tumbler, {Customizing SpinBox} +*/ + +class QQuickSpinBoxPrivate : public QQuickControlPrivate +{ + Q_DECLARE_PUBLIC(QQuickSpinBox) + +public: + QQuickSpinBoxPrivate() : editable(false), from(0), to(99), value(0), stepSize(1), + delayTimer(0), repeatTimer(0), up(nullptr), down(nullptr), validator(nullptr) { } + + int boundValue(int value) const; + void updateValue(); + + int effectiveStepSize() const; + + void startRepeatDelay(); + void startPressRepeat(); + void stopPressRepeat(); + + bool handleMousePressEvent(QQuickItem *child, QMouseEvent *event); + bool handleMouseMoveEvent(QQuickItem *child, QMouseEvent *event); + bool handleMouseReleaseEvent(QQuickItem *child, QMouseEvent *event); + bool handleMouseUngrabEvent(QQuickItem *child); + + bool editable; + int from; + int to; + int value; + int stepSize; + int delayTimer; + int repeatTimer; + QQuickSpinButton *up; + QQuickSpinButton *down; + QValidator *validator; + mutable QJSValue textFromValue; + mutable QJSValue valueFromText; +}; + +int QQuickSpinBoxPrivate::boundValue(int value) const +{ + return from > to ? qBound(to, value, from) : qBound(from, value, to); +} + +void QQuickSpinBoxPrivate::updateValue() +{ + Q_Q(QQuickSpinBox); + if (contentItem) { + QVariant text = contentItem->property("text"); + if (text.isValid()) { + QQmlEngine *engine = qmlEngine(q); + if (engine) { + QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine); + QJSValue loc(v4, QQmlLocale::wrap(v4, locale)); + QJSValue val = q->valueFromText().call(QJSValueList() << text.toString() << loc); + q->setValue(val.toInt()); + } + } + } +} + +int QQuickSpinBoxPrivate::effectiveStepSize() const +{ + return from > to ? -1 * stepSize : stepSize; +} + +void QQuickSpinBoxPrivate::startRepeatDelay() +{ + Q_Q(QQuickSpinBox); + stopPressRepeat(); + delayTimer = q->startTimer(AUTO_REPEAT_DELAY); +} + +void QQuickSpinBoxPrivate::startPressRepeat() +{ + Q_Q(QQuickSpinBox); + stopPressRepeat(); + repeatTimer = q->startTimer(AUTO_REPEAT_INTERVAL); +} + +void QQuickSpinBoxPrivate::stopPressRepeat() +{ + Q_Q(QQuickSpinBox); + if (delayTimer > 0) { + q->killTimer(delayTimer); + delayTimer = 0; + } + if (repeatTimer > 0) { + q->killTimer(repeatTimer); + repeatTimer = 0; + } +} + +bool QQuickSpinBoxPrivate::handleMousePressEvent(QQuickItem *child, QMouseEvent *event) +{ + Q_Q(QQuickSpinBox); + QQuickItem *ui = up->indicator(); + QQuickItem *di = down->indicator(); + up->setPressed(ui && ui->contains(ui->mapFromItem(child, event->pos()))); + down->setPressed(di && di->contains(di->mapFromItem(child, event->pos()))); + + bool pressed = up->isPressed() || down->isPressed(); + q->setAccessibleProperty("pressed", pressed); + if (pressed) + startRepeatDelay(); + return pressed; +} + +bool QQuickSpinBoxPrivate::handleMouseMoveEvent(QQuickItem *child, QMouseEvent *event) +{ + Q_Q(QQuickSpinBox); + QQuickItem *ui = up->indicator(); + QQuickItem *di = down->indicator(); + up->setPressed(ui && ui->contains(ui->mapFromItem(child, event->pos()))); + down->setPressed(di && di->contains(di->mapFromItem(child, event->pos()))); + + bool pressed = up->isPressed() || down->isPressed(); + q->setAccessibleProperty("pressed", pressed); + stopPressRepeat(); + return pressed; +} + +bool QQuickSpinBoxPrivate::handleMouseReleaseEvent(QQuickItem *child, QMouseEvent *event) +{ + Q_Q(QQuickSpinBox); + QQuickItem *ui = up->indicator(); + QQuickItem *di = down->indicator(); + bool wasPressed = up->isPressed() || down->isPressed(); + if (up->isPressed()) { + up->setPressed(false); + if (repeatTimer <= 0 && ui && ui->contains(ui->mapFromItem(child, event->pos()))) + q->increase(); + } else if (down->isPressed()) { + down->setPressed(false); + if (repeatTimer <= 0 && di && di->contains(di->mapFromItem(child, event->pos()))) + q->decrease(); + } + + q->setAccessibleProperty("pressed", false); + stopPressRepeat(); + return wasPressed; +} + +bool QQuickSpinBoxPrivate::handleMouseUngrabEvent(QQuickItem *) +{ + Q_Q(QQuickSpinBox); + up->setPressed(false); + down->setPressed(false); + + q->setAccessibleProperty("pressed", false); + stopPressRepeat(); + return false; +} + +QQuickSpinBox::QQuickSpinBox(QQuickItem *parent) : + QQuickControl(*(new QQuickSpinBoxPrivate), parent) +{ + Q_D(QQuickSpinBox); + d->up = new QQuickSpinButton(this); + d->down = new QQuickSpinButton(this); + + setFlag(ItemIsFocusScope); + setFiltersChildMouseEvents(true); + setAcceptedMouseButtons(Qt::LeftButton); +} + +/*! + \qmlproperty int Qt.labs.controls::SpinBox::from + + This property holds the starting value for the range. The default value is \c 0. + + \sa to, value +*/ +int QQuickSpinBox::from() const +{ + Q_D(const QQuickSpinBox); + return d->from; +} + +void QQuickSpinBox::setFrom(int from) +{ + Q_D(QQuickSpinBox); + if (d->from == from) + return; + + d->from = from; + emit fromChanged(); + if (isComponentComplete()) + setValue(d->value); +} + +/*! + \qmlproperty int Qt.labs.controls::SpinBox::to + + This property holds the end value for the range. The default value is \c 99. + + \sa from, value +*/ +int QQuickSpinBox::to() const +{ + Q_D(const QQuickSpinBox); + return d->to; +} + +void QQuickSpinBox::setTo(int to) +{ + Q_D(QQuickSpinBox); + if (d->to == to) + return; + + d->to = to; + emit toChanged(); + if (isComponentComplete()) + setValue(d->value); +} + +/*! + \qmlproperty int Qt.labs.controls::SpinBox::value + + This property holds the value in the range \c from - \c to. The default value is \c 0. +*/ +int QQuickSpinBox::value() const +{ + Q_D(const QQuickSpinBox); + return d->value; +} + +void QQuickSpinBox::setValue(int value) +{ + Q_D(QQuickSpinBox); + if (isComponentComplete()) + value = d->boundValue(value); + + if (d->value == value) + return; + + d->value = value; + emit valueChanged(); +} + +/*! + \qmlproperty int Qt.labs.controls::SpinBox::stepSize + + This property holds the step size. The default value is \c 1. + + \sa increase(), decrease() +*/ +int QQuickSpinBox::stepSize() const +{ + Q_D(const QQuickSpinBox); + return d->stepSize; +} + +void QQuickSpinBox::setStepSize(int step) +{ + Q_D(QQuickSpinBox); + if (d->stepSize == step) + return; + + d->stepSize = step; + emit stepSizeChanged(); +} + +/*! + \qmlproperty bool Qt.labs.controls::SpinBox::editable + + This property holds whether the spinbox is editable. The default value is \c false. + + \sa validator +*/ +bool QQuickSpinBox::isEditable() const +{ + Q_D(const QQuickSpinBox); + return d->editable; +} + +void QQuickSpinBox::setEditable(bool editable) +{ + Q_D(QQuickSpinBox); + if (d->editable == editable) + return; + + d->editable = editable; + emit editableChanged(); +} + +/*! + \qmlproperty Validator Qt.labs.controls::SpinBox::validator + + This property holds the input text validator for editable spinboxes. By + default, SpinBox uses \l IntValidator to accept input of integer numbers. + + \snippet SpinBox.qml validator + + \sa editable, textFromValue, valueFromText, {Control::locale}{locale} +*/ +QValidator *QQuickSpinBox::validator() const +{ + Q_D(const QQuickSpinBox); + return d->validator; +} + +void QQuickSpinBox::setValidator(QValidator *validator) +{ + Q_D(QQuickSpinBox); + if (d->validator == validator) + return; + + d->validator = validator; + emit validatorChanged(); +} + +/*! + \qmlproperty function Qt.labs.controls::SpinBox::textFromValue + + This property holds a callback function that is called whenever + an integer value needs to be converted to display text. + + The callback function signature is \c {string function(value, locale)}. + The function can have one or two arguments, where the first argument + is the value to be converted, and the optional second argument is the + locale that should be used for the conversion, if applicable. + + The default implementation does the conversion using \l {QtQml::Locale}{Number.toLocaleString()}: + + \code + textFromValue: function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); } + \endcode + + \sa valueFromText, validator, {Control::locale}{locale} +*/ +QJSValue QQuickSpinBox::textFromValue() const +{ + Q_D(const QQuickSpinBox); + if (!d->textFromValue.isCallable()) { + QQmlEngine *engine = qmlEngine(this); + if (engine) + d->textFromValue = engine->evaluate(QStringLiteral("function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); }")); + } + return d->textFromValue; +} + +void QQuickSpinBox::setTextFromValue(const QJSValue &callback) +{ + Q_D(QQuickSpinBox); + if (!callback.isCallable()) { + qmlInfo(this) << "textFromValue must be a callable function"; + return; + } + d->textFromValue = callback; + emit textFromValueChanged(); +} + +/*! + \qmlproperty function Qt.labs.controls::SpinBox::valueFromText + + This property holds a callback function that is called whenever + input text needs to be converted to an integer value. + + The callback function signature is \c {int function(text, locale)}. + The function can have one or two arguments, where the first argument + is the text to be converted, and the optional second argument is the + locale that should be used for the conversion, if applicable. + + The default implementation does the conversion using \l {QtQml::Locale}{Number.fromLocaleString()}: + + \code + valueFromText: function(text, locale) { return Number.fromLocaleString(locale, text); } + \endcode + + \sa textFromValue, validator, {Control::locale}{locale} +*/ +QJSValue QQuickSpinBox::valueFromText() const +{ + Q_D(const QQuickSpinBox); + if (!d->valueFromText.isCallable()) { + QQmlEngine *engine = qmlEngine(this); + if (engine) + d->valueFromText = engine->evaluate(QStringLiteral("function(text, locale) { return Number.fromLocaleString(locale, text); }")); + } + return d->valueFromText; +} + +void QQuickSpinBox::setValueFromText(const QJSValue &callback) +{ + Q_D(QQuickSpinBox); + if (!callback.isCallable()) { + qmlInfo(this) << "valueFromText must be a callable function"; + return; + } + d->valueFromText = callback; + emit valueFromTextChanged(); +} + +/*! + \qmlpropertygroup Qt.labs.controls::SpinBox::up + \qmlproperty bool Qt.labs.controls::SpinBox::up.pressed + \qmlproperty Item Qt.labs.controls::SpinBox::up.indicator + + These properties hold the up indicator item and whether it is pressed. + + \sa increase() +*/ +QQuickSpinButton *QQuickSpinBox::up() const +{ + Q_D(const QQuickSpinBox); + return d->up; +} + +/*! + \qmlpropertygroup Qt.labs.controls::SpinBox::down + \qmlproperty bool Qt.labs.controls::SpinBox::down.pressed + \qmlproperty Item Qt.labs.controls::SpinBox::down.indicator + + These properties hold the down indicator item and whether it is pressed. + + \sa decrease() +*/ +QQuickSpinButton *QQuickSpinBox::down() const +{ + Q_D(const QQuickSpinBox); + return d->down; +} + +/*! + \qmlmethod void Qt.labs.controls::SpinBox::increase() + + Increases the value by \l stepSize. + + \sa stepSize +*/ +void QQuickSpinBox::increase() +{ + Q_D(QQuickSpinBox); + setValue(d->value + d->effectiveStepSize()); +} + +/*! + \qmlmethod void Qt.labs.controls::SpinBox::decrease() + + Decreases the value by \l stepSize. + + \sa stepSize +*/ +void QQuickSpinBox::decrease() +{ + Q_D(QQuickSpinBox); + setValue(d->value - d->effectiveStepSize()); +} + +void QQuickSpinBox::keyPressEvent(QKeyEvent *event) +{ + Q_D(QQuickSpinBox); + QQuickControl::keyPressEvent(event); + + switch (event->key()) { + case Qt::Key_Up: + increase(); + d->up->setPressed(true); + event->accept(); + break; + + case Qt::Key_Down: + decrease(); + d->down->setPressed(true); + event->accept(); + break; + + default: + break; + } + + setAccessibleProperty("pressed", d->up->isPressed() || d->down->isPressed()); +} + +void QQuickSpinBox::keyReleaseEvent(QKeyEvent *event) +{ + Q_D(QQuickSpinBox); + QQuickControl::keyReleaseEvent(event); + + if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) + d->updateValue(); + + d->up->setPressed(false); + d->down->setPressed(false); + setAccessibleProperty("pressed", false); +} + +bool QQuickSpinBox::childMouseEventFilter(QQuickItem *child, QEvent *event) +{ + Q_D(QQuickSpinBox); + switch (event->type()) { + case QEvent::MouseButtonPress: + return d->handleMousePressEvent(child, static_cast(event)); + case QEvent::MouseMove: + return d->handleMouseMoveEvent(child, static_cast(event)); + case QEvent::MouseButtonRelease: + return d->handleMouseReleaseEvent(child, static_cast(event)); + case QEvent::UngrabMouse: + return d->handleMouseUngrabEvent(child); + default: + return false; + } +} + +void QQuickSpinBox::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickSpinBox); + QQuickControl::mousePressEvent(event); + d->handleMousePressEvent(this, event); +} + +void QQuickSpinBox::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickSpinBox); + QQuickControl::mouseMoveEvent(event); + d->handleMouseMoveEvent(this, event); +} + +void QQuickSpinBox::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickSpinBox); + QQuickControl::mouseReleaseEvent(event); + d->handleMouseReleaseEvent(this, event); +} + +void QQuickSpinBox::mouseUngrabEvent() +{ + Q_D(QQuickSpinBox); + QQuickControl::mouseUngrabEvent(); + d->handleMouseUngrabEvent(this); +} + +void QQuickSpinBox::timerEvent(QTimerEvent *event) +{ + Q_D(QQuickSpinBox); + QQuickControl::timerEvent(event); + if (event->timerId() == d->delayTimer) { + d->startPressRepeat(); + } else if (event->timerId() == d->repeatTimer) { + if (d->up->isPressed()) + increase(); + else if (d->down->isPressed()) + decrease(); + } +} + +void QQuickSpinBox::wheelEvent(QWheelEvent *event) +{ + Q_D(QQuickSpinBox); + QQuickControl::wheelEvent(event); + if (d->wheelEnabled) { + const int oldValue = d->value; + const QPointF angle = event->angleDelta(); + const qreal delta = (qFuzzyIsNull(angle.y()) ? angle.x() : angle.y()) / QWheelEvent::DefaultDeltasPerStep; + setValue(oldValue + qRound(d->effectiveStepSize() * delta)); + event->setAccepted(d->value != oldValue); + } +} + +void QQuickSpinBox::itemChange(ItemChange change, const ItemChangeData &value) +{ + Q_D(QQuickSpinBox); + QQuickControl::itemChange(change, value); + if (change == ItemActiveFocusHasChanged && !value.boolValue) + d->updateValue(); +} + +void QQuickSpinBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_UNUSED(oldItem); + if (newItem) + newItem->setActiveFocusOnTab(true); +} + +QFont QQuickSpinBox::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::EditorFont); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickSpinBox::accessibleRole() const +{ + return QAccessible::SpinBox; +} +#endif + +class QQuickSpinButtonPrivate : public QObjectPrivate +{ +public: + QQuickSpinButtonPrivate() : pressed(false), indicator(nullptr) { } + bool pressed; + QQuickItem *indicator; +}; + +QQuickSpinButton::QQuickSpinButton(QQuickSpinBox *parent) : + QObject(*(new QQuickSpinButtonPrivate), parent) +{ +} + +bool QQuickSpinButton::isPressed() const +{ + Q_D(const QQuickSpinButton); + return d->pressed; +} + +void QQuickSpinButton::setPressed(bool pressed) +{ + Q_D(QQuickSpinButton); + if (d->pressed == pressed) + return; + + d->pressed = pressed; + emit pressedChanged(); +} + +QQuickItem *QQuickSpinButton::indicator() const +{ + Q_D(const QQuickSpinButton); + return d->indicator; +} + +void QQuickSpinButton::setIndicator(QQuickItem *indicator) +{ + Q_D(QQuickSpinButton); + if (d->indicator == indicator) + return; + + delete d->indicator; + d->indicator = indicator; + if (indicator) { + if (!indicator->parentItem()) + indicator->setParentItem(static_cast(parent())); + indicator->setAcceptedMouseButtons(Qt::LeftButton); + } + emit indicatorChanged(); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickspinbox_p.h b/src/quicktemplates2/qquickspinbox_p.h new file mode 100644 index 00000000..11d8fff6 --- /dev/null +++ b/src/quicktemplates2/qquickspinbox_p.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSPINBOX_P_H +#define QQUICKSPINBOX_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QValidator; +class QQuickSpinButton; +class QQuickSpinButtonPrivate; +class QQuickSpinBoxPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickSpinBox : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(int from READ from WRITE setFrom NOTIFY fromChanged FINAL) + Q_PROPERTY(int to READ to WRITE setTo NOTIFY toChanged FINAL) + Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged FINAL) + Q_PROPERTY(int stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL) + Q_PROPERTY(bool editable READ isEditable WRITE setEditable NOTIFY editableChanged FINAL) + Q_PROPERTY(QValidator *validator READ validator WRITE setValidator NOTIFY validatorChanged FINAL) + Q_PROPERTY(QJSValue textFromValue READ textFromValue WRITE setTextFromValue NOTIFY textFromValueChanged FINAL) + Q_PROPERTY(QJSValue valueFromText READ valueFromText WRITE setValueFromText NOTIFY valueFromTextChanged FINAL) + Q_PROPERTY(QQuickSpinButton *up READ up CONSTANT FINAL) + Q_PROPERTY(QQuickSpinButton *down READ down CONSTANT FINAL) + +public: + explicit QQuickSpinBox(QQuickItem *parent = nullptr); + + int from() const; + void setFrom(int from); + + int to() const; + void setTo(int to); + + int value() const; + void setValue(int value); + + int stepSize() const; + void setStepSize(int step); + + bool isEditable() const; + void setEditable(bool editable); + + QValidator *validator() const; + void setValidator(QValidator *validator); + + QJSValue textFromValue() const; + void setTextFromValue(const QJSValue &callback); + + QJSValue valueFromText() const; + void setValueFromText(const QJSValue &callback); + + QQuickSpinButton *up() const; + QQuickSpinButton *down() const; + +public Q_SLOTS: + void increase(); + void decrease(); + +Q_SIGNALS: + void fromChanged(); + void toChanged(); + void valueChanged(); + void stepSizeChanged(); + void editableChanged(); + void validatorChanged(); + void textFromValueChanged(); + void valueFromTextChanged(); + +protected: + bool childMouseEventFilter(QQuickItem *child, QEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseUngrabEvent() override; + void timerEvent(QTimerEvent *event) override; + void wheelEvent(QWheelEvent *event) override; + + void itemChange(ItemChange change, const ItemChangeData &value) override; + void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; + + QFont defaultFont() const override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickSpinBox) + Q_DECLARE_PRIVATE(QQuickSpinBox) +}; + +class Q_QUICKTEMPLATES2_EXPORT QQuickSpinButton : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL) + Q_PROPERTY(QQuickItem *indicator READ indicator WRITE setIndicator NOTIFY indicatorChanged FINAL) + +public: + explicit QQuickSpinButton(QQuickSpinBox *parent); + + bool isPressed() const; + void setPressed(bool pressed); + + QQuickItem *indicator() const; + void setIndicator(QQuickItem *indicator); + +Q_SIGNALS: + void pressedChanged(); + void indicatorChanged(); + +private: + Q_DISABLE_COPY(QQuickSpinButton) + Q_DECLARE_PRIVATE(QQuickSpinButton) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickSpinBox) + +#endif // QQUICKSPINBOX_P_H diff --git a/src/quicktemplates2/qquickstackview.cpp b/src/quicktemplates2/qquickstackview.cpp new file mode 100644 index 00000000..f5d6f5b1 --- /dev/null +++ b/src/quicktemplates2/qquickstackview.cpp @@ -0,0 +1,989 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickstackview_p.h" +#include "qquickstackview_p_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype StackView + \inherits Control + \instantiates QQuickStackView + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-navigation + \ingroup qtquickcontrols2-containers + \brief Provides a stack-based navigation model. + + \image qtquickcontrols-stackview-wireframe.png + + StackView can be used with a set of inter-linked information pages. For + example, an email application with separate views to list the latest emails, + view a specific email, and list/view the attachments. The email list view + is pushed onto the stack as users open an email, and popped out as they + choose to go back. + + The following snippet demonstrates a simple use case, where the \c mainView + is pushed onto and popped out of the stack on relevant button click: + + \qml + ApplicationWindow { + title: qsTr("Hello World") + width: 640 + height: 480 + visible: true + + StackView { + id: stack + initialItem: mainView + anchors.fill: parent + } + + Component { + id: mainView + + Row { + spacing: 10 + + Button { + text: "Push" + onClicked: stack.push(mainView) + } + Button { + text: "Pop" + enabled: stack.depth > 1 + onClicked: stack.pop() + + } + Text { + text: stack.depth + } + } + } + } + \endqml + + \section1 Using StackView in an Application + + Using StackView in an application is as simple as adding it as a child to + a Window. The stack is usually anchored to the edges of the window, except + at the top or bottom where it might be anchored to a status bar, or some + other similar UI component. The stack can then be used by invoking its + navigation methods. The first item to show in the StackView is the one + that was assigned to \l initialItem, or the topmost item if \l initialItem + is not set. + + \section1 Basic Navigation + + StackView supports three primary navigation operations: push(), pop(), and + replace(). These correspond to classic stack operations where "push" adds + an item to the top of a stack, "pop" removes the top item from the + stack, and "replace" is like a pop followed by a push, which replaces the + topmost item with the new item. The topmost item in the stack + corresponds to the one that is \l{StackView::currentItem}{currently} + visible on screen. Logically, "push" navigates forward or deeper into the + application UI, "pop" navigates backward, and "replace" replaces the + \l currentItem. + + Sometimes, it is necessary to go back more than a single step in the stack. + For example, to return to a "main" item or some kind of section item in the + application. In such cases, it is possible to specify an item as a + parameter for pop(). This is called an "unwind" operation, where the stack + unwinds till the specified item. If the item is not found, stack unwinds + until it is left with one item, which becomes the \l currentItem. To + explicitly unwind to the bottom of the stack, it is recommended to use + \l{pop()}{pop(null)}, although any non-existent item will do. + + Given the stack [A, B, C]: + + \list + \li \l{push()}{push(D)} => [A, B, C, D] - "push" transition animation + between C and D + \li pop() => [A, B] - "pop" transition animation between C and B + \li \l{replace()}{replace(D)} => [A, B, D] - "replace" transition between + C and D + \li \l{pop()}{pop(A)} => [A] - "pop" transition between C and A + \endlist + + \note When the stack is empty, a push() operation will not have a + transition animation because there is nothing to transition from (typically + on application start-up). A pop() operation on a stack with depth 1 or + 0 does nothing. In such cases, the stack can be emptied using the clear() + method. + + \section1 Deep Linking + + \e{Deep linking} means launching an application into a particular state. For + example, a newspaper application could be launched into showing a + particular article, bypassing the topmost item. In terms of StackView, deep linking means the ability to modify + the state of the stack, so much so that it is possible to push a set of + items to the top of the stack, or to completely reset the stack to a given + state. + + The API for deep linking in StackView is the same as for basic navigation. + Pushing an array instead of a single item adds all the items in that array + to the stack. The transition animation, however, is applied only for the + last item in the array. The normal semantics of push() apply for deep + linking, that is, it adds whatever is pushed onto the stack. + + \note Only the last item of the array is loaded. The rest of the items are + loaded only when needed, either on subsequent calls to pop or on request to + get an item using get(). + + This gives us the following result, given the stack [A, B, C]: + + \list + \li \l{push()}{push([D, E, F])} => [A, B, C, D, E, F] - "push" transition + animation between C and F + \li \l{replace()}{replace([D, E, F])} => [A, B, D, E, F] - "replace" + transition animation between C and F + \li \l{clear()} followed by \l{push()}{push([D, E, F])} => [D, E, F] - no + transition animation for pushing items as the stack was empty. + \endlist + + \section1 Finding Items + + An Item for which the application does not have a reference can be found + by calling find(). The method needs a callback function, which is invoked + for each item in the stack (starting at the top) until a match is found. + If the callback returns \c true, find() stops and returns the matching + item, otherwise \c null is returned. + + The code below searches the stack for an item named "order_id" and unwinds + to that item. + + \badcode + stackView.pop(stackView.find(function(item) { + return item.name == "order_id"; + })); + \endcode + + You can also get to an item in the stack using \l {get()}{get(index)}. + + \badcode + previousItem = stackView.get(myItem.StackView.index - 1)); + \endcode + + \section1 Transitions + + For each push or pop operation, different transition animations are applied + to entering and exiting items. These animations define how the entering item + should animate in, and the exiting item should animate out. The animations + can be customized by assigning different \l{Transition}s for the + \l pushEnter, \l pushExit, \l popEnter, \l popExit, \l replaceEnter, and + \l replaceExit properties of StackView. + + \note The transition animations affect each others' transitional behavior. + Customizing the animation for one and leaving the other may give unexpected + results. + + The following snippet defines a simple fade transition for push and pop + operations: + + \qml + StackView { + id: stackview + anchors.fill: parent + + pushEnter: Transition { + PropertyAnimation { + property: "opacity" + from: 0 + to:1 + duration: 200 + } + } + pushExit: Transition { + PropertyAnimation { + property: "opacity" + from: 1 + to:0 + duration: 200 + } + } + popEnter: Transition { + PropertyAnimation { + property: "opacity" + from: 0 + to:1 + duration: 200 + } + } + popExit: Transition { + PropertyAnimation { + property: "opacity" + from: 1 + to:0 + duration: 200 + } + } + } + \endqml + + \note Using anchors on the items added to a StackView is not supported. + Typically push, pop, and replace transitions animate the position, + which is not possible when anchors are applied. Notice that this + only applies to the root of the item. Using anchors for its children + works as expected. + + \labs + + \sa {Customizing StackView}, {Navigation Controls}, {Container Controls} +*/ + +QQuickStackView::QQuickStackView(QQuickItem *parent) : + QQuickControl(*(new QQuickStackViewPrivate), parent) +{ + setFlag(ItemIsFocusScope); +} + +QQuickStackView::~QQuickStackView() +{ + Q_D(QQuickStackView); + if (d->transitioner) { + d->transitioner->setChangeListener(nullptr); + delete d->transitioner; + } + qDeleteAll(d->removals); + qDeleteAll(d->elements); +} + +QQuickStackAttached *QQuickStackView::qmlAttachedProperties(QObject *object) +{ + QQuickItem *item = qobject_cast(object); + if (!item) { + qmlInfo(object) << "StackView must be attached to an Item"; + return nullptr; + } + return new QQuickStackAttached(item); +} + +/*! + \qmlproperty bool Qt.labs.controls::StackView::busy + \readonly + This property holds whether a transition is running. +*/ +bool QQuickStackView::isBusy() const +{ + Q_D(const QQuickStackView); + return d->busy; +} + +/*! + \qmlproperty int Qt.labs.controls::StackView::depth + \readonly + This property holds the number of items currently pushed onto the stack. +*/ +int QQuickStackView::depth() const +{ + Q_D(const QQuickStackView); + return d->elements.count(); +} + +/*! + \qmlproperty Item Qt.labs.controls::StackView::currentItem + \readonly + This property holds the current top-most item in the stack. +*/ +QQuickItem *QQuickStackView::currentItem() const +{ + Q_D(const QQuickStackView); + return d->currentItem; +} + +/*! + \qmlmethod Item Qt.labs.controls::StackView::get(index, behavior) + + Returns the item at position \a index in the stack, or \c null if the index + is out of bounds. + + Supported behavior values: + \value StackView.DontLoad The item is not forced to load (and \c null is returned if not yet loaded). + \value StackView.ForceLoad The item is forced to load. +*/ +QQuickItem *QQuickStackView::get(int index, LoadBehavior behavior) +{ + Q_D(QQuickStackView); + QQuickStackElement *element = d->elements.value(index); + if (element) { + if (behavior == ForceLoad) + element->load(this); + return element->item; + } + return nullptr; +} + +/*! + \qmlmethod Item Qt.labs.controls::StackView::find(callback, behavior) + + Search for a specific item inside the stack. The \a callback function is called + for each item in the stack (with the item and index as arguments) until the callback + function returns \c true. The return value is the item found. For example: + + \code + stackView.find(function(item, index) { + return item.isTheOne + }) + \endcode + + Supported behavior values: + \value StackView.DontLoad Unloaded items are skipped (the callback function is not called for them). + \value StackView.ForceLoad Unloaded items are forced to load. +*/ +QQuickItem *QQuickStackView::find(const QJSValue &callback, LoadBehavior behavior) +{ + Q_D(QQuickStackView); + QJSValue func(callback); + QQmlEngine *engine = qmlEngine(this); + if (!engine || !func.isCallable()) // TODO: warning? + return nullptr; + + for (int i = d->elements.count() - 1; i >= 0; --i) { + QQuickStackElement *element = d->elements.at(i); + if (behavior == ForceLoad) + element->load(this); + if (element->item) { + QJSValue rv = func.call(QJSValueList() << engine->newQObject(element->item) << i); + if (rv.toBool()) + return element->item; + } + } + + return nullptr; +} + +/*! + \qmlmethod Item Qt.labs.controls::StackView::push(item, properties, operation) + + Pushes an \a item onto the stack using the specified \a operation, and + optionally applies a set of \a properties on the item. The item can be + an \l Item, \l Component, or a \l [QML] url. Returns the item that became + current. + + Pushing a single item: + \code + stackView.push(rect) + + // or with properties: + stackView.push(rect, {"color": "red"}) + \endcode + + Multiple items can be pushed at the same time either by passing them as + additional arguments, or as an array. The last item becomes the current + item. Each item can be followed by a set of properties to apply. + + Passing a variable amount of arguments: + \code + stackView.push(rect1, rect2, rect3) + + // or with properties: + stackView.push(rect1, {"color": "red"}, rect2, {"color": "green"}, rect3, {"color": "blue"}) + \endcode + + Pushing an array of items: + \code + stackView.push([rect1, rect2, rect3]) + + // or with properties: + stackView.push([rect1, {"color": "red"}, rect2, {"color": "green"}, rect3, {"color": "blue"}]) + \endcode + + An \a operation can be optionally specified as the last argument. Supported + operations: + + \value StackView.Transition An operation with transitions. + \value StackView.Immediate An immediate operation without transitions. + + \sa initialItem +*/ +void QQuickStackView::push(QQmlV4Function *args) +{ + Q_D(QQuickStackView); + if (args->length() <= 0) { + qmlInfo(this) << "push: missing arguments"; + args->setReturnValue(QV4::Encode::null()); + return; + } + + QV4::ExecutionEngine *v4 = args->v4engine(); + QV4::Scope scope(v4); + + Operation operation = d->elements.isEmpty() ? Immediate : Transition; + QV4::ScopedValue lastArg(scope, (*args)[args->length() - 1]); + if (lastArg->isInt32()) + operation = static_cast(lastArg->toInt32()); + + QList elements = d->parseElements(args); + if (elements.isEmpty()) { + qmlInfo(this) << "push: nothing to push"; + args->setReturnValue(QV4::Encode::null()); + return; + } + + QQuickStackElement *exit = nullptr; + if (!d->elements.isEmpty()) + exit = d->elements.top(); + + if (d->pushElements(elements)) { + emit depthChanged(); + QQuickStackElement *enter = d->elements.top(); + d->pushTransition(enter, exit, boundingRect(), operation == Immediate); + d->setCurrentItem(enter->item); + } + + if (d->currentItem) { + QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(v4, d->currentItem)); + args->setReturnValue(rv->asReturnedValue()); + } else { + args->setReturnValue(QV4::Encode::null()); + } +} + +/*! + \qmlmethod Item Qt.labs.controls::StackView::pop(item, operation) + + Pops one or more items off the stack. Returns the last item removed from the stack. + + If the \a item argument is specified, all items down to (but not + including) \a item will be popped. If \a item is \c null, all + items down to (but not including) the first item is popped. + If not specified, only the current item is popped. + + An \a operation can be optionally specified as the last argument. Supported + operations: + + \value StackView.Transition An operation with transitions. + \value StackView.Immediate An immediate operation without transitions. + + Examples: + \code + stackView.pop() + stackView.pop(someItem, StackView.Immediate) + stackView.pop(StackView.Immediate) + stackView.pop(null) + \endcode + + \sa clear() +*/ +void QQuickStackView::pop(QQmlV4Function *args) +{ + Q_D(QQuickStackView); + int argc = args->length(); + if (d->elements.count() <= 1 || argc > 2) { + if (argc > 2) + qmlInfo(this) << "pop: too many arguments"; + args->setReturnValue(QV4::Encode::null()); + return; + } + + QQuickStackElement *exit = d->elements.pop(); + QQuickStackElement *enter = d->elements.top(); + + QV4::ExecutionEngine *v4 = args->v4engine(); + QV4::Scope scope(v4); + + if (argc > 0) { + QV4::ScopedValue value(scope, (*args)[0]); + if (value->isNull()) { + enter = d->elements.value(0); + } else if (!value->isUndefined() && !value->isInt32()) { + enter = d->findElement(value); + if (!enter) { + qmlInfo(this) << "pop: unknown argument: " << value->toQString(); // TODO: safe? + args->setReturnValue(QV4::Encode::null()); + d->elements.push(exit); // restore + return; + } + } + } + + Operation operation = Transition; + if (argc > 0) { + QV4::ScopedValue lastArg(scope, (*args)[argc - 1]); + if (lastArg->isInt32()) + operation = static_cast(lastArg->toInt32()); + } + + QQuickItem *previousItem = nullptr; + + if (d->popElements(enter)) { + if (exit) + previousItem = exit->item; + emit depthChanged(); + d->popTransition(enter, exit, boundingRect(), operation == Immediate); + d->setCurrentItem(enter->item); + } + + if (previousItem) { + QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(v4, previousItem)); + args->setReturnValue(rv->asReturnedValue()); + } else { + args->setReturnValue(QV4::Encode::null()); + } +} + +/*! + \qmlmethod Item Qt.labs.controls::StackView::replace(target, item, properties, operation) + + Replaces one or more items on the stack with the specified \a item and + \a operation, and optionally applies a set of \a properties on the + item. The item can be an \l Item, \l Component, or a \l [QML] url. + Returns the item that became current. + + If the \a target argument is specified, all items down to the \target + item will be replaced. If \a target is \c null, all items in the stack + will be replaced. If not specified, only the top item will be replaced. + + Replace the top item: + \code + stackView.replace(rect) + + // or with properties: + stackView.replace(rect, {"color": "red"}) + \endcode + + Multiple items can be replaced at the same time either by passing them as + additional arguments, or as an array. Each item can be followed by a set + of properties to apply. + + Passing a variable amount of arguments: + \code + stackView.replace(rect1, rect2, rect3) + + // or with properties: + stackView.replace(rect1, {"color": "red"}, rect2, {"color": "green"}, rect3, {"color": "blue"}) + \endcode + + Replacing an array of items: + \code + stackView.replace([rect1, rect2, rect3]) + + // or with properties: + stackView.replace([rect1, {"color": "red"}, rect2, {"color": "green"}, rect3, {"color": "blue"}]) + \endcode + + An \a operation can be optionally specified as the last argument. Supported + operations: + + \value StackView.Transition An operation with transitions. + \value StackView.Immediate An immediate operation without transitions. + + \sa push() +*/ +void QQuickStackView::replace(QQmlV4Function *args) +{ + Q_D(QQuickStackView); + if (args->length() <= 0) { + qmlInfo(this) << "replace: missing arguments"; + args->setReturnValue(QV4::Encode::null()); + return; + } + + QV4::ExecutionEngine *v4 = args->v4engine(); + QV4::Scope scope(v4); + + Operation operation = d->elements.isEmpty() ? Immediate : Transition; + QV4::ScopedValue lastArg(scope, (*args)[args->length() - 1]); + if (lastArg->isInt32()) + operation = static_cast(lastArg->toInt32()); + + QQuickStackElement *target = nullptr; + QV4::ScopedValue firstArg(scope, (*args)[0]); + if (firstArg->isNull()) + target = d->elements.value(0); + else if (!firstArg->isInt32()) + target = d->findElement(firstArg); + + QList elements = d->parseElements(args, target ? 1 : 0); + if (elements.isEmpty()) { + qmlInfo(this) << "replace: nothing to push"; + args->setReturnValue(QV4::Encode::null()); + return; + } + + int depth = d->elements.count(); + QQuickStackElement* exit = nullptr; + if (!d->elements.isEmpty()) + exit = d->elements.pop(); + + if (exit != target ? d->replaceElements(target, elements) : d->pushElements(elements)) { + if (depth != d->elements.count()) + emit depthChanged(); + QQuickStackElement *enter = d->elements.top(); + d->replaceTransition(enter, exit, boundingRect(), operation == Immediate); + d->setCurrentItem(enter->item); + } + + if (d->currentItem) { + QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(v4, d->currentItem)); + args->setReturnValue(rv->asReturnedValue()); + } else { + args->setReturnValue(QV4::Encode::null()); + } +} + +/*! + \qmlmethod void Qt.labs.controls::StackView::clear() + + Removes all items from the stack. No animations are applied. +*/ +void QQuickStackView::clear() +{ + Q_D(QQuickStackView); + d->setCurrentItem(nullptr); + qDeleteAll(d->elements); + d->elements.clear(); + emit depthChanged(); +} + +/*! + \qmlproperty var Qt.labs.controls::StackView::initialItem + + This property holds the initial item that should be shown when the StackView + is created. The initial item can be an \l Item, \l Component, or a \l [QML] url. + Specifying an initial item is equivalent to: + \code + Component.onCompleted: stackView.push(myInitialItem) + \endcode + + \sa push() +*/ +QVariant QQuickStackView::initialItem() const +{ + Q_D(const QQuickStackView); + return d->initialItem; +} + +void QQuickStackView::setInitialItem(const QVariant &item) +{ + Q_D(QQuickStackView); + d->initialItem = item; +} + +/*! + \qmlproperty Transition Qt.labs.controls::StackView::popEnter + + This property holds the transition that is applied to the item that + enters the stack when another item is popped off of it. + + \sa {Customizing StackView} +*/ +QQuickTransition *QQuickStackView::popEnter() const +{ + Q_D(const QQuickStackView); + if (d->transitioner) + return d->transitioner->removeDisplacedTransition; + return nullptr; +} + +void QQuickStackView::setPopEnter(QQuickTransition *enter) +{ + Q_D(QQuickStackView); + d->ensureTransitioner(); + if (d->transitioner->removeDisplacedTransition == enter) + return; + + d->transitioner->removeDisplacedTransition = enter; + emit popEnterChanged(); +} + +/*! + \qmlproperty Transition Qt.labs.controls::StackView::popExit + + This property holds the transition that is applied to the item that + exits the stack when the item is popped off of it. + + \sa {Customizing StackView} +*/ +QQuickTransition *QQuickStackView::popExit() const +{ + Q_D(const QQuickStackView); + if (d->transitioner) + return d->transitioner->removeTransition; + return nullptr; +} + +void QQuickStackView::setPopExit(QQuickTransition *exit) +{ + Q_D(QQuickStackView); + d->ensureTransitioner(); + if (d->transitioner->removeTransition == exit) + return; + + d->transitioner->removeTransition = exit; + emit popExitChanged(); +} + +/*! + \qmlproperty Transition Qt.labs.controls::StackView::pushEnter + + This property holds the transition that is applied to the item that + enters the stack when the item is pushed onto it. + + \sa {Customizing StackView} +*/ +QQuickTransition *QQuickStackView::pushEnter() const +{ + Q_D(const QQuickStackView); + if (d->transitioner) + return d->transitioner->addTransition; + return nullptr; +} + +void QQuickStackView::setPushEnter(QQuickTransition *enter) +{ + Q_D(QQuickStackView); + d->ensureTransitioner(); + if (d->transitioner->addTransition == enter) + return; + + d->transitioner->addTransition = enter; + emit pushEnterChanged(); +} + +/*! + \qmlproperty Transition Qt.labs.controls::StackView::pushExit + + This property holds the transition that is applied to the item that + exits the stack when another item is pushed onto it. + + \sa {Customizing StackView} +*/ +QQuickTransition *QQuickStackView::pushExit() const +{ + Q_D(const QQuickStackView); + if (d->transitioner) + return d->transitioner->addDisplacedTransition; + return nullptr; +} + +void QQuickStackView::setPushExit(QQuickTransition *exit) +{ + Q_D(QQuickStackView); + d->ensureTransitioner(); + if (d->transitioner->addDisplacedTransition == exit) + return; + + d->transitioner->addDisplacedTransition = exit; + emit pushExitChanged(); +} + +/*! + \qmlproperty Transition Qt.labs.controls::StackView::replaceEnter + + This property holds the transition that is applied to the item that + enters the stack when another item is replaced by it. + + \sa {Customizing StackView} +*/ +QQuickTransition *QQuickStackView::replaceEnter() const +{ + Q_D(const QQuickStackView); + if (d->transitioner) + return d->transitioner->moveTransition; + return nullptr; +} + +void QQuickStackView::setReplaceEnter(QQuickTransition *enter) +{ + Q_D(QQuickStackView); + d->ensureTransitioner(); + if (d->transitioner->moveTransition == enter) + return; + + d->transitioner->moveTransition = enter; + emit replaceEnterChanged(); +} + +/*! + \qmlproperty Transition Qt.labs.controls::StackView::replaceExit + + This property holds the transition that is applied to the item that + exits the stack when it is replaced by another item. + + \sa {Customizing StackView} +*/ +QQuickTransition *QQuickStackView::replaceExit() const +{ + Q_D(const QQuickStackView); + if (d->transitioner) + return d->transitioner->moveDisplacedTransition; + return nullptr; +} + +void QQuickStackView::setReplaceExit(QQuickTransition *exit) +{ + Q_D(QQuickStackView); + d->ensureTransitioner(); + if (d->transitioner->moveDisplacedTransition == exit) + return; + + d->transitioner->moveDisplacedTransition = exit; + emit replaceExitChanged(); +} + +void QQuickStackView::componentComplete() +{ + QQuickControl::componentComplete(); + + Q_D(QQuickStackView); + QQuickStackElement *element = nullptr; + if (QObject *o = d->initialItem.value()) + element = QQuickStackElement::fromObject(o, this); + else if (d->initialItem.canConvert()) + element = QQuickStackElement::fromString(d->initialItem.toString(), this); + if (d->pushElement(element)) { + emit depthChanged(); + d->setCurrentItem(element->item); + element->setStatus(QQuickStackView::Active); + } +} + +void QQuickStackView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + QQuickControl::geometryChanged(newGeometry, oldGeometry); + + Q_D(QQuickStackView); + for (QQuickStackElement *element : qAsConst(d->elements)) { + if (element->item) { + if (!element->widthValid) + element->item->setWidth(newGeometry.width()); + if (!element->heightValid) + element->item->setHeight(newGeometry.height()); + } + } +} + +bool QQuickStackView::childMouseEventFilter(QQuickItem *item, QEvent *event) +{ + // in order to block accidental user interaction while busy/transitioning, + // StackView filters out childrens' mouse events. therefore we block all + // press events. however, since push() may be called from signal handlers + // such as onPressed or onDoubleClicked, we must let the current mouse + // grabber item receive the respective mouse release event to avoid + // breaking its state (QTBUG-50305). + if (event->type() == QEvent::MouseButtonPress) + return true; + QQuickWindow *window = item->window(); + return window && !window->mouseGrabberItem(); +} + +void QQuickStackAttachedPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent) +{ + Q_Q(QQuickStackAttached); + int oldIndex = element ? element->index : -1; + QQuickStackView *oldView = element ? element->view : nullptr; + QQuickStackView::Status oldStatus = element ? element->status : QQuickStackView::Inactive; + + QQuickStackView *newView = qobject_cast(parent); + element = newView ? QQuickStackViewPrivate::get(newView)->findElement(item) : nullptr; + + int newIndex = element ? element->index : -1; + QQuickStackView::Status newStatus = element ? element->status : QQuickStackView::Inactive; + + if (oldIndex != newIndex) + emit q->indexChanged(); + if (oldView != newView) + emit q->viewChanged(); + if (oldStatus != newStatus) + emit q->statusChanged(); +} + +QQuickStackAttached::QQuickStackAttached(QQuickItem *parent) : + QObject(*(new QQuickStackAttachedPrivate), parent) +{ + Q_D(QQuickStackAttached); + QQuickItemPrivate::get(parent)->addItemChangeListener(d, QQuickItemPrivate::Parent); + d->itemParentChanged(parent, parent->parentItem()); +} + +QQuickStackAttached::~QQuickStackAttached() +{ + Q_D(QQuickStackAttached); + QQuickItem *parentItem = static_cast(parent()); + QQuickItemPrivate::get(parentItem)->removeItemChangeListener(d, QQuickItemPrivate::Parent); +} + +/*! + \qmlattachedproperty int Qt.labs.controls::StackView::index + \readonly + + This attached property holds the stack index of the item it's + attached to, or \c -1 if the item is not in a stack. +*/ +int QQuickStackAttached::index() const +{ + Q_D(const QQuickStackAttached); + return d->element ? d->element->index : -1; +} + +/*! + \qmlattachedproperty StackView Qt.labs.controls::StackView::view + \readonly + + This attached property holds the stack view of the item it's + attached to, or \c null if the item is not in a stack. +*/ +QQuickStackView *QQuickStackAttached::view() const +{ + Q_D(const QQuickStackAttached); + return d->element ? d->element->view : nullptr; +} + +/*! + \qmlattachedproperty enumeration Qt.labs.controls::StackView::status + \readonly + + This attached property holds the stack status of the item it's + attached to, or \c StackView.Inactive if the item is not in a stack. + + Available values: + \value StackView.Inactive The item is inactive (or not in a stack). + \value StackView.Deactivating The item is being deactivated (popped off). + \value StackView.Activating The item is being activated (becoming the current item). + \value StackView.Active The item is active, that is, the current item. +*/ +QQuickStackView::Status QQuickStackAttached::status() const +{ + Q_D(const QQuickStackAttached); + return d->element ? d->element->status : QQuickStackView::Inactive; +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickstackview_p.cpp b/src/quicktemplates2/qquickstackview_p.cpp new file mode 100644 index 00000000..196e77e3 --- /dev/null +++ b/src/quicktemplates2/qquickstackview_p.cpp @@ -0,0 +1,549 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickstackview_p_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static QQuickStackAttached *attachedStackObject(QQuickStackElement *element) +{ + QQuickStackAttached *attached = qobject_cast(qmlAttachedPropertiesObject(element->item, false)); + if (attached) + QQuickStackAttachedPrivate::get(attached)->element = element; + return attached; +} + +class QQuickStackIncubator : public QQmlIncubator +{ +public: + QQuickStackIncubator(QQuickStackElement *element) : QQmlIncubator(Synchronous), element(element) { } + +protected: + void setInitialState(QObject *object) override { element->incubate(object); } + +private: + QQuickStackElement *element; +}; + +QQuickStackElement::QQuickStackElement() : QQuickItemViewTransitionableItem(nullptr), + index(-1), init(false), removal(false), ownItem(false), ownComponent(false), widthValid(false), heightValid(false), + context(nullptr), component(nullptr), incubator(nullptr), view(nullptr), + status(QQuickStackView::Inactive) +{ +} + +QQuickStackElement::~QQuickStackElement() +{ + if (item) + QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed); + + if (ownComponent) + delete component; + + if (item) { + if (ownItem) { + item->setParentItem(nullptr); + item->deleteLater(); + item = nullptr; + } else { + item->setVisible(false); + if (item->parentItem() != originalParent) { + item->setParentItem(originalParent); + } else { + QQuickStackAttached *attached = attachedStackObject(this); + if (attached) + QQuickStackAttachedPrivate::get(attached)->itemParentChanged(item, nullptr); + } + } + } + + delete context; + delete incubator; +} + +QQuickStackElement *QQuickStackElement::fromString(const QString &str, QQuickStackView *view) +{ + QQuickStackElement *element = new QQuickStackElement; + element->component = new QQmlComponent(qmlEngine(view), QUrl(str), view); + element->ownComponent = true; + return element; +} + +QQuickStackElement *QQuickStackElement::fromObject(QObject *object, QQuickStackView *view) +{ + QQuickStackElement *element = new QQuickStackElement; + element->component = qobject_cast(object); + if (!element->component) { + element->component = new QQmlComponent(qmlEngine(view), view); + element->ownComponent = true; + } + element->item = qobject_cast(object); + if (element->item) + element->originalParent = element->item->parentItem(); + return element; +} + +bool QQuickStackElement::load(QQuickStackView *parent) +{ + setView(parent); + if (!item) { + ownItem = true; + + QQmlContext *creationContext = component->creationContext(); + if (!creationContext) + creationContext = qmlContext(parent); + context = new QQmlContext(creationContext); + context->setContextObject(parent); + + delete incubator; + incubator = new QQuickStackIncubator(this); + component->create(*incubator, context); + if (component->isError()) + qWarning() << qPrintable(component->errorString().trimmed()); + } else { + initialize(); + } + return item; +} + +void QQuickStackElement::incubate(QObject *object) +{ + item = qmlobject_cast(object); + if (item) { + QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership); + initialize(); + } +} + +void QQuickStackElement::initialize() +{ + if (!item || init) + return; + + QQuickItemPrivate *p = QQuickItemPrivate::get(item); + if (!(widthValid = p->widthValid)) + item->setWidth(view->width()); + if (!(heightValid = p->heightValid)) + item->setHeight(view->height()); + item->setParentItem(view); + p->addItemChangeListener(this, QQuickItemPrivate::Destroyed); + + if (!properties.isUndefined()) { + QQmlComponentPrivate *d = QQmlComponentPrivate::get(component); + Q_ASSERT(d && d->engine); + QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(d->engine); + Q_ASSERT(v4); + QV4::Scope scope(v4); + QV4::ScopedValue ipv(scope, properties.value()); + d->initializeObjectWithInitialProperties(ipv, item); + properties.clear(); + } + + init = true; +} + +void QQuickStackElement::setIndex(int value) +{ + if (index == value) + return; + + index = value; + QQuickStackAttached *attached = attachedStackObject(this); + if (attached) + emit attached->indexChanged(); +} + +void QQuickStackElement::setView(QQuickStackView *value) +{ + if (view == value) + return; + + view = value; + QQuickStackAttached *attached = attachedStackObject(this); + if (attached) + emit attached->viewChanged(); +} + +void QQuickStackElement::setStatus(QQuickStackView::Status value) +{ + if (status == value) + return; + + status = value; + QQuickStackAttached *attached = attachedStackObject(this); + if (attached) + emit attached->statusChanged(); +} + +void QQuickStackElement::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget) +{ + if (transitioner) + transitioner->transitionNextReposition(this, type, asTarget); +} + +bool QQuickStackElement::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds) +{ + if (transitioner) { + if (item) { + QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors; + // TODO: expose QQuickAnchorLine so we can test for other conflicting anchors + if (anchors && (anchors->fill() || anchors->centerIn())) + qmlInfo(item) << "StackView has detected conflicting anchors. Transitions may not execute properly."; + } + + // TODO: add force argument to QQuickItemViewTransitionableItem::prepareTransition()? + nextTransitionToSet = true; + nextTransitionFromSet = true; + nextTransitionFrom += QPointF(1, 1); + return QQuickItemViewTransitionableItem::prepareTransition(transitioner, index, viewBounds); + } + return false; +} + +void QQuickStackElement::startTransition(QQuickItemViewTransitioner *transitioner) +{ + if (transitioner) + QQuickItemViewTransitionableItem::startTransition(transitioner, index); +} + +void QQuickStackElement::itemDestroyed(QQuickItem *) +{ + item = nullptr; +} + +QQuickStackViewPrivate::QQuickStackViewPrivate() : busy(false), currentItem(nullptr), transitioner(nullptr) +{ +} + +void QQuickStackViewPrivate::setCurrentItem(QQuickItem *item) +{ + Q_Q(QQuickStackView); + if (currentItem == item) + return; + + currentItem = item; + if (item) + item->setVisible(true); + emit q->currentItemChanged(); +} + +static bool initProperties(QQuickStackElement *element, const QV4::Value &props, QQmlV4Function *args) +{ + if (props.isObject()) { + const QV4::QObjectWrapper *wrapper = props.as(); + if (!wrapper) { + QV4::ExecutionEngine *v4 = args->v4engine(); + element->properties.set(v4, props); + return true; + } + } + return false; +} + +QList QQuickStackViewPrivate::parseElements(QQmlV4Function *args, int from) +{ + QV4::ExecutionEngine *v4 = args->v4engine(); + QV4::Scope scope(v4); + + QList elements; + + int argc = args->length(); + for (int i = from; i < argc; ++i) { + QV4::ScopedValue arg(scope, (*args)[i]); + if (QV4::ArrayObject *array = arg->as()) { + int len = array->getLength(); + for (int j = 0; j < len; ++j) { + QV4::ScopedValue value(scope, array->getIndexed(j)); + QQuickStackElement *element = createElement(value); + if (element) { + if (j < len - 1) { + QV4::ScopedValue props(scope, array->getIndexed(j + 1)); + if (initProperties(element, props, args)) + ++j; + } + elements += element; + } + } + } else { + QQuickStackElement *element = createElement(arg); + if (element) { + if (i < argc - 1) { + QV4::ScopedValue props(scope, (*args)[i + 1]); + if (initProperties(element, props, args)) + ++i; + } + elements += element; + } + } + } + return elements; +} + +QQuickStackElement *QQuickStackViewPrivate::findElement(QQuickItem *item) const +{ + if (item) { + for (QQuickStackElement *e : qAsConst(elements)) { + if (e->item == item) + return e; + } + } + return nullptr; +} + +QQuickStackElement *QQuickStackViewPrivate::findElement(const QV4::Value &value) const +{ + if (const QV4::QObjectWrapper *o = value.as()) + return findElement(qobject_cast(o->object())); + return nullptr; +} + +QQuickStackElement *QQuickStackViewPrivate::createElement(const QV4::Value &value) +{ + Q_Q(QQuickStackView); + if (const QV4::String *s = value.as()) + return QQuickStackElement::fromString(s->toQString(), q); + if (const QV4::QObjectWrapper *o = value.as()) + return QQuickStackElement::fromObject(o->object(), q); + return nullptr; +} + +bool QQuickStackViewPrivate::pushElements(const QList &elems) +{ + Q_Q(QQuickStackView); + if (!elems.isEmpty()) { + for (QQuickStackElement *e : elems) { + e->setIndex(elements.count()); + elements += e; + } + return elements.top()->load(q); + } + return false; +} + +bool QQuickStackViewPrivate::pushElement(QQuickStackElement *element) +{ + if (element) + return pushElements(QList() << element); + return false; +} + +bool QQuickStackViewPrivate::popElements(QQuickStackElement *element) +{ + Q_Q(QQuickStackView); + while (elements.count() > 1 && elements.top() != element) { + delete elements.pop(); + if (!element) + break; + } + return elements.top()->load(q); +} + +bool QQuickStackViewPrivate::replaceElements(QQuickStackElement *target, const QList &elems) +{ + if (target) { + while (!elements.isEmpty()) { + QQuickStackElement* top = elements.pop(); + delete top; + if (top == target) + break; + } + } + return pushElements(elems); +} + +void QQuickStackViewPrivate::ensureTransitioner() +{ + if (!transitioner) { + transitioner = new QQuickItemViewTransitioner; + transitioner->setChangeListener(this); + } +} + +void QQuickStackViewPrivate::popTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate) +{ + ensureTransitioner(); + + if (exit) { + exit->removal = true; + exit->setStatus(QQuickStackView::Deactivating); + exit->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, true); + } + if (enter) { + enter->setStatus(QQuickStackView::Activating); + enter->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false); + } + + if (exit) { + if (immediate || !exit->item || !exit->prepareTransition(transitioner, viewBounds)) + completeTransition(exit, transitioner->removeTransition); + else + exit->startTransition(transitioner); + } + if (enter) { + if (immediate || !enter->item || !enter->prepareTransition(transitioner, QRectF())) + completeTransition(enter, transitioner->removeDisplacedTransition); + else + enter->startTransition(transitioner); + } + + if (transitioner) { + setBusy(!transitioner->runningJobs.isEmpty()); + transitioner->resetTargetLists(); + } +} + +void QQuickStackViewPrivate::pushTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate) +{ + ensureTransitioner(); + + if (enter) { + enter->setStatus(QQuickStackView::Activating); + enter->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true); + } + if (exit) { + exit->setStatus(QQuickStackView::Deactivating); + exit->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, false); + } + + if (enter) { + if (immediate || !enter->item || !enter->prepareTransition(transitioner, viewBounds)) + completeTransition(enter, transitioner->addTransition); + else + enter->startTransition(transitioner); + } + if (exit) { + if (immediate || !exit->item || !exit->prepareTransition(transitioner, QRectF())) + completeTransition(exit, transitioner->addDisplacedTransition); + else + exit->startTransition(transitioner); + } + + if (transitioner) { + setBusy(!transitioner->runningJobs.isEmpty()); + transitioner->resetTargetLists(); + } +} + +void QQuickStackViewPrivate::replaceTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate) +{ + ensureTransitioner(); + + if (exit) { + exit->removal = true; + exit->setStatus(QQuickStackView::Deactivating); + exit->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false); + } + if (enter) { + enter->setStatus(QQuickStackView::Activating); + enter->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, true); + } + + if (exit) { + if (immediate || !exit->item || !exit->prepareTransition(transitioner, QRectF())) + completeTransition(exit, transitioner->moveDisplacedTransition); + else + exit->startTransition(transitioner); + } + if (enter) { + if (immediate || !enter->item || !enter->prepareTransition(transitioner, viewBounds)) + completeTransition(enter, transitioner->moveTransition); + else + enter->startTransition(transitioner); + } + + if (transitioner) { + setBusy(!transitioner->runningJobs.isEmpty()); + transitioner->resetTargetLists(); + } +} + +void QQuickStackViewPrivate::completeTransition(QQuickStackElement *element, QQuickTransition *transition) +{ + if (transition) { + // TODO: add a proper way to complete a transition + QQmlListProperty animations = transition->animations(); + int count = animations.count(&animations); + for (int i = 0; i < count; ++i) { + QQuickAbstractAnimation *anim = animations.at(&animations, i); + anim->complete(); + } + } + viewItemTransitionFinished(element); +} + +void QQuickStackViewPrivate::viewItemTransitionFinished(QQuickItemViewTransitionableItem *transitionable) +{ + QQuickStackElement *element = static_cast(transitionable); + if (element->status == QQuickStackView::Activating) { + element->setStatus(QQuickStackView::Active); + } else if (element->status == QQuickStackView::Deactivating) { + element->setStatus(QQuickStackView::Inactive); + if (element->item) + element->item->setVisible(false); + if (element->removal || element->isPendingRemoval()) + removals += element; + } + + if (transitioner->runningJobs.isEmpty()) { + qDeleteAll(removals); + removals.clear(); + setBusy(false); + } +} + +void QQuickStackViewPrivate::setBusy(bool b) +{ + Q_Q(QQuickStackView); + if (busy == b) + return; + + busy = b; + q->setFiltersChildMouseEvents(busy); + emit q->busyChanged(); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickstackview_p.h b/src/quicktemplates2/qquickstackview_p.h new file mode 100644 index 00000000..5b303648 --- /dev/null +++ b/src/quicktemplates2/qquickstackview_p.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSTACKVIEW_P_H +#define QQUICKSTACKVIEW_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQmlV4Function; +class QQuickTransition; +class QQuickStackElement; +class QQuickStackAttached; +class QQuickStackViewPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickStackView : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(bool busy READ isBusy NOTIFY busyChanged FINAL) + Q_PROPERTY(int depth READ depth NOTIFY depthChanged FINAL) + Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL) + Q_PROPERTY(QVariant initialItem READ initialItem WRITE setInitialItem FINAL) + Q_PROPERTY(QQuickTransition *popEnter READ popEnter WRITE setPopEnter NOTIFY popEnterChanged FINAL) + Q_PROPERTY(QQuickTransition *popExit READ popExit WRITE setPopExit NOTIFY popExitChanged FINAL) + Q_PROPERTY(QQuickTransition *pushEnter READ pushEnter WRITE setPushEnter NOTIFY pushEnterChanged FINAL) + Q_PROPERTY(QQuickTransition *pushExit READ pushExit WRITE setPushExit NOTIFY pushExitChanged FINAL) + Q_PROPERTY(QQuickTransition *replaceEnter READ replaceEnter WRITE setReplaceEnter NOTIFY replaceEnterChanged FINAL) + Q_PROPERTY(QQuickTransition *replaceExit READ replaceExit WRITE setReplaceExit NOTIFY replaceExitChanged FINAL) + +public: + explicit QQuickStackView(QQuickItem *parent = nullptr); + ~QQuickStackView(); + + static QQuickStackAttached *qmlAttachedProperties(QObject *object); + + bool isBusy() const; + int depth() const; + QQuickItem *currentItem() const; + + enum Status { + Inactive = 0, + Deactivating = 1, + Activating = 2, + Active = 3 + }; + Q_ENUM(Status) + + QVariant initialItem() const; + void setInitialItem(const QVariant &item); + + QQuickTransition *popEnter() const; + void setPopEnter(QQuickTransition *enter); + + QQuickTransition *popExit() const; + void setPopExit(QQuickTransition *exit); + + QQuickTransition *pushEnter() const; + void setPushEnter(QQuickTransition *enter); + + QQuickTransition *pushExit() const; + void setPushExit(QQuickTransition *exit); + + QQuickTransition *replaceEnter() const; + void setReplaceEnter(QQuickTransition *enter); + + QQuickTransition *replaceExit() const; + void setReplaceExit(QQuickTransition *exit); + + enum LoadBehavior { + DontLoad, + ForceLoad + }; + Q_ENUM(LoadBehavior) + + Q_INVOKABLE QQuickItem *get(int index, LoadBehavior behavior = DontLoad); + Q_INVOKABLE QQuickItem *find(const QJSValue &callback, LoadBehavior behavior = DontLoad); + + enum Operation { + Transition, + Immediate + }; + Q_ENUM(Operation) + + Q_INVOKABLE void push(QQmlV4Function *args); + Q_INVOKABLE void pop(QQmlV4Function *args); + Q_INVOKABLE void replace(QQmlV4Function *args); + +public Q_SLOTS: + void clear(); + +Q_SIGNALS: + void busyChanged(); + void depthChanged(); + void currentItemChanged(); + void popEnterChanged(); + void popExitChanged(); + void pushEnterChanged(); + void pushExitChanged(); + void replaceEnterChanged(); + void replaceExitChanged(); + +protected: + void componentComplete() override; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + bool childMouseEventFilter(QQuickItem *, QEvent *) override; + +private: + Q_DISABLE_COPY(QQuickStackView) + Q_DECLARE_PRIVATE(QQuickStackView) +}; + +class QQuickStackAttachedPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickStackAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL) + Q_PROPERTY(QQuickStackView *view READ view NOTIFY viewChanged FINAL) + Q_PROPERTY(QQuickStackView::Status status READ status NOTIFY statusChanged FINAL) + +public: + explicit QQuickStackAttached(QQuickItem *parent = nullptr); + ~QQuickStackAttached(); + + int index() const; + QQuickStackView *view() const; + QQuickStackView::Status status() const; + +Q_SIGNALS: + void indexChanged(); + void viewChanged(); + void statusChanged(); + +private: + Q_DISABLE_COPY(QQuickStackAttached) + Q_DECLARE_PRIVATE(QQuickStackAttached) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickStackView) +QML_DECLARE_TYPEINFO(QQuickStackView, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QQUICKSTACKVIEW_P_H diff --git a/src/quicktemplates2/qquickstackview_p_p.h b/src/quicktemplates2/qquickstackview_p_p.h new file mode 100644 index 00000000..a0a7f77a --- /dev/null +++ b/src/quicktemplates2/qquickstackview_p_p.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSTACKVIEW_P_P_H +#define QQUICKSTACKVIEW_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQmlContext; +class QQmlComponent; +class QQmlIncubator; + +class QQuickStackElement : public QQuickItemViewTransitionableItem, public QQuickItemChangeListener +{ + QQuickStackElement(); + +public: + ~QQuickStackElement(); + + static QQuickStackElement *fromString(const QString &str, QQuickStackView *view); + static QQuickStackElement *fromObject(QObject *object, QQuickStackView *view); + + bool load(QQuickStackView *parent); + void incubate(QObject *object); + void initialize(); + + void setIndex(int index); + void setView(QQuickStackView *view); + void setStatus(QQuickStackView::Status status); + + void transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget); + bool prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds); + void startTransition(QQuickItemViewTransitioner *transitioner); + + void itemDestroyed(QQuickItem *item) override; + + int index; + bool init; + bool removal; + bool ownItem; + bool ownComponent; + bool widthValid; + bool heightValid; + QQmlContext *context; + QQmlComponent *component; + QQmlIncubator *incubator; + QQuickStackView *view; + QPointer originalParent; + QQuickStackView::Status status; + QV4::PersistentValue properties; +}; + +class QQuickStackViewPrivate : public QQuickControlPrivate, public QQuickItemViewTransitionChangeListener +{ + Q_DECLARE_PUBLIC(QQuickStackView) + +public: + QQuickStackViewPrivate(); + + static QQuickStackViewPrivate *get(QQuickStackView *view) + { + return view->d_func(); + } + + void setCurrentItem(QQuickItem *item); + + QList parseElements(QQmlV4Function *args, int from = 0); + QQuickStackElement *findElement(QQuickItem *item) const; + QQuickStackElement *findElement(const QV4::Value &value) const; + QQuickStackElement *createElement(const QV4::Value &value); + bool pushElements(const QList &elements); + bool pushElement(QQuickStackElement *element); + bool popElements(QQuickStackElement *element); + bool replaceElements(QQuickStackElement *element, const QList &elements); + + void ensureTransitioner(); + void popTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate); + void pushTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate); + void replaceTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate); + void completeTransition(QQuickStackElement *element, QQuickTransition *transition); + + void viewItemTransitionFinished(QQuickItemViewTransitionableItem *item) override; + void setBusy(bool busy); + + bool busy; + QVariant initialItem; + QQuickItem *currentItem; + QList removals; + QStack elements; + QQuickItemViewTransitioner *transitioner; +}; + +class QQuickStackAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickStackAttached) + +public: + QQuickStackAttachedPrivate() : element(nullptr) { } + + static QQuickStackAttachedPrivate *get(QQuickStackAttached *attached) + { + return attached->d_func(); + } + + void itemParentChanged(QQuickItem *item, QQuickItem *parent); + + QQuickStackElement *element; +}; + +QT_END_NAMESPACE + +#endif // QQUICKSTACKVIEW_P_P_H diff --git a/src/quicktemplates2/qquickswipedelegate.cpp b/src/quicktemplates2/qquickswipedelegate.cpp new file mode 100644 index 00000000..064aebb7 --- /dev/null +++ b/src/quicktemplates2/qquickswipedelegate.cpp @@ -0,0 +1,855 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickswipedelegate_p.h" +#include "qquickcontrol_p_p.h" +#include "qquickabstractbutton_p_p.h" +#include "qquickvelocitycalculator_p_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype SwipeDelegate + \inherits AbstractButton + \instantiates QQuickSwipeDelegate + \inqmlmodule Qt.labs.controls + \brief A swipable item delegate. + + SwipeDelegate presents a view item that can be swiped left or right to + expose more options or information. It is used as a delegate in views such + as \l ListView. + + SwipeDelegate inherits its API from AbstractButton. For instance, you can set + \l {AbstractButton::text}{text}, make items \l {AbstractButton::checkable}{checkable}, + and react to \l {AbstractButton::clicked}{clicks} using the AbstractButton API. + + Information regarding the progress of a swipe, as well as the components + that should be shown upon swiping, are both available through the + \l {SwipeDelegate::}{exposure} grouped property object. For example, + \c exposure.position holds the position of the + swipe within the range \c -1.0 to \c 1.0. The \c exposure.left + property determines which item will be displayed when the control is swiped + to the right, and vice versa for \c exposure.right. The positioning of these + components is left to applications to decide. For example, without specifying + any position for \c exposure.left or \c exposure.right, the following will + occur: + + \image qtquickcontrols-swipedelegate.gif + + If \c exposure.left and \c exposure.right are anchored to the left and + right of the \l background item (respectively), they'll behave like this: + + \image qtquickcontrols-swipedelegate-leading-trailing.gif + + When using \c exposure.left and \c exposure.right, the control cannot be + swiped past the left and right edges. To achieve this type of "wrapping" + behavior, set \c exposure.behind instead. This will result in the same + item being shown regardless of which direction the control is swiped. For + example, in the image below, we set \c exposure.behind and then swipe the + control repeatedly in both directions: + + \image qtquickcontrols-swipedelegate-behind.gif + + \labs + + \sa {Customizing SwipeDelegate} +*/ + +class QQuickSwipeExposurePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QQuickSwipeExposure) + +public: + QQuickSwipeExposurePrivate(QQuickSwipeDelegate *control) : + control(control), + positionBeforePress(0), + position(0), + wasActive(false), + active(false), + left(nullptr), + behind(nullptr), + right(nullptr), + leftItem(nullptr), + behindItem(nullptr), + rightItem(nullptr) + { + } + + static QQuickSwipeExposurePrivate *get(QQuickSwipeExposure *exposure); + + QQuickItem *createDelegateItem(QQmlComponent *component); + QQuickItem *showRelevantItemForPosition(qreal position); + QQuickItem *createRelevantItemForDistance(qreal distance); + void createLeftItem(); + void createBehindItem(); + void createRightItem(); + void createAndShowLeftItem(); + void createAndShowBehindItem(); + void createAndShowRightItem(); + + void warnAboutMixingDelegates(); + void warnAboutSettingDelegatesWhileVisible(); + + QQuickSwipeDelegate *control; + // Same range as position, but is set before press events so that we can + // keep track of which direction the user must swipe when using left and right delegates. + qreal positionBeforePress; + qreal position; + // A "less strict" version of active that is true if active was true + // before the last press event. + bool wasActive; + bool active; + QQuickVelocityCalculator velocityCalculator; + QQmlComponent *left; + QQmlComponent *behind; + QQmlComponent *right; + QQuickItem *leftItem; + QQuickItem *behindItem; + QQuickItem *rightItem; +}; + +QQuickSwipeExposurePrivate *QQuickSwipeExposurePrivate::get(QQuickSwipeExposure *exposure) +{ + return exposure->d_func(); +} + +QQuickItem *QQuickSwipeExposurePrivate::createDelegateItem(QQmlComponent *component) +{ + // If we don't use the correct context, it won't be possible to refer to + // the control's id from within the delegates. + QQmlContext *creationContext = component->creationContext(); + // The component might not have been created in QML, in which case + // the creation context will be null and we have to create it ourselves. + if (!creationContext) + creationContext = qmlContext(control); + QQmlContext *context = new QQmlContext(creationContext); + context->setContextObject(control); + QQuickItem *item = qobject_cast(component->beginCreate(context)); + if (item) { + item->setParentItem(control); + component->completeCreate(); + } + return item; +} + +QQuickItem *QQuickSwipeExposurePrivate::showRelevantItemForPosition(qreal position) +{ + if (qFuzzyIsNull(position)) + return nullptr; + + if (behind) { + createAndShowBehindItem(); + return behindItem; + } + + if (right && position < 0.0) { + createAndShowRightItem(); + return rightItem; + } + + if (left && position > 0.0) { + createAndShowLeftItem(); + return leftItem; + } + + return nullptr; +} + +QQuickItem *QQuickSwipeExposurePrivate::createRelevantItemForDistance(qreal distance) +{ + if (qFuzzyIsNull(distance)) + return nullptr; + + if (behind) { + createBehindItem(); + return behindItem; + } + + // a) If the position before the press was 0.0, we know that *any* movement + // whose distance is negative will result in the right item being shown and + // vice versa. + // b) Once the control has been exposed (that is, swiped to the left or right, + // and hence the position is either -1.0 or 1.0), we must use the width of the + // relevant item to determine if the distance is larger than that item, + // in order to know whether or not to display it. + // c) If the control has been exposed, and the swipe is larger than the width + // of the relevant item from which the swipe started from, we must show the + // item on the other side (if any). + + if (right) { + if ((distance < 0.0 && positionBeforePress == 0.0) /* a) */ + || (rightItem && positionBeforePress == -1.0 && distance < rightItem->width()) /* b) */ + || (leftItem && positionBeforePress == 1.0 && qAbs(distance) > leftItem->width())) /* c) */ { + createRightItem(); + return rightItem; + } + } + + if (left) { + if ((distance > 0.0 && positionBeforePress == 0.0) /* a) */ + || (leftItem && positionBeforePress == 1.0 && qAbs(distance) < leftItem->width()) /* b) */ + || (rightItem && positionBeforePress == -1.0 && qAbs(distance) > rightItem->width())) /* c) */ { + createLeftItem(); + return leftItem; + } + } + + return nullptr; +} + +void QQuickSwipeExposurePrivate::createLeftItem() +{ + if (!leftItem) { + Q_Q(QQuickSwipeExposure); + q->setLeftItem(createDelegateItem(left)); + if (!leftItem) + qmlInfo(control) << "Failed to create left item:" << left->errors(); + } +} + +void QQuickSwipeExposurePrivate::createBehindItem() +{ + if (!behindItem) { + Q_Q(QQuickSwipeExposure); + q->setBehindItem(createDelegateItem(behind)); + if (!behindItem) + qmlInfo(control) << "Failed to create behind item:" << behind->errors(); + } +} + +void QQuickSwipeExposurePrivate::createRightItem() +{ + if (!rightItem) { + Q_Q(QQuickSwipeExposure); + q->setRightItem(createDelegateItem(right)); + if (!rightItem) + qmlInfo(control) << "Failed to create right item:" << right->errors(); + } +} + +void QQuickSwipeExposurePrivate::createAndShowLeftItem() +{ + createLeftItem(); + + if (leftItem) + leftItem->setVisible(true); + + if (rightItem) + rightItem->setVisible(false); +} + +void QQuickSwipeExposurePrivate::createAndShowBehindItem() +{ + createBehindItem(); + + if (behindItem) + behindItem->setVisible(true); +} + +void QQuickSwipeExposurePrivate::createAndShowRightItem() +{ + createRightItem(); + + // This item may have already existed but was hidden. + if (rightItem) + rightItem->setVisible(true); + + // The left item isn't visible when the right item is visible, so save rendering effort by hiding it. + if (leftItem) + leftItem->setVisible(false); +} + +void QQuickSwipeExposurePrivate::warnAboutMixingDelegates() +{ + qmlInfo(control) << "cannot set both behind and left/right properties"; +} + +void QQuickSwipeExposurePrivate::warnAboutSettingDelegatesWhileVisible() +{ + qmlInfo(control) << "left/right/behind properties may only be set when exposure.position is 0"; +} + +QQuickSwipeExposure::QQuickSwipeExposure(QQuickSwipeDelegate *control) : + QObject(*(new QQuickSwipeExposurePrivate(control))) +{ +} + +QQmlComponent *QQuickSwipeExposure::left() const +{ + Q_D(const QQuickSwipeExposure); + return d->left; +} + +void QQuickSwipeExposure::setLeft(QQmlComponent *left) +{ + Q_D(QQuickSwipeExposure); + if (left == d->left) + return; + + if (d->behind) { + d->warnAboutMixingDelegates(); + return; + } + + if (!qFuzzyIsNull(d->position)) { + d->warnAboutSettingDelegatesWhileVisible(); + return; + } + + d->left = left; + + if (!d->left) { + delete d->leftItem; + d->leftItem = nullptr; + } + + emit leftChanged(); +} + +QQmlComponent *QQuickSwipeExposure::behind() const +{ + Q_D(const QQuickSwipeExposure); + return d->behind; +} + +void QQuickSwipeExposure::setBehind(QQmlComponent *behind) +{ + Q_D(QQuickSwipeExposure); + if (behind == d->behind) + return; + + if (d->left || d->right) { + d->warnAboutMixingDelegates(); + return; + } + + if (!qFuzzyIsNull(d->position)) { + d->warnAboutSettingDelegatesWhileVisible(); + return; + } + + d->behind = behind; + + if (!d->behind) { + delete d->behindItem; + d->behindItem = nullptr; + } + + emit behindChanged(); +} + +QQmlComponent *QQuickSwipeExposure::right() const +{ + Q_D(const QQuickSwipeExposure); + return d->right; +} + +void QQuickSwipeExposure::setRight(QQmlComponent *right) +{ + Q_D(QQuickSwipeExposure); + if (right == d->right) + return; + + if (d->behind) { + d->warnAboutMixingDelegates(); + return; + } + + if (!qFuzzyIsNull(d->position)) { + d->warnAboutSettingDelegatesWhileVisible(); + return; + } + + d->right = right; + + if (!d->right) { + delete d->rightItem; + d->rightItem = nullptr; + } + + emit rightChanged(); +} + +QQuickItem *QQuickSwipeExposure::leftItem() const +{ + Q_D(const QQuickSwipeExposure); + return d->leftItem; +} + +void QQuickSwipeExposure::setLeftItem(QQuickItem *item) +{ + Q_D(QQuickSwipeExposure); + if (item == d->leftItem) + return; + + delete d->leftItem; + d->leftItem = item; + + if (d->leftItem) { + d->leftItem->setParentItem(d->control); + + if (qFuzzyIsNull(d->leftItem->z())) + d->leftItem->setZ(-2); + } + + emit leftItemChanged(); +} + +QQuickItem *QQuickSwipeExposure::behindItem() const +{ + Q_D(const QQuickSwipeExposure); + return d->behindItem; +} + +void QQuickSwipeExposure::setBehindItem(QQuickItem *item) +{ + Q_D(QQuickSwipeExposure); + if (item == d->behindItem) + return; + + delete d->behindItem; + d->behindItem = item; + + if (d->behindItem) { + d->behindItem->setParentItem(d->control); + + if (qFuzzyIsNull(d->behindItem->z())) + d->behindItem->setZ(-2); + } + + emit behindItemChanged(); +} + +QQuickItem *QQuickSwipeExposure::rightItem() const +{ + Q_D(const QQuickSwipeExposure); + return d->rightItem; +} + +void QQuickSwipeExposure::setRightItem(QQuickItem *item) +{ + Q_D(QQuickSwipeExposure); + if (item == d->rightItem) + return; + + delete d->rightItem; + d->rightItem = item; + + if (d->rightItem) { + d->rightItem->setParentItem(d->control); + + if (qFuzzyIsNull(d->rightItem->z())) + d->rightItem->setZ(-2); + } + + emit rightItemChanged(); +} + +qreal QQuickSwipeExposure::position() const +{ + Q_D(const QQuickSwipeExposure); + return d->position; +} + +void QQuickSwipeExposure::setPosition(qreal position) +{ + Q_D(QQuickSwipeExposure); + const qreal adjustedPosition = qBound(-1.0, position, 1.0); + if (adjustedPosition == d->position) + return; + + d->position = adjustedPosition; + + QQuickItem *relevantItem = d->showRelevantItemForPosition(d->position); + const qreal relevantWidth = relevantItem ? relevantItem->width() : 0.0; + d->control->contentItem()->setProperty("x", d->position * relevantWidth + d->control->leftPadding()); + if (QQuickItem *background = d->control->background()) + background->setProperty("x", d->position * relevantWidth); + + emit positionChanged(); +} + +bool QQuickSwipeExposure::isActive() const +{ + Q_D(const QQuickSwipeExposure); + return d->active; +} + +void QQuickSwipeExposure::setActive(bool active) +{ + Q_D(QQuickSwipeExposure); + if (active == d->active) + return; + + d->active = active; + emit activeChanged(); +} + +class QQuickSwipeDelegatePrivate : public QQuickAbstractButtonPrivate +{ + Q_DECLARE_PUBLIC(QQuickSwipeDelegate) + +public: + QQuickSwipeDelegatePrivate(QQuickSwipeDelegate *control) : + exposure(control) + { + } + + bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); + bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); + bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); + + void resizeContent() override; + + QQuickSwipeExposure exposure; +}; + +bool QQuickSwipeDelegatePrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) +{ + Q_Q(QQuickSwipeDelegate); + QQuickSwipeExposurePrivate *exposurePrivate = QQuickSwipeExposurePrivate::get(&exposure); + // If the position is 0, we want to handle events ourself - we don't want child items to steal them. + // This code will only get called when a child item has been created; + // events will go through the regular channels (mousePressEvent()) until then. + if (qFuzzyIsNull(exposurePrivate->position)) { + q->mousePressEvent(event); + return true; + } + + exposurePrivate->positionBeforePress = exposurePrivate->position; + exposurePrivate->velocityCalculator.startMeasuring(event->pos(), event->timestamp()); + pressPoint = item->mapToItem(q, event->pos()); + return false; +} + +bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event) +{ + Q_Q(QQuickSwipeDelegate); + + if (autoRepeat) { + stopPressRepeat(); + } else if (holdTimer > 0) { + if (QLineF(pressPoint, event->localPos()).length() > QGuiApplication::styleHints()->startDragDistance()) + stopPressAndHold(); + } + + // Protect against division by zero. + if (width == 0) + return false; + + // Don't bother reacting to events if we don't have any delegates. + QQuickSwipeExposurePrivate *exposurePrivate = QQuickSwipeExposurePrivate::get(&exposure); + if (!exposurePrivate->left && !exposurePrivate->right && !exposurePrivate->behind) + return false; + + // Don't handle move events for the control if it wasn't pressed. + if (item == q && !pressed) + return false; + + const qreal distance = (event->pos() - pressPoint).x(); + if (!q->keepMouseGrab()) { + // Taken from QQuickDrawer::handleMouseMoveEvent; see comments there. + int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5); + const bool overThreshold = QQuickWindowPrivate::dragOverThreshold(distance, Qt::XAxis, event, threshold); + if (window && overThreshold) { + QQuickItem *grabber = q->window()->mouseGrabberItem(); + if (!grabber || !grabber->keepMouseGrab()) { + q->grabMouse(); + q->setKeepMouseGrab(overThreshold); + q->setPressed(true); + exposure.setActive(false); + } + } + } + + if (q->keepMouseGrab()) { + // Ensure we don't try to calculate a position when the user tried to drag + // to the left when the left item is already exposed, and vice versa. + // The code below assumes that the drag is valid, so if we don't have this check, + // the wrong items are visible and the swiping wraps. + if (exposurePrivate->behind + || ((exposurePrivate->left || exposurePrivate->right) + && (qFuzzyIsNull(exposurePrivate->positionBeforePress) + || (exposurePrivate->positionBeforePress == -1.0 && distance >= 0.0) + || (exposurePrivate->positionBeforePress == 1.0 && distance <= 0.0)))) { + + // We must instantiate the items here so that we can calculate the + // position against the width of the relevant item. + QQuickItem *relevantItem = exposurePrivate->createRelevantItemForDistance(distance); + // If there isn't any relevant item, the user may have swiped back to the 0 position, + // or they swiped back to a position that is equal to positionBeforePress. + const qreal normalizedDistance = relevantItem ? distance / relevantItem->width() : 0.0; + qreal position = 0; + + // If the control was exposed before the drag begun, the distance should be inverted. + // For example, if the control had been swiped to the right, the position would be 1.0. + // If the control was then swiped the left by a distance of -20 pixels, the normalized + // distance might be -0.2, for example, which cannot be used as the position; the swipe + // started from the right, so we account for that by adding the position. + if (qFuzzyIsNull(normalizedDistance)) { + // There are two cases when the normalizedDistance can be 0, + // and we must distinguish between them: + // + // a) The swipe returns to the position that it was at before the press event. + // In this case, the distance will be 0. + // There would have been many position changes in the meantime, so we can't just + // ignore the move event; we have to set position to what it was before the press. + // + // b) If the position was at, 1.0, for example, and the control was then swiped + // to the left by the exact width of the left item, there won't be any relevant item + // (because the swipe's position would be at 0.0). In turn, the normalizedDistance + // would be 0 (because of the lack of a relevant item), but the distance will be non-zero. + position = qFuzzyIsNull(distance) ? exposurePrivate->positionBeforePress : 0; + } else if (!exposurePrivate->wasActive) { + position = normalizedDistance; + } else { + position = distance > 0 ? normalizedDistance - 1.0 : normalizedDistance + 1.0; + } + + exposure.setPosition(position); + } + } + + event->accept(); + + return q->keepMouseGrab(); +} + +static const qreal exposeVelocityThreshold = 300.0; + +bool QQuickSwipeDelegatePrivate::handleMouseReleaseEvent(QQuickItem *, QMouseEvent *event) +{ + Q_Q(QQuickSwipeDelegate); + QQuickSwipeExposurePrivate *exposurePrivate = QQuickSwipeExposurePrivate::get(&exposure); + exposurePrivate->velocityCalculator.stopMeasuring(event->pos(), event->timestamp()); + + // The control can be exposed by either swiping past the halfway mark, or swiping fast enough. + const qreal swipeVelocity = exposurePrivate->velocityCalculator.velocity().x(); + if (exposurePrivate->position > 0.5 || + (exposurePrivate->position > 0.0 && swipeVelocity > exposeVelocityThreshold)) { + exposure.setPosition(1.0); + exposure.setActive(true); + exposurePrivate->wasActive = true; + } else if (exposurePrivate->position < -0.5 || + (exposurePrivate->position < 0.0 && swipeVelocity < -exposeVelocityThreshold)) { + exposure.setPosition(-1.0); + exposure.setActive(true); + exposurePrivate->wasActive = true; + } else { + exposure.setPosition(0.0); + exposure.setActive(false); + exposurePrivate->wasActive = false; + } + + q->setKeepMouseGrab(false); + + return true; +} + +void QQuickSwipeDelegatePrivate::resizeContent() +{ + // If the background and contentItem are outside the visible bounds + // of the control (we clip anything outside the bounds), we don't want + // to call QQuickControlPrivate's implementation of this function, + // as it repositions the contentItem to be visible. + QQuickSwipeExposurePrivate *exposurePrivate = QQuickSwipeExposurePrivate::get(&exposure); + if (!exposurePrivate->active) { + QQuickAbstractButtonPrivate::resizeContent(); + } +} + +QQuickSwipeDelegate::QQuickSwipeDelegate(QQuickItem *parent) : + QQuickAbstractButton(*(new QQuickSwipeDelegatePrivate(this)), parent) +{ + setFiltersChildMouseEvents(true); +} + +/*! + \qmlpropertygroup Qt.labs.controls::SwipeDelegate::exposure + \qmlproperty real Qt.labs.controls::SwipeDelegate::exposure.position + \qmlproperty bool Qt.labs.controls::SwipeDelegate::exposure.active + \qmlproperty Component Qt.labs.controls::SwipeDelegate::exposure.left + \qmlproperty Component Qt.labs.controls::SwipeDelegate::exposure.behind + \qmlproperty Component Qt.labs.controls::SwipeDelegate::exposure.right + \qmlproperty Item Qt.labs.controls::SwipeDelegate::exposure.leftItem + \qmlproperty Item Qt.labs.controls::SwipeDelegate::exposure.behindItem + \qmlproperty Item Qt.labs.controls::SwipeDelegate::exposure.rightItem + + \table + \header + \li Property + \li Description + \row + \li position + \li This property holds the position of the swipe relative to either + side of the control. When this value reaches either + \c -1.0 (left side) or \c 1.0 (right side) and the mouse button is + released, \c active will be \c true. + \row + \li active + \li This property holds whether the control is fully exposed. It is + equivalent to \c {!pressed && (position == -1.0 || position == 1.0)}. + + When active is \c true, any interactive items declared in \l left + or \l right will receive mouse events. + \row + \li left + \li This property holds the left delegate. + + The left delegate sits behind both \l {Control::}{contentItem} and + \l background. When the SwipeDelegate is swiped to the right, this item + will be gradually revealed. + \row + \li behind + \li This property holds the delegate that is shown when the + SwipeDelegate is swiped to both the left and right. + + As with the \c left and \c right delegates, it sits behind both + \l {Control::}{contentItem} and \l background. However, a SwipeDelegate + whose \c behind has been set can be continuously swiped from either + side, and will always show the same item. + \row + \li right + \li This property holds the right delegate. + + The right delegate sits behind both \l {Control::}{contentItem} and + \l background. When the SwipeDelegate is swiped to the left, this item + will be gradually revealed. + \row + \li leftItem + \li This property holds the item instantiated from the \c left component. + + If \c left has not been set, or the position hasn't changed since + creation of the SwipeDelegate, this property will be \c null. + \row + \li behindItem + \li This property holds the item instantiated from the \c behind component. + + If \c behind has not been set, or the position hasn't changed since + creation of the SwipeDelegate, this property will be \c null. + \row + \li rightItem + \li This property holds the item instantiated from the \c right component. + + If \c right has not been set, or the position hasn't changed since + creation of the SwipeDelegate, this property will be \c null. + \endtable + + \sa {Control::}{contentItem}, {Control::}{background} +*/ +QQuickSwipeExposure *QQuickSwipeDelegate::exposure() const +{ + Q_D(const QQuickSwipeDelegate); + return const_cast(&d->exposure); +} + +static bool isChildOrGrandchildOf(QQuickItem *child, QQuickItem *item) +{ + return item && (child == item || item->isAncestorOf(child)); +} + +bool QQuickSwipeDelegate::childMouseEventFilter(QQuickItem *child, QEvent *event) +{ + Q_D(QQuickSwipeDelegate); + // The contentItem is, by default, usually a non-interactive item like Text, and + // the same applies to the background. This means that simply stacking the left/right/behind + // items before these items won't allow us to get mouse events when the control is not currently exposed + // but has been previously. Therefore, we instead call setFiltersChildMouseEvents(true) in the constructor + // and filter out child events only when the child is the left/right/behind item. + const QQuickSwipeExposurePrivate *exposurePrivate = QQuickSwipeExposurePrivate::get(&d->exposure); + if (!isChildOrGrandchildOf(child, exposurePrivate->leftItem) && !isChildOrGrandchildOf(child, exposurePrivate->behindItem) + && !isChildOrGrandchildOf(child, exposurePrivate->rightItem)) { + return false; + } + + switch (event->type()) { + case QEvent::MouseButtonPress: { + return d->handleMousePressEvent(child, static_cast(event)); + } case QEvent::MouseMove: { + return d->handleMouseMoveEvent(child, static_cast(event)); + } case QEvent::MouseButtonRelease: { + // Make sure that the control gets release events if it has created child + // items that are stealing events from it. + QMouseEvent *mouseEvent = static_cast(event); + QQuickAbstractButton::mouseReleaseEvent(mouseEvent); + return d->handleMouseReleaseEvent(child, mouseEvent); + } default: + return false; + } +} + +// We only override this to set positionBeforePress; +// otherwise, it's the same as the base class implementation. +void QQuickSwipeDelegate::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickSwipeDelegate); + QQuickAbstractButton::mousePressEvent(event); + QQuickSwipeExposurePrivate *exposurePrivate = QQuickSwipeExposurePrivate::get(&d->exposure); + exposurePrivate->positionBeforePress = exposurePrivate->position; + exposurePrivate->velocityCalculator.startMeasuring(event->pos(), event->timestamp()); +} + +void QQuickSwipeDelegate::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickSwipeDelegate); + d->handleMouseMoveEvent(this, event); +} + +void QQuickSwipeDelegate::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickSwipeDelegate); + QQuickAbstractButton::mouseReleaseEvent(event); + d->handleMouseReleaseEvent(this, event); +} + +QFont QQuickSwipeDelegate::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::ItemViewFont); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickSwipeDelegate::accessibleRole() const +{ + return QAccessible::ListItem; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickswipedelegate_p.h b/src/quicktemplates2/qquickswipedelegate_p.h new file mode 100644 index 00000000..1febf17e --- /dev/null +++ b/src/quicktemplates2/qquickswipedelegate_p.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSWIPEDELEGATE_P_H +#define QQUICKSWIPEDELEGATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickSwipeDelegatePrivate; +class QQuickSwipeExposure; + +class Q_QUICKTEMPLATES2_EXPORT QQuickSwipeDelegate : public QQuickAbstractButton +{ + Q_OBJECT + Q_PROPERTY(QQuickSwipeExposure *exposure READ exposure CONSTANT) + +public: + explicit QQuickSwipeDelegate(QQuickItem *parent = nullptr); + + QQuickSwipeExposure *exposure() const; + +protected: + bool childMouseEventFilter(QQuickItem *child, QEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + + QFont defaultFont() const override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickSwipeDelegate) + Q_DECLARE_PRIVATE(QQuickSwipeDelegate) +}; + +class QQuickSwipeExposurePrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickSwipeExposure : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL) + Q_PROPERTY(bool active READ isActive NOTIFY activeChanged FINAL) + Q_PROPERTY(QQmlComponent *left READ left WRITE setLeft NOTIFY leftChanged FINAL) + Q_PROPERTY(QQmlComponent *behind READ behind WRITE setBehind NOTIFY behindChanged FINAL) + Q_PROPERTY(QQmlComponent *right READ right WRITE setRight NOTIFY rightChanged FINAL) + Q_PROPERTY(QQuickItem *leftItem READ leftItem NOTIFY leftItemChanged FINAL) + Q_PROPERTY(QQuickItem *behindItem READ behindItem NOTIFY behindItemChanged FINAL) + Q_PROPERTY(QQuickItem *rightItem READ rightItem NOTIFY rightItemChanged FINAL) + +public: + explicit QQuickSwipeExposure(QQuickSwipeDelegate *control); + + qreal position() const; + void setPosition(qreal position); + + bool isActive() const; + void setActive(bool active); + + QQmlComponent *left() const; + void setLeft(QQmlComponent *left); + + QQmlComponent *behind() const; + void setBehind(QQmlComponent *behind); + + QQmlComponent *right() const; + void setRight(QQmlComponent *right); + + QQuickItem *leftItem() const; + void setLeftItem(QQuickItem *item); + + QQuickItem *behindItem() const; + void setBehindItem(QQuickItem *item); + + QQuickItem *rightItem() const; + void setRightItem(QQuickItem *item); + +Q_SIGNALS: + void positionChanged(); + void activeChanged(); + void leftChanged(); + void behindChanged(); + void rightChanged(); + void leftItemChanged(); + void behindItemChanged(); + void rightItemChanged(); + +private: + Q_DISABLE_COPY(QQuickSwipeExposure) + Q_DECLARE_PRIVATE(QQuickSwipeExposure) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickSwipeDelegate) + +#endif // QQUICKSWIPEDELEGATE_P_H diff --git a/src/quicktemplates2/qquickswipeview.cpp b/src/quicktemplates2/qquickswipeview.cpp new file mode 100644 index 00000000..6614ebe2 --- /dev/null +++ b/src/quicktemplates2/qquickswipeview.cpp @@ -0,0 +1,348 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickswipeview_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype SwipeView + \inherits Container + \instantiates QQuickSwipeView + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-navigation + \ingroup qtquickcontrols2-containers + \brief Enables the user to navigate pages by swiping sideways. + + SwipeView provides a swipe-based navigation model. + + \image qtquickcontrols-swipeview-wireframe.png + + SwipeView is populated with a set of pages. One page is visible at a time. + The user can navigate between the pages by swiping sideways. Notice that + SwipeView itself is entirely non-visual. It is recommended to combine it + with PageIndicator, to give the user a visual clue that there are multiple + pages. + + \snippet qtquickcontrols-swipeview-indicator.qml 1 + + As shown above, SwipeView is typically populated with a static set of + pages that are defined inline as children of the view. It is also possible + to \l {Container::addItem()}{add}, \l {Container::insertItem()}{insert}, + \l {Container::moveItem()}{move}, and \l {Container::removeItem()}{remove} + pages dynamically at run time. + + \note SwipeView takes over the geometry management of items added to the + view. Using anchors on the items is not supported, and any \c width + or \c height assignment will be overridden by the view. Notice that + this only applies to the root of the item. Specifying width and height, + or using anchors for its children works as expected. + + \labs + + \sa TabBar, PageIndicator, {Customizing SwipeView}, {Navigation Controls}, {Container Controls} +*/ + +class QQuickSwipeViewPrivate : public QQuickContainerPrivate +{ + Q_DECLARE_PUBLIC(QQuickSwipeView) + +public: + void resizeItem(QQuickItem *item); + void resizeItems(); + + static QQuickSwipeViewPrivate *get(QQuickSwipeView *view); +}; + +void QQuickSwipeViewPrivate::resizeItems() +{ + Q_Q(QQuickSwipeView); + const int count = q->count(); + for (int i = 0; i < count; ++i) { + QQuickItem *item = itemAt(i); + if (item) { + QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors; + // TODO: expose QQuickAnchorLine so we can test for other conflicting anchors + if (anchors && (anchors->fill() || anchors->centerIn()) && !item->property("_q_QQuickSwipeView_warned").toBool()) { + qmlInfo(item) << "SwipeView has detected conflicting anchors. Unable to layout the item."; + item->setProperty("_q_QQuickSwipeView_warned", true); + } + + item->setSize(QSizeF(contentItem->width(), contentItem->height())); + } + } +} + +QQuickSwipeViewPrivate *QQuickSwipeViewPrivate::get(QQuickSwipeView *view) +{ + return view->d_func(); +} + +QQuickSwipeView::QQuickSwipeView(QQuickItem *parent) : + QQuickContainer(*(new QQuickSwipeViewPrivate), parent) +{ + setFlag(ItemIsFocusScope); + setActiveFocusOnTab(true); +} + +QQuickSwipeViewAttached *QQuickSwipeView::qmlAttachedProperties(QObject *object) +{ + QQuickItem *item = qobject_cast(object); + if (!item) { + qWarning() << "SwipeView: attached properties must be accessed from within a child item"; + return nullptr; + } + + return new QQuickSwipeViewAttached(item); +} + +void QQuickSwipeView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickSwipeView); + QQuickContainer::geometryChanged(newGeometry, oldGeometry); + d->resizeItems(); +} + +void QQuickSwipeView::itemAdded(int, QQuickItem *item) +{ + Q_D(QQuickSwipeView); + QQuickItemPrivate::get(item)->setCulled(true); // QTBUG-51078, QTBUG-51669 + if (isComponentComplete()) + item->setSize(QSizeF(d->contentItem->width(), d->contentItem->height())); +} + +/*! + \qmlattachedproperty int Qt.labs.controls::SwipeView::index + \readonly + + This attached property holds the index of each child item in the SwipeView. + + It is attached to each child item of the SwipeView. +*/ + +/*! + \qmlattachedproperty bool Qt.labs.controls::SwipeView::isCurrentItem + \readonly + + This attached property is \c true if this child is the current item. + + It is attached to each child item of the SwipeView. +*/ + +/*! + \qmlattachedproperty SwipeView Qt.labs.controls::SwipeView::view + \readonly + + This attached property holds the view that manages this child item. + + It is attached to each child item of the SwipeView. +*/ + +class QQuickSwipeViewAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickSwipeViewAttached) +public: + QQuickSwipeViewAttachedPrivate(QQuickItem *item) : + item(item), + swipeView(nullptr), + index(-1), + isCurrent(false) + { + } + + ~QQuickSwipeViewAttachedPrivate() { + } + + void updateView(QQuickItem *parent); + + void itemChildAdded(QQuickItem *, QQuickItem *) override; + void itemChildRemoved(QQuickItem *, QQuickItem *) override; + void itemParentChanged(QQuickItem *, QQuickItem *) override; + + void updateIndex(); + void updateIsCurrent(); + + void setView(QQuickSwipeView *view); + void setIndex(int i); + void setIsCurrent(bool current); + + QQuickItem *item; + QQuickSwipeView *swipeView; + int index; + // Better to store this so that we don't need to lump its calculation + // together with index's calculation, as it would otherwise need to know + // the old index to know if it should emit the change signal. + bool isCurrent; +}; + +void QQuickSwipeViewAttachedPrivate::updateIndex() +{ + setIndex(swipeView ? QQuickSwipeViewPrivate::get(swipeView)->contentModel->indexOf(item, nullptr) : -1); +} + +void QQuickSwipeViewAttachedPrivate::updateIsCurrent() +{ + setIsCurrent(swipeView ? swipeView->currentIndex() == index : false); +} + +void QQuickSwipeViewAttachedPrivate::setView(QQuickSwipeView *view) +{ + if (view == swipeView) + return; + + if (swipeView) { + QQuickItemPrivate *p = QQuickItemPrivate::get(swipeView); + p->removeItemChangeListener(this, QQuickItemPrivate::Children); + + disconnect(swipeView, &QQuickSwipeView::currentIndexChanged, + this, &QQuickSwipeViewAttachedPrivate::updateIsCurrent); + disconnect(swipeView, &QQuickSwipeView::contentChildrenChanged, + this, &QQuickSwipeViewAttachedPrivate::updateIndex); + } + + swipeView = view; + + if (swipeView) { + QQuickItemPrivate *p = QQuickItemPrivate::get(swipeView); + p->addItemChangeListener(this, QQuickItemPrivate::Children); + + connect(swipeView, &QQuickSwipeView::currentIndexChanged, + this, &QQuickSwipeViewAttachedPrivate::updateIsCurrent); + connect(swipeView, &QQuickSwipeView::contentChildrenChanged, + this, &QQuickSwipeViewAttachedPrivate::updateIndex); + } + + Q_Q(QQuickSwipeViewAttached); + emit q->viewChanged(); + + updateIndex(); + updateIsCurrent(); +} + +void QQuickSwipeViewAttachedPrivate::setIsCurrent(bool current) +{ + if (current == isCurrent) + return; + + isCurrent = current; + Q_Q(QQuickSwipeViewAttached); + emit q->isCurrentItemChanged(); +} + +void QQuickSwipeViewAttachedPrivate::setIndex(int i) +{ + if (i == index) + return; + + index = i; + Q_Q(QQuickSwipeViewAttached); + emit q->indexChanged(); +} + +void QQuickSwipeViewAttachedPrivate::updateView(QQuickItem *parent) +{ + // parent can be, e.g.: + // - The contentItem of a ListView (typically the case) + // - A non-visual or weird type like TestCase, when child items are created from components + // wherein the attached properties are used + // - null, when the item was removed with removeItem() + QQuickSwipeView *view = nullptr; + if (parent) { + view = qobject_cast(parent); + if (!view) { + if (parent->parentItem() && parent->parentItem()->property("contentItem").isValid()) { + // The parent is the contentItem of some kind of view. + view = qobject_cast(parent->parentItem()->parentItem()); + } + } + } + + setView(view); +} + +void QQuickSwipeViewAttachedPrivate::itemChildAdded(QQuickItem *, QQuickItem *) +{ + updateIndex(); +} + +void QQuickSwipeViewAttachedPrivate::itemChildRemoved(QQuickItem *, QQuickItem *) +{ + updateIndex(); +} + +void QQuickSwipeViewAttachedPrivate::itemParentChanged(QQuickItem *, QQuickItem *parent) +{ + updateView(parent); +} + +QQuickSwipeViewAttached::QQuickSwipeViewAttached(QQuickItem *item) : + QObject(*(new QQuickSwipeViewAttachedPrivate(item)), item) +{ + Q_D(QQuickSwipeViewAttached); + if (item->parentItem()) { + d->updateView(item->parentItem()); + } else { + QQuickItemPrivate *p = QQuickItemPrivate::get(item); + p->addItemChangeListener(d, QQuickItemPrivate::Parent); + } +} + +QQuickSwipeViewAttached::~QQuickSwipeViewAttached() +{ +} + +QQuickSwipeView *QQuickSwipeViewAttached::view() const +{ + Q_D(const QQuickSwipeViewAttached); + return d->swipeView; +} + +int QQuickSwipeViewAttached::index() const +{ + Q_D(const QQuickSwipeViewAttached); + return d->index; +} + +bool QQuickSwipeViewAttached::isCurrentItem() const +{ + Q_D(const QQuickSwipeViewAttached); + return d->swipeView ? d->swipeView->currentIndex() == d->index : false; +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickswipeview_p.h b/src/quicktemplates2/qquickswipeview_p.h new file mode 100644 index 00000000..84f009d3 --- /dev/null +++ b/src/quicktemplates2/qquickswipeview_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSWIPEVIEW_P_H +#define QQUICKSWIPEVIEW_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickSwipeViewAttached; +class QQuickSwipeViewPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickSwipeView : public QQuickContainer +{ + Q_OBJECT + +public: + explicit QQuickSwipeView(QQuickItem *parent = nullptr); + + static QQuickSwipeViewAttached *qmlAttachedProperties(QObject *object); + +protected: + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + void itemAdded(int index, QQuickItem *item) override; + +private: + Q_DISABLE_COPY(QQuickSwipeView) + Q_DECLARE_PRIVATE(QQuickSwipeView) +}; + +class QQuickSwipeViewAttachedPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickSwipeViewAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL) + Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY isCurrentItemChanged FINAL) + Q_PROPERTY(QQuickSwipeView *view READ view NOTIFY viewChanged FINAL) + +public: + explicit QQuickSwipeViewAttached(QQuickItem *delegateItem); + ~QQuickSwipeViewAttached(); + + int index() const; + bool isCurrentItem() const; + QQuickSwipeView *view() const; + +Q_SIGNALS: + void indexChanged(); + void isCurrentItemChanged(); + void viewChanged(); + +private: + Q_DISABLE_COPY(QQuickSwipeViewAttached) + Q_DECLARE_PRIVATE(QQuickSwipeViewAttached) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickSwipeView) +QML_DECLARE_TYPEINFO(QQuickSwipeView, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QQUICKSWIPEVIEW_P_H diff --git a/src/quicktemplates2/qquickswitch.cpp b/src/quicktemplates2/qquickswitch.cpp new file mode 100644 index 00000000..04281a9e --- /dev/null +++ b/src/quicktemplates2/qquickswitch.cpp @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickswitch_p.h" +#include "qquickabstractbutton_p_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Switch + \inherits AbstractButton + \instantiates QQuickSwitch + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-buttons + \brief An option button that can be toggled on or off. + + \image qtquickcontrols-switch.gif + + Switch is an option button that can be dragged or toggled on (checked) or + off (unchecked). Switches are typically used to select between two states. + + \table + \row \li \image qtquickcontrols-switch-normal.png + \li A switch in its normal state. + \row \li \image qtquickcontrols-switch-checked.png + \li A switch that is checked. + \row \li \image qtquickcontrols-switch-focused.png + \li A switch that has active focus. + \row \li \image qtquickcontrols-switch-disabled.png + \li A switch that is disabled. + \endtable + + \code + ColumnLayout { + Switch { + text: qsTr("Wi-Fi") + } + Switch { + text: qsTr("Bluetooth") + } + } + \endcode + + \labs + + \sa {Customizing Switch}, {Button Controls} +*/ + +class QQuickSwitchPrivate : public QQuickAbstractButtonPrivate +{ + Q_DECLARE_PUBLIC(QQuickSwitch) + +public: + QQuickSwitchPrivate() : position(0) { } + + void updatePosition(); + qreal positionAt(const QPoint &point) const; + + bool handleMousePressEvent(QQuickItem *child, QMouseEvent *event); + bool handleMouseMoveEvent(QQuickItem *child, QMouseEvent *event); + bool handleMouseReleaseEvent(QQuickItem *child, QMouseEvent *event); + bool handleMouseUngrabEvent(QQuickItem *child); + + qreal position; + QPoint pressPoint; +}; + +void QQuickSwitchPrivate::updatePosition() +{ + Q_Q(QQuickSwitch); + q->setPosition(checked ? 1.0 : 0.0); +} + +qreal QQuickSwitchPrivate::positionAt(const QPoint &point) const +{ + Q_Q(const QQuickSwitch); + qreal pos = point.x() / indicator->width(); + if (q->isMirrored()) + return 1.0 - pos; + return pos; +} + +bool QQuickSwitchPrivate::handleMousePressEvent(QQuickItem *child, QMouseEvent *event) +{ + Q_Q(QQuickSwitch); + Q_UNUSED(child); + pressPoint = event->pos(); + q->setPressed(true); + event->accept(); + return true; +} + +bool QQuickSwitchPrivate::handleMouseMoveEvent(QQuickItem *child, QMouseEvent *event) +{ + Q_Q(QQuickSwitch); + if (!child->keepMouseGrab()) + child->setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(event->pos().x() - pressPoint.x(), Qt::XAxis, event)); + if (child->keepMouseGrab()) { + q->setPosition(positionAt(event->pos())); + event->accept(); + } + return true; +} + +bool QQuickSwitchPrivate::handleMouseReleaseEvent(QQuickItem *child, QMouseEvent *event) +{ + Q_Q(QQuickSwitch); + pressPoint = QPoint(); + q->setPressed(false); + if (child->keepMouseGrab()) { + q->setChecked(position > 0.5); + q->setPosition(checked ? 1.0 : 0.0); + child->setKeepMouseGrab(false); + event->accept(); + } else { + emit q->clicked(); + event->accept(); + q->toggle(); + } + return true; +} + +bool QQuickSwitchPrivate::handleMouseUngrabEvent(QQuickItem *child) +{ + Q_Q(QQuickSwitch); + Q_UNUSED(child); + pressPoint = QPoint(); + q->setChecked(position > 0.5); + q->setPosition(checked ? 1.0 : 0.0); + q->setPressed(false); + return true; +} + +QQuickSwitch::QQuickSwitch(QQuickItem *parent) : + QQuickAbstractButton(*(new QQuickSwitchPrivate), parent) +{ + setCheckable(true); + setFiltersChildMouseEvents(true); + QObjectPrivate::connect(this, &QQuickAbstractButton::checkedChanged, d_func(), &QQuickSwitchPrivate::updatePosition); +} + +/*! + \qmlproperty real Qt.labs.controls::Switch::position + \readonly + + \input includes/qquickswitch.qdocinc position +*/ +qreal QQuickSwitch::position() const +{ + Q_D(const QQuickSwitch); + return d->position; +} + +void QQuickSwitch::setPosition(qreal position) +{ + Q_D(QQuickSwitch); + position = qBound(0.0, position, 1.0); + if (qFuzzyCompare(d->position, position)) + return; + + d->position = position; + emit positionChanged(); + emit visualPositionChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::Switch::visualPosition + \readonly + + \input includes/qquickswitch.qdocinc visualPosition +*/ +qreal QQuickSwitch::visualPosition() const +{ + Q_D(const QQuickSwitch); + if (isMirrored()) + return 1.0 - d->position; + return d->position; +} + +void QQuickSwitch::mirrorChange() +{ + QQuickAbstractButton::mirrorChange(); + emit visualPositionChanged(); +} + +bool QQuickSwitch::childMouseEventFilter(QQuickItem *child, QEvent *event) +{ + Q_D(QQuickSwitch); + if (child == indicator()) { + switch (event->type()) { + case QEvent::MouseButtonPress: + return d->handleMousePressEvent(child, static_cast(event)); + case QEvent::MouseMove: + return d->handleMouseMoveEvent(child, static_cast(event)); + case QEvent::MouseButtonRelease: + return d->handleMouseReleaseEvent(child, static_cast(event)); + case QEvent::UngrabMouse: + return d->handleMouseUngrabEvent(child); + default: + return false; + } + } + return false; +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickswitch_p.h b/src/quicktemplates2/qquickswitch_p.h new file mode 100644 index 00000000..abf2879f --- /dev/null +++ b/src/quicktemplates2/qquickswitch_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSWITCH_P_H +#define QQUICKSWITCH_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickSwitchPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickSwitch : public QQuickAbstractButton +{ + Q_OBJECT + Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL) + Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL) + +public: + explicit QQuickSwitch(QQuickItem *parent = nullptr); + + qreal position() const; + void setPosition(qreal position); + + qreal visualPosition() const; + +Q_SIGNALS: + void positionChanged(); + void visualPositionChanged(); + +protected: + void mirrorChange() override; + bool childMouseEventFilter(QQuickItem *child, QEvent *event) override; + +private: + Q_DISABLE_COPY(QQuickSwitch) + Q_DECLARE_PRIVATE(QQuickSwitch) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickSwitch) + +#endif // QQUICKSWITCH_P_H diff --git a/src/quicktemplates2/qquickswitchdelegate.cpp b/src/quicktemplates2/qquickswitchdelegate.cpp new file mode 100644 index 00000000..05cee244 --- /dev/null +++ b/src/quicktemplates2/qquickswitchdelegate.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickswitchdelegate_p.h" + +#include "qquickabstractbutton_p_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype SwitchDelegate + \inherits ItemDelegate + \instantiates QQuickSwitchDelegate + \inqmlmodule Qt.labs.controls + \ingroup qtlabscontrols-delegates + \brief An item delegate that can be toggled on or off. + + \image qtquickcontrols-switchdelegate.gif + + SwitchDelegate presents an item delegate that can be toggled on (checked) or + off (unchecked). Switch delegates are typically used to select one or more + options from a set of options. + + The state of the check delegate can be set with the + \l {AbstractButton::}{checked} property. + + \code + ListView { + model: ["Option 1", "Option 2", "Option 3"] + delegate: SwitchDelegate { + text: modelData + } + } + \endcode + + \labs + + \sa {Customizing SwitchDelegate}, {Delegate Controls} +*/ + +class QQuickSwitchDelegatePrivate : public QQuickAbstractButtonPrivate +{ + Q_DECLARE_PUBLIC(QQuickSwitchDelegate) + +public: + QQuickSwitchDelegatePrivate() : + position(0) + { + } + + void updatePosition(); + qreal positionAt(const QPoint &point) const; + + qreal position; +}; + +void QQuickSwitchDelegatePrivate::updatePosition() +{ + Q_Q(QQuickSwitchDelegate); + q->setPosition(checked ? 1.0 : 0.0); +} + +qreal QQuickSwitchDelegatePrivate::positionAt(const QPoint &point) const +{ + Q_Q(const QQuickSwitchDelegate); + qreal pos = point.x() / indicator->width(); + if (q->isMirrored()) + return 1.0 - pos; + return pos; +} + +QQuickSwitchDelegate::QQuickSwitchDelegate(QQuickItem *parent) : + QQuickItemDelegate(*(new QQuickSwitchDelegatePrivate), parent) +{ + setCheckable(true); + + QObjectPrivate::connect(this, &QQuickAbstractButton::checkedChanged, d_func(), &QQuickSwitchDelegatePrivate::updatePosition); +} + +/*! + \qmlproperty real Qt.labs.controls::SwitchDelegate::position + \readonly + + \input includes/qquickswitch.qdocinc position +*/ +qreal QQuickSwitchDelegate::position() const +{ + Q_D(const QQuickSwitchDelegate); + return d->position; +} + +void QQuickSwitchDelegate::setPosition(qreal position) +{ + Q_D(QQuickSwitchDelegate); + position = qBound(0.0, position, 1.0); + if (qFuzzyCompare(d->position, position)) + return; + + d->position = position; + emit positionChanged(); + emit visualPositionChanged(); +} + +/*! + \qmlproperty real Qt.labs.controls::SwitchDelegate::visualPosition + \readonly + + \input includes/qquickswitch.qdocinc visualPosition +*/ +qreal QQuickSwitchDelegate::visualPosition() const +{ + Q_D(const QQuickSwitchDelegate); + if (isMirrored()) + return 1.0 - d->position; + return d->position; +} + +void QQuickSwitchDelegate::mirrorChange() +{ + QQuickItemDelegate::mirrorChange(); + emit visualPositionChanged(); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickswitchdelegate_p.h b/src/quicktemplates2/qquickswitchdelegate_p.h new file mode 100644 index 00000000..1707c55c --- /dev/null +++ b/src/quicktemplates2/qquickswitchdelegate_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSWITCHDELEGATE_P_H +#define QQUICKSWITCHDELEGATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickSwitchDelegatePrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickSwitchDelegate : public QQuickItemDelegate +{ + Q_OBJECT + Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL) + Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL) + +public: + explicit QQuickSwitchDelegate(QQuickItem *parent = nullptr); + + qreal position() const; + void setPosition(qreal position); + + qreal visualPosition() const; + +Q_SIGNALS: + void positionChanged(); + void visualPositionChanged(); + +protected: + void mirrorChange() override; + +private: + Q_DISABLE_COPY(QQuickSwitchDelegate) + Q_DECLARE_PRIVATE(QQuickSwitchDelegate) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickSwitchDelegate) + +#endif // QQUICKSWITCHDELEGATE_P_H diff --git a/src/quicktemplates2/qquicktabbar.cpp b/src/quicktemplates2/qquicktabbar.cpp new file mode 100644 index 00000000..8d6a65f8 --- /dev/null +++ b/src/quicktemplates2/qquicktabbar.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicktabbar_p.h" +#include "qquicktabbutton_p.h" +#include "qquickcontainer_p_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype TabBar + \inherits Container + \instantiates QQuickTabBar + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-navigation + \ingroup qtquickcontrols2-containers + \brief A bar with icons allowing to switch between different views or subtasks. + + TabBar provides a tab-based navigation model. + + \image qtquickcontrols-tabbar-wireframe.png + + TabBar is populated with TabButton controls, and can be used together with + any layout or container control that provides \c currentIndex -property, + such as \l StackLayout or \l SwipeView + + \snippet qtquickcontrols-tabbar.qml 1 + + \labs + + \sa TabButton, {Customizing TabBar}, {Navigation Controls}, {Container Controls} +*/ + +class QQuickTabBarPrivate : public QQuickContainerPrivate +{ + Q_DECLARE_PUBLIC(QQuickTabBar) + +public: + QQuickTabBarPrivate(); + + void updateCurrentItem(); + void updateCurrentIndex(); + void updateLayout(); + + QQuickTabBar::Position position; +}; + +QQuickTabBarPrivate::QQuickTabBarPrivate() : position(QQuickTabBar::Header) +{ +} + +void QQuickTabBarPrivate::updateCurrentItem() +{ + QQuickTabButton *button = qobject_cast(contentModel->get(currentIndex)); + if (button) + button->setChecked(true); +} + +void QQuickTabBarPrivate::updateCurrentIndex() +{ + Q_Q(QQuickTabBar); + QQuickTabButton *button = qobject_cast(q->sender()); + if (button && button->isChecked()) + q->setCurrentIndex(contentModel->indexOf(button, nullptr)); +} + +void QQuickTabBarPrivate::updateLayout() +{ + Q_Q(QQuickTabBar); + const int count = contentModel->count(); + if (count > 0 && contentItem) { + const qreal itemWidth = (contentItem->width() - qMax(0, count - 1) * spacing) / count; + + for (int i = 0; i < count; ++i) { + QQuickItem *item = q->itemAt(i); + if (item) { + QQuickItemPrivate *p = QQuickItemPrivate::get(item); + if (!p->widthValid) { + item->setWidth(itemWidth); + p->widthValid = false; + } + } + } + } +} + +QQuickTabBar::QQuickTabBar(QQuickItem *parent) : + QQuickContainer(*(new QQuickTabBarPrivate), parent) +{ + Q_D(QQuickTabBar); + setFlag(ItemIsFocusScope); + QObjectPrivate::connect(this, &QQuickTabBar::currentIndexChanged, d, &QQuickTabBarPrivate::updateCurrentItem); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::TabBar::position + + This property holds the position of the tab bar. + + \note If the tab bar is assigned as a header or footer of ApplicationWindow + or Page, the appropriate position is set automatically. + + Possible values: + \value TabBar.Header The tab bar is at the top, as a window or page header. + \value TabBar.Footer The tab bar is at the bottom, as a window or page footer. + + The default value is style-specific. + + \sa ApplicationWindow::header, ApplicationWindow::footer, Page::header, Page::footer +*/ +QQuickTabBar::Position QQuickTabBar::position() const +{ + Q_D(const QQuickTabBar); + return d->position; +} + +void QQuickTabBar::setPosition(Position position) +{ + Q_D(QQuickTabBar); + if (d->position == position) + return; + + d->position = position; + emit positionChanged(); +} + +void QQuickTabBar::updatePolish() +{ + Q_D(QQuickTabBar); + QQuickContainer::updatePolish(); + d->updateLayout(); +} + +void QQuickTabBar::componentComplete() +{ + Q_D(QQuickTabBar); + QQuickContainer::componentComplete(); + d->updateCurrentItem(); + d->updateLayout(); +} + +void QQuickTabBar::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickTabBar); + QQuickContainer::geometryChanged(newGeometry, oldGeometry); + d->updateLayout(); +} + +bool QQuickTabBar::isContent(QQuickItem *item) const +{ + return qobject_cast(item); +} + +void QQuickTabBar::itemAdded(int index, QQuickItem *item) +{ + Q_D(QQuickTabBar); + Q_UNUSED(index); + if (QQuickTabButton *button = qobject_cast(item)) + QObjectPrivate::connect(button, &QQuickTabButton::checkedChanged, d, &QQuickTabBarPrivate::updateCurrentIndex); + if (isComponentComplete()) + polish(); +} + +void QQuickTabBar::itemRemoved(int index, QQuickItem *item) +{ + Q_D(QQuickTabBar); + Q_UNUSED(index); + if (QQuickTabButton *button = qobject_cast(item)) + QObjectPrivate::disconnect(button, &QQuickTabButton::checkedChanged, d, &QQuickTabBarPrivate::updateCurrentIndex); + if (isComponentComplete()) + polish(); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickTabBar::accessibleRole() const +{ + return QAccessible::PageTabList; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquicktabbar_p.h b/src/quicktemplates2/qquicktabbar_p.h new file mode 100644 index 00000000..bfc7f2c9 --- /dev/null +++ b/src/quicktemplates2/qquicktabbar_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKTABBAR_P_H +#define QQUICKTABBAR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickTabBarPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickTabBar : public QQuickContainer +{ + Q_OBJECT + Q_PROPERTY(Position position READ position WRITE setPosition NOTIFY positionChanged FINAL) + +public: + explicit QQuickTabBar(QQuickItem *parent = nullptr); + + enum Position { + Header, + Footer + }; + Q_ENUM(Position) + + Position position() const; + void setPosition(Position position); + +Q_SIGNALS: + void positionChanged(); + +protected: + void updatePolish() override; + void componentComplete() override; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + bool isContent(QQuickItem *item) const override; + void itemAdded(int index, QQuickItem *item) override; + void itemRemoved(int index, QQuickItem *item) override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickTabBar) + Q_DECLARE_PRIVATE(QQuickTabBar) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickTabBar) + +#endif // QQUICKTABBAR_P_H diff --git a/src/quicktemplates2/qquicktabbutton.cpp b/src/quicktemplates2/qquicktabbutton.cpp new file mode 100644 index 00000000..fc7cb634 --- /dev/null +++ b/src/quicktemplates2/qquicktabbutton.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicktabbutton_p.h" +#include "qquickcontrol_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype TabButton + \inherits AbstractButton + \instantiates QQuickTabButton + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-navigation + \brief A tab button control that can be found on a TabBar. + + \image qtquickcontrols-tabbutton.png + + TabButton is used in conjunction with a \l TabBar. + + \snippet qtquickcontrols-tabbutton.qml 1 + + \labs + + \sa TabBar, {Customizing TabButton}, {Navigation Controls} +*/ + +QQuickTabButton::QQuickTabButton(QQuickItem *parent) : + QQuickAbstractButton(parent) +{ + setCheckable(true); + setAutoExclusive(true); +} + +QFont QQuickTabButton::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::TabButtonFont); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickTabButton::accessibleRole() const +{ + return QAccessible::PageTab; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquicktabbutton_p.h b/src/quicktemplates2/qquicktabbutton_p.h new file mode 100644 index 00000000..c298e308 --- /dev/null +++ b/src/quicktemplates2/qquicktabbutton_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKTABBUTTON_P_H +#define QQUICKTABBUTTON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class Q_QUICKTEMPLATES2_EXPORT QQuickTabButton : public QQuickAbstractButton +{ + Q_OBJECT + +public: + explicit QQuickTabButton(QQuickItem *parent = nullptr); + +protected: + QFont defaultFont() const override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickTabButton) + +#endif // QQUICKTABBUTTON_P_H diff --git a/src/quicktemplates2/qquicktextarea.cpp b/src/quicktemplates2/qquicktextarea.cpp new file mode 100644 index 00000000..0f3860c9 --- /dev/null +++ b/src/quicktemplates2/qquicktextarea.cpp @@ -0,0 +1,425 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicktextarea_p.h" +#include "qquicktextarea_p_p.h" +#include "qquickcontrol_p.h" +#include "qquickcontrol_p_p.h" + +#include +#include +#include +#include + +#ifndef QT_NO_ACCESSIBILITY +#include +#endif + +QT_BEGIN_NAMESPACE + +/*! + \qmltype TextArea + \inherits TextEdit + \instantiates QQuickTextArea + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-input + \brief A multi line text input control. + + TextArea is a multi-line text editor. TextArea extends TextEdit with + a \l {placeholderText}{placeholder text} functionality, and adds decoration. + + \code + TextArea { + placeholderText: qsTr("Enter description") + } + \endcode + + \labs + + \sa TextField, {Customizing TextArea}, {Input Controls} +*/ + +/*! + \qmlsignal Qt.labs.controls::TextArea::pressAndHold(MouseEvent mouse) + + This signal is emitted when there is a long press (the delay depends on the platform plugin). + The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y + position of the press, and which button is pressed. +*/ + +QQuickTextAreaPrivate::QQuickTextAreaPrivate() + : background(nullptr), focusReason(Qt::OtherFocusReason), accessibleAttached(nullptr) +{ +#ifndef QT_NO_ACCESSIBILITY + QAccessible::installActivationObserver(this); +#endif +} + +QQuickTextAreaPrivate::~QQuickTextAreaPrivate() +{ +#ifndef QT_NO_ACCESSIBILITY + QAccessible::removeActivationObserver(this); +#endif +} + +void QQuickTextAreaPrivate::resizeBackground() +{ + Q_Q(QQuickTextArea); + if (background) { + QQuickItemPrivate *p = QQuickItemPrivate::get(background); + if (!p->widthValid && qFuzzyIsNull(background->x())) { + background->setWidth(q->width()); + p->widthValid = false; + } + if (!p->heightValid && qFuzzyIsNull(background->y())) { + background->setHeight(q->height()); + p->heightValid = false; + } + } +} + +qreal QQuickTextAreaPrivate::getImplicitWidth() const +{ + return QQuickItemPrivate::getImplicitWidth(); +} + +qreal QQuickTextAreaPrivate::getImplicitHeight() const +{ + return QQuickItemPrivate::getImplicitHeight(); +} + +void QQuickTextAreaPrivate::implicitWidthChanged() +{ + Q_Q(QQuickTextArea); + QQuickItemPrivate::implicitWidthChanged(); + emit q->implicitWidthChanged(); +} + +void QQuickTextAreaPrivate::implicitHeightChanged() +{ + Q_Q(QQuickTextArea); + QQuickItemPrivate::implicitHeightChanged(); + emit q->implicitHeightChanged(); +} + +QQuickTextArea::QQuickTextArea(QQuickItem *parent) : + QQuickTextEdit(*(new QQuickTextAreaPrivate), parent) +{ + Q_D(QQuickTextArea); + setActiveFocusOnTab(true); + d->setImplicitResizeEnabled(false); + d->pressHandler.control = this; + QObjectPrivate::connect(this, &QQuickTextEdit::readOnlyChanged, + d, &QQuickTextAreaPrivate::_q_readOnlyChanged); +} + +QQuickTextArea::~QQuickTextArea() +{ +} + +/*! + \internal + + Determine which font is implicitly imposed on this control by its ancestors + and QGuiApplication::font, resolve this against its own font (attributes from + the implicit font are copied over). Then propagate this font to this + control's children. +*/ +void QQuickTextAreaPrivate::resolveFont() +{ + Q_Q(QQuickTextArea); + inheritFont(QQuickControlPrivate::parentFont(q)); +} + +void QQuickTextAreaPrivate::inheritFont(const QFont &f) +{ + Q_Q(QQuickTextArea); + QFont parentFont = font.resolve(f); + parentFont.resolve(font.resolve() | f.resolve()); + + const QFont defaultFont = QQuickControlPrivate::themeFont(QPlatformTheme::EditorFont); + const QFont resolvedFont = parentFont.resolve(defaultFont); + + const bool changed = resolvedFont != sourceFont; + q->QQuickTextEdit::setFont(resolvedFont); + if (changed) + emit q->fontChanged(); +} + +void QQuickTextAreaPrivate::_q_readOnlyChanged(bool isReadOnly) +{ +#ifndef QT_NO_ACCESSIBILITY + if (accessibleAttached) + accessibleAttached->set_readOnly(isReadOnly); +#else + Q_UNUSED(isReadOnly) +#endif +} + +#ifndef QT_NO_ACCESSIBILITY +void QQuickTextAreaPrivate::accessibilityActiveChanged(bool active) +{ + if (accessibleAttached || !active) + return; + + Q_Q(QQuickTextArea); + accessibleAttached = qobject_cast(qmlAttachedPropertiesObject(q, true)); + if (accessibleAttached) { + accessibleAttached->setRole(accessibleRole()); + accessibleAttached->set_readOnly(q->isReadOnly()); + accessibleAttached->setDescription(placeholder); + } else { + qWarning() << "QQuickTextArea: " << q << " QQuickAccessibleAttached object creation failed!"; + } +} + +QAccessible::Role QQuickTextAreaPrivate::accessibleRole() const +{ + return QAccessible::EditableText; +} +#endif + +QFont QQuickTextArea::font() const +{ + return QQuickTextEdit::font(); +} + +void QQuickTextArea::setFont(const QFont &font) +{ + Q_D(QQuickTextArea); + if (d->font.resolve() == font.resolve() && d->font == font) + return; + + d->font = font; + d->resolveFont(); +} + +/*! + \qmlproperty Item Qt.labs.controls::TextArea::background + + This property holds the background item. + + \note If the background item has no explicit size specified, it automatically + follows the control's size. In most cases, there is no need to specify + width or height for a background item. + + \sa {Customizing TextArea} +*/ +QQuickItem *QQuickTextArea::background() const +{ + Q_D(const QQuickTextArea); + return d->background; +} + +void QQuickTextArea::setBackground(QQuickItem *background) +{ + Q_D(QQuickTextArea); + if (d->background == background) + return; + + delete d->background; + d->background = background; + if (background) { + background->setParentItem(this); + if (qFuzzyIsNull(background->z())) + background->setZ(-1); + if (isComponentComplete()) + d->resizeBackground(); + } + emit backgroundChanged(); +} + +/*! + \qmlproperty string Qt.labs.controls::TextArea::placeholderText + + This property holds the short hint that is displayed in the text area before + the user enters a value. +*/ +QString QQuickTextArea::placeholderText() const +{ + Q_D(const QQuickTextArea); + return d->placeholder; +} + +void QQuickTextArea::setPlaceholderText(const QString &text) +{ + Q_D(QQuickTextArea); + if (d->placeholder == text) + return; + + d->placeholder = text; +#ifndef QT_NO_ACCESSIBILITY + if (d->accessibleAttached) + d->accessibleAttached->setDescription(text); +#endif + emit placeholderTextChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::TextArea::focusReason + + This property holds the reason of the last focus change. + + \note This property does not indicate whether the control has \l {Item::activeFocus} + {active focus}, but the reason why the control either gained or lost focus. + + \value Qt.MouseFocusReason A mouse action occurred. + \value Qt.TabFocusReason The Tab key was pressed. + \value Qt.BacktabFocusReason A Backtab occurred. The input for this may include the Shift or Control keys; e.g. Shift+Tab. + \value Qt.ActiveWindowFocusReason The window system made this window either active or inactive. + \value Qt.PopupFocusReason The application opened/closed a pop-up that grabbed/released the keyboard focus. + \value Qt.ShortcutFocusReason The user typed a label's buddy shortcut + \value Qt.MenuBarFocusReason The menu bar took focus. + \value Qt.OtherFocusReason Another reason, usually application-specific. + + \sa Item::activeFocus +*/ +Qt::FocusReason QQuickTextArea::focusReason() const +{ + Q_D(const QQuickTextArea); + return d->focusReason; +} + +void QQuickTextArea::setFocusReason(Qt::FocusReason reason) +{ + Q_D(QQuickTextArea); + if (d->focusReason == reason) + return; + + d->focusReason = reason; + emit focusReasonChanged(); +} + +void QQuickTextArea::classBegin() +{ + Q_D(QQuickTextArea); + QQuickTextEdit::classBegin(); + d->resolveFont(); +} + +void QQuickTextArea::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) +{ + Q_D(QQuickTextArea); + QQuickTextEdit::itemChange(change, value); + if (change == ItemParentHasChanged && value.item) + d->resolveFont(); +} + +void QQuickTextArea::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickTextArea); + QQuickTextEdit::geometryChanged(newGeometry, oldGeometry); + d->resizeBackground(); +} + +QSGNode *QQuickTextArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) +{ + QQuickDefaultClipNode *clipNode = static_cast(oldNode); + if (!clipNode) + clipNode = new QQuickDefaultClipNode(QRectF()); + + clipNode->setRect(clipRect().adjusted(leftPadding(), topPadding(), -rightPadding(), -bottomPadding())); + clipNode->update(); + + QSGNode *textNode = QQuickTextEdit::updatePaintNode(clipNode->firstChild(), data); + if (!textNode->parent()) + clipNode->appendChildNode(textNode); + + return clipNode; +} + +void QQuickTextArea::focusInEvent(QFocusEvent *event) +{ + QQuickTextEdit::focusInEvent(event); + setFocusReason(event->reason()); +} + +void QQuickTextArea::focusOutEvent(QFocusEvent *event) +{ + QQuickTextEdit::focusOutEvent(event); + setFocusReason(event->reason()); +} + +void QQuickTextArea::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickTextArea); + d->pressHandler.mousePressEvent(event); + if (d->pressHandler.isActive()) { + if (d->pressHandler.delayedMousePressEvent) { + QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent); + d->pressHandler.clearDelayedMouseEvent(); + } + QQuickTextEdit::mousePressEvent(event); + } +} + +void QQuickTextArea::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickTextArea); + d->pressHandler.mouseMoveEvent(event); + if (d->pressHandler.isActive()) { + if (d->pressHandler.delayedMousePressEvent) { + QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent); + d->pressHandler.clearDelayedMouseEvent(); + } + QQuickTextEdit::mouseMoveEvent(event); + } +} + +void QQuickTextArea::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickTextArea); + d->pressHandler.mouseReleaseEvent(event); + if (d->pressHandler.isActive()) { + if (d->pressHandler.delayedMousePressEvent) { + QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent); + d->pressHandler.clearDelayedMouseEvent(); + } + QQuickTextEdit::mouseReleaseEvent(event); + } +} + +void QQuickTextArea::timerEvent(QTimerEvent *event) +{ + Q_D(QQuickTextArea); + if (event->timerId() == d->pressHandler.timer.timerId()) { + d->pressHandler.timerEvent(event); + } else { + QQuickTextEdit::timerEvent(event); + } +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquicktextarea_p.h b/src/quicktemplates2/qquicktextarea_p.h new file mode 100644 index 00000000..d681e8bb --- /dev/null +++ b/src/quicktemplates2/qquicktextarea_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKTEXTAREA_P_H +#define QQUICKTEXTAREA_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickText; +class QQuickTextAreaPrivate; +class QQuickMouseEvent; + +class Q_QUICKTEMPLATES2_EXPORT QQuickTextArea : public QQuickTextEdit +{ + Q_OBJECT + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) // override + Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged FINAL) + Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged FINAL) + Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL) + Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText NOTIFY placeholderTextChanged FINAL) + Q_PROPERTY(Qt::FocusReason focusReason READ focusReason WRITE setFocusReason NOTIFY focusReasonChanged FINAL) + +public: + explicit QQuickTextArea(QQuickItem *parent = nullptr); + ~QQuickTextArea(); + + QFont font() const; + void setFont(const QFont &font); + + QQuickItem *background() const; + void setBackground(QQuickItem *background); + + QString placeholderText() const; + void setPlaceholderText(const QString &text); + + Qt::FocusReason focusReason() const; + void setFocusReason(Qt::FocusReason reason); + +Q_SIGNALS: + void fontChanged(); + void implicitWidthChanged(); + void implicitHeightChanged(); + void backgroundChanged(); + void placeholderTextChanged(); + void focusReasonChanged(); + void pressAndHold(QQuickMouseEvent *event); + +protected: + void classBegin() override; + + void itemChange(ItemChange change, const ItemChangeData &value) override; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) override; + + void focusInEvent(QFocusEvent *event) override; + void focusOutEvent(QFocusEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void timerEvent(QTimerEvent *event) override; + +private: + Q_DISABLE_COPY(QQuickTextArea) + Q_DECLARE_PRIVATE(QQuickTextArea) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickTextArea) + +#endif // QQUICKTEXTAREA_P_H diff --git a/src/quicktemplates2/qquicktextarea_p_p.h b/src/quicktemplates2/qquicktextarea_p_p.h new file mode 100644 index 00000000..8274243f --- /dev/null +++ b/src/quicktemplates2/qquicktextarea_p_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKTEXTAREA_P_P_H +#define QQUICKTEXTAREA_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include "qquicktextarea_p.h" + +#ifndef QT_NO_ACCESSIBILITY +#include +#endif + +QT_BEGIN_NAMESPACE + +class QQuickAccessibleAttached; + +class QQuickTextAreaPrivate : public QQuickTextEditPrivate +#ifndef QT_NO_ACCESSIBILITY + , public QAccessible::ActivationObserver +#endif +{ + Q_DECLARE_PUBLIC(QQuickTextArea) + +public: + QQuickTextAreaPrivate(); + ~QQuickTextAreaPrivate(); + + static QQuickTextAreaPrivate *get(QQuickTextArea *item) { + return static_cast(QObjectPrivate::get(item)); } + + void resizeBackground(); + void resolveFont(); + void inheritFont(const QFont &f); + + qreal getImplicitWidth() const override; + qreal getImplicitHeight() const override; + + void implicitWidthChanged() override; + void implicitHeightChanged() override; + + void _q_readOnlyChanged(bool isReadOnly); + +#ifndef QT_NO_ACCESSIBILITY + void accessibilityActiveChanged(bool active) override; + QAccessible::Role accessibleRole() const override; +#endif + + QFont font; + QQuickItem *background; + QString placeholder; + Qt::FocusReason focusReason; + QQuickPressHandler pressHandler; + QQuickAccessibleAttached *accessibleAttached; +}; + +QT_END_NAMESPACE + +#endif // QQUICKTEXTAREA_P_P_H diff --git a/src/quicktemplates2/qquicktextfield.cpp b/src/quicktemplates2/qquicktextfield.cpp new file mode 100644 index 00000000..7a8dae0d --- /dev/null +++ b/src/quicktemplates2/qquicktextfield.cpp @@ -0,0 +1,450 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicktextfield_p.h" +#include "qquicktextfield_p_p.h" +#include "qquickcontrol_p.h" +#include "qquickcontrol_p_p.h" + +#include +#include +#include +#include +#include + +#ifndef QT_NO_ACCESSIBILITY +#include +#endif + +QT_BEGIN_NAMESPACE + +/*! + \qmltype TextField + \inherits TextInput + \instantiates QQuickTextField + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-input + \brief A single line text input control. + + TextField is a single line text editor. TextField extends TextInput with + a \l {placeholderText}{placeholder text} functionality, and adds decoration. + + \table + \row \li \image qtquickcontrols-textfield-normal.png + \li A text field in its normal state. + \row \li \image qtquickcontrols-textfield-focused.png + \li A text field that has active focus. + \row \li \image qtquickcontrols-textfield-disabled.png + \li A text field that is disabled. + \endtable + + \code + TextField { + placeholderText: qsTr("Enter name") + } + \endcode + + \labs + + \sa TextArea, {Customizing TextField}, {Input Controls} +*/ + +/*! + \qmlsignal Qt.labs.controls::TextField::pressAndHold(MouseEvent mouse) + + This signal is emitted when there is a long press (the delay depends on the platform plugin). + The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y + position of the press, and which button is pressed. +*/ + +QQuickTextFieldPrivate::QQuickTextFieldPrivate() + : background(nullptr) + , focusReason(Qt::OtherFocusReason) + , accessibleAttached(nullptr) +{ +#ifndef QT_NO_ACCESSIBILITY + QAccessible::installActivationObserver(this); +#endif +} + +QQuickTextFieldPrivate::~QQuickTextFieldPrivate() +{ +#ifndef QT_NO_ACCESSIBILITY + QAccessible::removeActivationObserver(this); +#endif +} + +void QQuickTextFieldPrivate::resizeBackground() +{ + Q_Q(QQuickTextField); + if (background) { + QQuickItemPrivate *p = QQuickItemPrivate::get(background); + if (!p->widthValid && qFuzzyIsNull(background->x())) { + background->setWidth(q->width()); + p->widthValid = false; + } + if (!p->heightValid && qFuzzyIsNull(background->y())) { + background->setHeight(q->height()); + p->heightValid = false; + } + } +} + +qreal QQuickTextFieldPrivate::getImplicitWidth() const +{ + return QQuickItemPrivate::getImplicitWidth(); +} + +qreal QQuickTextFieldPrivate::getImplicitHeight() const +{ + return QQuickItemPrivate::getImplicitHeight(); +} + +void QQuickTextFieldPrivate::implicitWidthChanged() +{ + Q_Q(QQuickTextField); + QQuickItemPrivate::implicitWidthChanged(); + emit q->implicitWidthChanged(); +} + +void QQuickTextFieldPrivate::implicitHeightChanged() +{ + Q_Q(QQuickTextField); + QQuickItemPrivate::implicitHeightChanged(); + emit q->implicitHeightChanged(); +} + +QQuickTextField::QQuickTextField(QQuickItem *parent) : + QQuickTextInput(*(new QQuickTextFieldPrivate), parent) +{ + Q_D(QQuickTextField); + d->pressHandler.control = this; + d->setImplicitResizeEnabled(false); + setActiveFocusOnTab(true); + QObjectPrivate::connect(this, &QQuickTextInput::readOnlyChanged, + d, &QQuickTextFieldPrivate::_q_readOnlyChanged); + QObjectPrivate::connect(this, &QQuickTextInput::echoModeChanged, + d, &QQuickTextFieldPrivate::_q_echoModeChanged); +} + +QQuickTextField::~QQuickTextField() +{ +} + +/*! + \internal + + Determine which font is implicitly imposed on this control by its ancestors + and QGuiApplication::font, resolve this against its own font (attributes from + the implicit font are copied over). Then propagate this font to this + control's children. +*/ +void QQuickTextFieldPrivate::resolveFont() +{ + Q_Q(QQuickTextField); + inheritFont(QQuickControlPrivate::parentFont(q)); +} + +void QQuickTextFieldPrivate::inheritFont(const QFont &f) +{ + Q_Q(QQuickTextField); + QFont parentFont = font.resolve(f); + parentFont.resolve(font.resolve() | f.resolve()); + + const QFont defaultFont = QQuickControlPrivate::themeFont(QPlatformTheme::EditorFont); + const QFont resolvedFont = parentFont.resolve(defaultFont); + + const bool changed = resolvedFont != sourceFont; + q->QQuickTextInput::setFont(resolvedFont); + if (changed) + emit q->fontChanged(); +} + +void QQuickTextFieldPrivate::_q_readOnlyChanged(bool isReadOnly) +{ +#ifndef QT_NO_ACCESSIBILITY + if (accessibleAttached) + accessibleAttached->set_readOnly(isReadOnly); +#else + Q_UNUSED(isReadOnly) +#endif +} + +void QQuickTextFieldPrivate::_q_echoModeChanged(QQuickTextField::EchoMode echoMode) +{ +#ifndef QT_NO_ACCESSIBILITY + if (accessibleAttached) + accessibleAttached->set_passwordEdit((echoMode == QQuickTextField::Password || echoMode == QQuickTextField::PasswordEchoOnEdit) ? true : false); +#else + Q_UNUSED(echoMode) +#endif +} + +#ifndef QT_NO_ACCESSIBILITY +void QQuickTextFieldPrivate::accessibilityActiveChanged(bool active) +{ + if (accessibleAttached || !active) + return; + + Q_Q(QQuickTextField); + accessibleAttached = qobject_cast(qmlAttachedPropertiesObject(q, true)); + if (accessibleAttached) { + accessibleAttached->setRole(accessibleRole()); + accessibleAttached->set_readOnly(m_readOnly); + accessibleAttached->set_passwordEdit((m_echoMode == QQuickTextField::Password || m_echoMode == QQuickTextField::PasswordEchoOnEdit) ? true : false); + accessibleAttached->setDescription(placeholder); + } else { + qWarning() << "QQuickTextField: " << q << " QQuickAccessibleAttached object creation failed!"; + } +} + +QAccessible::Role QQuickTextFieldPrivate::accessibleRole() const +{ + return QAccessible::EditableText; +} +#endif + +QFont QQuickTextField::font() const +{ + return QQuickTextInput::font(); +} + +void QQuickTextField::setFont(const QFont &font) +{ + Q_D(QQuickTextField); + if (d->font.resolve() == font.resolve() && d->font == font) + return; + + d->font = font; + d->resolveFont(); +} + +/*! + \qmlproperty Item Qt.labs.controls::TextField::background + + This property holds the background item. + + \note If the background item has no explicit size specified, it automatically + follows the control's size. In most cases, there is no need to specify + width or height for a background item. + + \sa {Customizing TextField} +*/ +QQuickItem *QQuickTextField::background() const +{ + Q_D(const QQuickTextField); + return d->background; +} + +void QQuickTextField::setBackground(QQuickItem *background) +{ + Q_D(QQuickTextField); + if (d->background == background) + return; + + delete d->background; + d->background = background; + if (background) { + background->setParentItem(this); + if (qFuzzyIsNull(background->z())) + background->setZ(-1); + if (isComponentComplete()) + d->resizeBackground(); + } + emit backgroundChanged(); +} + +/*! + \qmlproperty string Qt.labs.controls::TextField::placeholderText + + This property holds the hint that is displayed in the TextField before the user + enters text. +*/ +QString QQuickTextField::placeholderText() const +{ + Q_D(const QQuickTextField); + return d->placeholder; +} + +void QQuickTextField::setPlaceholderText(const QString &text) +{ + Q_D(QQuickTextField); + if (d->placeholder == text) + return; + + d->placeholder = text; +#ifndef QT_NO_ACCESSIBILITY + if (d->accessibleAttached) + d->accessibleAttached->setDescription(text); +#endif + emit placeholderTextChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.controls::TextField::focusReason + + This property holds the reason of the last focus change. + + \note This property does not indicate whether the control has \l {Item::activeFocus} + {active focus}, but the reason why the control either gained or lost focus. + + \value Qt.MouseFocusReason A mouse action occurred. + \value Qt.TabFocusReason The Tab key was pressed. + \value Qt.BacktabFocusReason A Backtab occurred. The input for this may include the Shift or Control keys; e.g. Shift+Tab. + \value Qt.ActiveWindowFocusReason The window system made this window either active or inactive. + \value Qt.PopupFocusReason The application opened/closed a pop-up that grabbed/released the keyboard focus. + \value Qt.ShortcutFocusReason The user typed a label's buddy shortcut + \value Qt.MenuBarFocusReason The menu bar took focus. + \value Qt.OtherFocusReason Another reason, usually application-specific. + + \sa Item::activeFocus +*/ +Qt::FocusReason QQuickTextField::focusReason() const +{ + Q_D(const QQuickTextField); + return d->focusReason; +} + +void QQuickTextField::setFocusReason(Qt::FocusReason reason) +{ + Q_D(QQuickTextField); + if (d->focusReason == reason) + return; + + d->focusReason = reason; + emit focusReasonChanged(); +} + +void QQuickTextField::classBegin() +{ + Q_D(QQuickTextField); + QQuickTextInput::classBegin(); + d->resolveFont(); +} + +void QQuickTextField::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) +{ + Q_D(QQuickTextField); + QQuickTextInput::itemChange(change, value); + if (change == ItemParentHasChanged && value.item) + d->resolveFont(); +} + +void QQuickTextField::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickTextField); + QQuickTextInput::geometryChanged(newGeometry, oldGeometry); + d->resizeBackground(); +} + +QSGNode *QQuickTextField::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) +{ + QQuickDefaultClipNode *clipNode = static_cast(oldNode); + if (!clipNode) + clipNode = new QQuickDefaultClipNode(QRectF()); + + clipNode->setRect(clipRect().adjusted(leftPadding(), topPadding(), -rightPadding(), -bottomPadding())); + clipNode->update(); + + QSGNode *textNode = QQuickTextInput::updatePaintNode(clipNode->firstChild(), data); + if (!textNode->parent()) + clipNode->appendChildNode(textNode); + + return clipNode; +} + +void QQuickTextField::focusInEvent(QFocusEvent *event) +{ + QQuickTextInput::focusInEvent(event); + setFocusReason(event->reason()); +} + +void QQuickTextField::focusOutEvent(QFocusEvent *event) +{ + QQuickTextInput::focusOutEvent(event); + setFocusReason(event->reason()); +} + +void QQuickTextField::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickTextField); + d->pressHandler.mousePressEvent(event); + if (d->pressHandler.isActive()) { + if (d->pressHandler.delayedMousePressEvent) { + QQuickTextInput::mousePressEvent(d->pressHandler.delayedMousePressEvent); + d->pressHandler.clearDelayedMouseEvent(); + } + QQuickTextInput::mousePressEvent(event); + } +} + +void QQuickTextField::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickTextField); + d->pressHandler.mouseMoveEvent(event); + if (d->pressHandler.isActive()) { + if (d->pressHandler.delayedMousePressEvent) { + QQuickTextInput::mousePressEvent(d->pressHandler.delayedMousePressEvent); + d->pressHandler.clearDelayedMouseEvent(); + } + QQuickTextInput::mouseMoveEvent(event); + } +} + +void QQuickTextField::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickTextField); + d->pressHandler.mouseReleaseEvent(event); + if (d->pressHandler.isActive()) { + if (d->pressHandler.delayedMousePressEvent) { + QQuickTextInput::mousePressEvent(d->pressHandler.delayedMousePressEvent); + d->pressHandler.clearDelayedMouseEvent(); + } + QQuickTextInput::mouseReleaseEvent(event); + } +} + +void QQuickTextField::timerEvent(QTimerEvent *event) +{ + Q_D(QQuickTextField); + if (event->timerId() == d->pressHandler.timer.timerId()) { + d->pressHandler.timerEvent(event); + } else { + QQuickTextInput::timerEvent(event); + } +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquicktextfield_p.h b/src/quicktemplates2/qquicktextfield_p.h new file mode 100644 index 00000000..2e10f17d --- /dev/null +++ b/src/quicktemplates2/qquicktextfield_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKTEXTFIELD_P_H +#define QQUICKTEXTFIELD_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickText; +class QQuickTextFieldPrivate; +class QQuickMouseEvent; + +class Q_QUICKTEMPLATES2_EXPORT QQuickTextField : public QQuickTextInput +{ + Q_OBJECT + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) // override + Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged FINAL) + Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged FINAL) + Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL) + Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText NOTIFY placeholderTextChanged FINAL) + Q_PROPERTY(Qt::FocusReason focusReason READ focusReason WRITE setFocusReason NOTIFY focusReasonChanged FINAL) + +public: + explicit QQuickTextField(QQuickItem *parent = nullptr); + ~QQuickTextField(); + + QFont font() const; + void setFont(const QFont &font); + + QQuickItem *background() const; + void setBackground(QQuickItem *background); + + QString placeholderText() const; + void setPlaceholderText(const QString &text); + + Qt::FocusReason focusReason() const; + void setFocusReason(Qt::FocusReason reason); + +Q_SIGNALS: + void fontChanged(); + void implicitWidthChanged(); + void implicitHeightChanged(); + void backgroundChanged(); + void placeholderTextChanged(); + void focusReasonChanged(); + void pressAndHold(QQuickMouseEvent *mouse); + +protected: + void classBegin() override; + + void itemChange(ItemChange change, const ItemChangeData &value) override; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) override; + + void focusInEvent(QFocusEvent *event) override; + void focusOutEvent(QFocusEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void timerEvent(QTimerEvent *event) override; + +private: + Q_DISABLE_COPY(QQuickTextField) + Q_DECLARE_PRIVATE(QQuickTextField) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickTextField) + +#endif // QQUICKTEXTFIELD_P_H diff --git a/src/quicktemplates2/qquicktextfield_p_p.h b/src/quicktemplates2/qquicktextfield_p_p.h new file mode 100644 index 00000000..bd85d606 --- /dev/null +++ b/src/quicktemplates2/qquicktextfield_p_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKTEXTFIELD_P_P_H +#define QQUICKTEXTFIELD_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include "qquicktextfield_p.h" + +#ifndef QT_NO_ACCESSIBILITY +#include +#endif + +QT_BEGIN_NAMESPACE + +class QQuickAccessibleAttached; + +class QQuickTextFieldPrivate : public QQuickTextInputPrivate +#ifndef QT_NO_ACCESSIBILITY + , public QAccessible::ActivationObserver +#endif +{ + Q_DECLARE_PUBLIC(QQuickTextField) + +public: + QQuickTextFieldPrivate(); + ~QQuickTextFieldPrivate(); + + static QQuickTextFieldPrivate *get(QQuickTextField *item) { + return static_cast(QObjectPrivate::get(item)); } + + void resizeBackground(); + void resolveFont(); + void inheritFont(const QFont &f); + + qreal getImplicitWidth() const override; + qreal getImplicitHeight() const override; + + void implicitWidthChanged() override; + void implicitHeightChanged() override; + + void _q_readOnlyChanged(bool isReadOnly); + void _q_echoModeChanged(QQuickTextField::EchoMode echoMode); + +#ifndef QT_NO_ACCESSIBILITY + void accessibilityActiveChanged(bool active) override; + QAccessible::Role accessibleRole() const override; +#endif + + QFont font; + QQuickItem *background; + QString placeholder; + Qt::FocusReason focusReason; + QQuickPressHandler pressHandler; + QQuickAccessibleAttached *accessibleAttached; +}; + +QT_END_NAMESPACE + +#endif // QQUICKTEXTFIELD_P_P_H diff --git a/src/quicktemplates2/qquicktoolbar.cpp b/src/quicktemplates2/qquicktoolbar.cpp new file mode 100644 index 00000000..541160fd --- /dev/null +++ b/src/quicktemplates2/qquicktoolbar.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicktoolbar_p.h" +#include "qquickframe_p_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ToolBar + \inherits Frame + \instantiates QQuickToolBar + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-containers + \brief A container with context-sensitive controls. + + ToolBar is a container of application-wide and context sensitive + actions and controls, such as navigation buttons and search fields. + ToolBar is commonly used as a \l {ApplicationWindow::header}{header} + or a \l {ApplicationWindow::footer}{footer} of an \l ApplicationWindow. + + ToolBar does not provide a layout of its own, but requires you to + position its contents, for instance by creating a \l RowLayout. If only + a single item is used within the ToolBar, it will resize to fit the + implicit size of its contained item. This makes it particularly suitable + for use together with layouts. + + \image qtquickcontrols-toolbar.png + + \code + ApplicationWindow { + visible:true + + header: ToolBar { + RowLayout { + anchors.fill: parent + ToolButton { + text: qsTr("\u25C0 %1").arg(Qt.application.name) + enabled: stack.depth > 1 + onClicked: stack.pop() + } + Item { Layout.fillWidth: true } + Switch { + checked: true + text: qsTr("Notifications") + } + } + } + + StackView { + id: stack + anchors.fill: parent + } + } + \endcode + + \labs + + \sa ApplicationWindow, ToolButton, {Customizing ToolBar}, {Container Controls} +*/ + +class QQuickToolBarPrivate : public QQuickFramePrivate +{ +public: + QQuickToolBarPrivate() : position(QQuickToolBar::Header) { } + + QQuickToolBar::Position position; +}; + +QQuickToolBar::QQuickToolBar(QQuickItem *parent) : + QQuickFrame(*(new QQuickToolBarPrivate), parent) +{ +} + +/*! + \qmlproperty enumeration Qt.labs.controls::ToolBar::position + + This property holds the position of the toolbar. + + \note If the toolbar is assigned as a header or footer of ApplicationWindow + or Page, the appropriate position is set automatically. + + Possible values: + \value ToolBar.Header The toolbar is at the top, as a window or page header. + \value ToolBar.Footer The toolbar is at the bottom, as a window or page footer. + + The default value is style-specific. + + \sa ApplicationWindow::header, ApplicationWindow::footer, Page::header, Page::footer +*/ +QQuickToolBar::Position QQuickToolBar::position() const +{ + Q_D(const QQuickToolBar); + return d->position; +} + +void QQuickToolBar::setPosition(Position position) +{ + Q_D(QQuickToolBar); + if (d->position == position) + return; + + d->position = position; + emit positionChanged(); +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickToolBar::accessibleRole() const +{ + return QAccessible::ToolBar; +} +#endif + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquicktoolbar_p.h b/src/quicktemplates2/qquicktoolbar_p.h new file mode 100644 index 00000000..11aee8a0 --- /dev/null +++ b/src/quicktemplates2/qquicktoolbar_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKTOOLBAR_P_H +#define QQUICKTOOLBAR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickToolBarPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickToolBar : public QQuickFrame +{ + Q_OBJECT + Q_PROPERTY(Position position READ position WRITE setPosition NOTIFY positionChanged FINAL) + +public: + explicit QQuickToolBar(QQuickItem *parent = nullptr); + + enum Position { + Header, + Footer + }; + Q_ENUM(Position) + + Position position() const; + void setPosition(Position position); + +Q_SIGNALS: + void positionChanged(); + +protected: +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickToolBar) + Q_DECLARE_PRIVATE(QQuickToolBar) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickToolBar) + +#endif // QQUICKTOOLBAR_P_H diff --git a/src/quicktemplates2/qquicktoolbutton.cpp b/src/quicktemplates2/qquicktoolbutton.cpp new file mode 100644 index 00000000..410bb556 --- /dev/null +++ b/src/quicktemplates2/qquicktoolbutton.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicktoolbutton_p.h" +#include "qquickcontrol_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ToolButton + \inherits Button + \instantiates QQuickToolButton + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-buttons + \brief A button with a layout suitable for a ToolBar. + + ToolButton is functionally similar to \l Button, but provides a look that + is more suitable within a \l ToolBar. + + ### TODO: screenshot + + \code + ToolBar { + RowLayout { + anchors.fill: parent + ToolButton { + text: qsTr("< %1").arg(Qt.application.name) + enabled: stack.depth > 1 + onClicked: stack.pop() + } + Item { Layout.fillWidth: true } + ToolButton { + text: qsTr("< %1").arg(Qt.application.name) + enabled: stack.depth > 1 + onClicked: stack.pop() + } + } + } + \endcode + + \labs + + \sa ToolBar, {Customizing ToolButton}, {Button Controls} +*/ + +QQuickToolButton::QQuickToolButton(QQuickItem *parent) : + QQuickButton(parent) +{ +} + +QFont QQuickToolButton::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::ToolButtonFont); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquicktoolbutton_p.h b/src/quicktemplates2/qquicktoolbutton_p.h new file mode 100644 index 00000000..e35e3525 --- /dev/null +++ b/src/quicktemplates2/qquicktoolbutton_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKTOOLBUTTON_P_H +#define QQUICKTOOLBUTTON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class Q_QUICKTEMPLATES2_EXPORT QQuickToolButton : public QQuickButton +{ + Q_OBJECT + +public: + explicit QQuickToolButton(QQuickItem *parent = nullptr); + +protected: + QFont defaultFont() const override; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickToolButton) + +#endif // QQUICKTOOLBUTTON_P_H diff --git a/src/quicktemplates2/qquicktooltip.cpp b/src/quicktemplates2/qquicktooltip.cpp new file mode 100644 index 00000000..010a07c5 --- /dev/null +++ b/src/quicktemplates2/qquicktooltip.cpp @@ -0,0 +1,560 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicktooltip_p.h" +#include "qquickpopup_p_p.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ToolTip + \inherits Popup + \instantiates QQuickToolTip + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-popups + \brief Provides tool tips for any control. + + A tool tip is a short piece of text that informs the user of a control's + function. It is typically placed above or below the parent control. The + tip text can be any \l{Rich Text Processing}{rich text} formatted string. + + \image qtquickcontrols-tooltip.png + + The most straight-forward way to setup tool tips for controls is to + specify \l text and \l {visible}{visibility} via attached properties. + The following example illustrates this approach: + + \snippet qtquickcontrols-tooltip.qml 1 + + Under normal circumstances, there is only one tool tip visible at a time. + In order to save resources, all items that use the ToolTip attached property + share the same visual tool tip label instance. Even though the visuals are + shared, \c text, \c timeout and \c delay are stored individually for each item + that uses the respective attached property. However, multiple items cannot + make the shared tool tip visible at the same time. The shared tool tip is only + shown for the last item that made it visible. The position of the shared tool + tip is determined by the framework. + + \section2 Delay and Timeout + + Tool tips are typically transient in a sense that they are shown as a + result of a certain external event or user interaction, and they usually + hide after a certain timeout. It is possible to control the delay when + a tool tip is shown, and the timeout when it is hidden. This makes it + possible to implement varying strategies for showing and hiding tool tips. + + For example, on touch screens, it is a common pattern to show a tool tip + as a result of pressing and holding down a button. The following example + demonstrates how to delay showing a tool tip until the press-and-hold + interval is reached. In this example, the tool tip hides as soon as the + button is released. + + \snippet qtquickcontrols-tooltip-pressandhold.qml 1 + + With pointer devices, however, it might be desired to show a tool tip as + a result of hovering a button for a while. The following example presents + how to show a tool tip after hovering a button for a second, and hide it + after a timeout of five seconds. + + \snippet qtquickcontrols-tooltip-hover.qml 1 + + \section2 Custom Tool Tips + + Should one need more fine-grained control over the tool tip position, or + multiple simultaneous tool tip instances are needed, it is also possible + to create local tool tip instances. This way, it is possible to + \l {Customizing ToolTip}{customize} the tool tip, and the whole \l Popup + API is available. The following example presents a tool tip that presents + the value of a slider when the handle is dragged. + + \image qtquickcontrols-tooltip-slider.png + + \snippet qtquickcontrols-tooltip-slider.qml 1 + + \labs + + \sa {Customizing ToolTip} +*/ + +class QQuickToolTipPrivate : public QQuickPopupPrivate +{ + Q_DECLARE_PUBLIC(QQuickToolTip) + +public: + QQuickToolTipPrivate() : delay(0), timeout(-1) { } + + void startDelay(); + void stopDelay(); + + void startTimeout(); + void stopTimeout(); + + void reposition() override; + + int delay; + int timeout; + QString text; + QBasicTimer delayTimer; + QBasicTimer timeoutTimer; +}; + +void QQuickToolTipPrivate::startDelay() +{ + Q_Q(QQuickToolTip); + if (delay > 0) + delayTimer.start(delay, q); +} + +void QQuickToolTipPrivate::stopDelay() +{ + delayTimer.stop(); +} + +void QQuickToolTipPrivate::startTimeout() +{ + Q_Q(QQuickToolTip); + if (timeout > 0) + timeoutTimer.start(timeout, q); +} + +void QQuickToolTipPrivate::stopTimeout() +{ + timeoutTimer.stop(); +} + +void QQuickToolTipPrivate::reposition() +{ + Q_Q(QQuickToolTip); + const qreal w = popupItem->width(); + const qreal h = popupItem->height(); + const qreal iw = popupItem->implicitWidth(); + const qreal ih = popupItem->implicitHeight(); + + bool widthAdjusted = false; + bool heightAdjusted = false; + + QRectF rect(x, y, iw > 0 ? iw : w, ih > 0 ? ih : h); + if (parentItem) { + rect = parentItem->mapRectToScene(rect); + + QQuickWindow *window = q->window(); + if (window) { + const QRectF bounds = QRectF(0, 0, window->width(), window->height()).marginsRemoved(getMargins()); + + if (rect.left() < bounds.left() || rect.right() > bounds.right()) { + // if the tooltip doesn't fit inside the window, try flipping it around (left <-> right) + const QRectF flipped = parentItem->mapRectToScene(QRectF(parentItem->width() - x - rect.width(), y, rect.width(), rect.height())); + + if (flipped.intersected(bounds).width() > rect.intersected(bounds).width()) + rect.moveLeft(flipped.left()); + + if (iw > 0) { + // neither the flipped around geometry fits inside the window, choose + // whichever side (left vs. right) fits larger part of the popup + if (rect.left() < bounds.left() && bounds.left() + rect.width() <= bounds.right()) + rect.moveLeft(bounds.left()); + else if (rect.right() > bounds.right() && bounds.right() - rect.width() >= bounds.left()) + rect.moveRight(bounds.right()); + + // as a last resort, adjust width to fit the window + if (rect.left() < bounds.left()) { + rect.setLeft(bounds.left()); + widthAdjusted = true; + } + if (rect.right() > bounds.right()) { + rect.setRight(bounds.right()); + widthAdjusted = true; + } + } + } + + if (rect.top() < bounds.top() || rect.bottom() > bounds.bottom()) { + // if the tooltip doesn't fit inside the window, try flipping it around (above <-> below) + const QRectF flipped = parentItem->mapRectToScene(QRectF(x, parentItem->height() - y - rect.height(), rect.width(), rect.height())); + + if (flipped.intersected(bounds).height() > rect.intersected(bounds).height()) + rect.moveTop(flipped.top()); + + if (ih > 0) { + // neither the flipped around geometry fits inside the window, choose + // whichever side (above vs. below) fits larger part of the popup + if (rect.top() < bounds.top() && bounds.top() + rect.height() <= bounds.bottom()) + rect.moveTop(bounds.top()); + else if (rect.bottom() > bounds.bottom() && bounds.bottom() - rect.height() >= bounds.top()) + rect.moveBottom(bounds.bottom()); + + // as a last resort, adjust height to fit the window + if (rect.top() < bounds.top()) { + rect.setTop(bounds.top()); + heightAdjusted = true; + } + if (rect.bottom() > bounds.bottom()) { + rect.setBottom(bounds.bottom()); + heightAdjusted = true; + } + } + } + } + } + + popupItem->setPosition(rect.topLeft()); + if (widthAdjusted && rect.width() > 0) + popupItem->setWidth(rect.width()); + if (heightAdjusted && rect.height() > 0) + popupItem->setHeight(rect.height()); +} + +QQuickToolTip::QQuickToolTip(QQuickItem *parent) : + QQuickPopup(*(new QQuickToolTipPrivate), parent) +{ +} + +/*! + \qmlproperty string Qt.labs.controls::ToolTip::text + + This property holds the text shown on the tool tip. +*/ +QString QQuickToolTip::text() const +{ + Q_D(const QQuickToolTip); + return d->text; +} + +void QQuickToolTip::setText(const QString &text) +{ + Q_D(QQuickToolTip); + if (d->text == text) + return; + + d->text = text; + emit textChanged(); +} + +/*! + \qmlproperty int Qt.labs.controls::ToolTip::delay + + This property holds the delay (milliseconds) after which the tool tip is + shown. A tooltip with a negative delay is shown immediately. The default + value is \c 0. +*/ +int QQuickToolTip::delay() const +{ + Q_D(const QQuickToolTip); + return d->delay; +} + +void QQuickToolTip::setDelay(int delay) +{ + Q_D(QQuickToolTip); + if (d->delay == delay) + return; + + d->delay = delay; + emit delayChanged(); +} + +/*! + \qmlproperty int Qt.labs.controls::ToolTip::timeout + + This property holds the timeout (milliseconds) after which the tool tip is + hidden. A tooltip with a negative timeout does not hide automatically. The + default value is \c -1. +*/ +int QQuickToolTip::timeout() const +{ + Q_D(const QQuickToolTip); + return d->timeout; +} + +void QQuickToolTip::setTimeout(int timeout) +{ + Q_D(QQuickToolTip); + if (d->timeout == timeout) + return; + + if (timeout <= 0) + d->stopTimeout(); + else if (isVisible()) + d->startTimeout(); + + d->timeout = timeout; + emit timeoutChanged(); +} + +QQuickToolTipAttached *QQuickToolTip::qmlAttachedProperties(QObject *object) +{ + QQuickItem *item = qobject_cast(object); + if (!item) { + qWarning() << "ToolTip must be attached to an Item" << object; + return nullptr; + } + + return new QQuickToolTipAttached(item); +} + +void QQuickToolTip::open() +{ + Q_D(QQuickToolTip); + if (d->delay > 0) + d->startDelay(); + else + QQuickPopup::open(); +} + +void QQuickToolTip::close() +{ + Q_D(QQuickToolTip); + d->stopDelay(); + QQuickPopup::close(); +} + +void QQuickToolTip::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) +{ + Q_D(QQuickToolTip); + QQuickPopup::itemChange(change, data); + if (change == QQuickItem::ItemVisibleHasChanged) { + if (data.boolValue) + d->startTimeout(); + else + d->stopTimeout(); + + QQuickToolTipAttached *attached = qobject_cast(qmlAttachedPropertiesObject(d->parentItem, false)); + if (attached) + emit attached->visibleChanged(); + } +} + +void QQuickToolTip::timerEvent(QTimerEvent *event) +{ + Q_D(QQuickToolTip); + if (event->timerId() == d->timeoutTimer.timerId()) { + d->stopTimeout(); + close(); + } else if (event->timerId() == d->delayTimer.timerId()) { + d->stopDelay(); + QQuickPopup::open(); + } +} + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickToolTip::accessibleRole() const +{ + return QAccessible::ToolTip; +} +#endif + +class QQuickToolTipAttachedPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QQuickToolTipAttached) + +public: + QQuickToolTipAttachedPrivate() : delay(0), timeout(-1) { } + + QQuickToolTip *instance(bool create) const; + + int delay; + int timeout; + QString text; +}; + +QQuickToolTip *QQuickToolTipAttachedPrivate::instance(bool create) const +{ + static QPointer tip; + if (!tip && create) { + // TODO: a cleaner way to create the instance? QQml(Meta)Type? + QQmlContext *context = qmlContext(parent); + QQmlComponent component(context->engine()); + component.setData("import Qt.labs.controls 1.0; ToolTip { }", QUrl()); + + QObject *object = component.create(context); + tip = qobject_cast(object); + if (!tip) + delete object; + } + return tip; +} + +QQuickToolTipAttached::QQuickToolTipAttached(QQuickItem *item) : + QObject(*(new QQuickToolTipAttachedPrivate), item) +{ +} + +/*! + \qmlattachedproperty string Qt.labs.controls::ToolTip::text + + This attached property holds the text of the shared tool tip instance. + The property can be attached to any item. +*/ +QString QQuickToolTipAttached::text() const +{ + Q_D(const QQuickToolTipAttached); + return d->text; +} + +void QQuickToolTipAttached::setText(const QString &text) +{ + Q_D(QQuickToolTipAttached); + if (d->text == text) + return; + + d->text = text; + emit textChanged(); + + d->instance(true)->setText(text); +} + +/*! + \qmlattachedproperty int Qt.labs.controls::ToolTip::delay + + This attached property holds the delay (milliseconds) of the shared tool tip. + The property can be attached to any item. +*/ +int QQuickToolTipAttached::delay() const +{ + Q_D(const QQuickToolTipAttached); + return d->delay; +} + +void QQuickToolTipAttached::setDelay(int delay) +{ + Q_D(QQuickToolTipAttached); + if (d->delay == delay) + return; + + d->delay = delay; + emit delayChanged(); +} + +/*! + \qmlattachedproperty int Qt.labs.controls::ToolTip::timeout + + This attached property holds the timeout (milliseconds) of the shared tool tip. + The property can be attached to any item. +*/ +int QQuickToolTipAttached::timeout() const +{ + Q_D(const QQuickToolTipAttached); + return d->timeout; +} + +void QQuickToolTipAttached::setTimeout(int timeout) +{ + Q_D(QQuickToolTipAttached); + if (d->timeout == timeout) + return; + + d->timeout = timeout; + emit timeoutChanged(); +} + +/*! + \qmlattachedproperty bool Qt.labs.controls::ToolTip::visible + + This attached property holds whether the shared tool tip is visible. + The property can be attached to any item. +*/ +bool QQuickToolTipAttached::isVisible() const +{ + Q_D(const QQuickToolTipAttached); + QQuickToolTip *tip = d->instance(false); + if (!tip) + return false; + + return tip->isVisible() && tip->parentItem() == parent(); +} + +void QQuickToolTipAttached::setVisible(bool visible) +{ + Q_D(QQuickToolTipAttached); + if (visible) + show(d->text); + else + hide(); +} + +/*! + \qmlattachedproperty ToolTip Qt.labs.controls::ToolTip::toolTip + + This attached property holds the shared tool tip instance. The property + can be attached to any item. +*/ +QQuickToolTip *QQuickToolTipAttached::toolTip() const +{ + Q_D(const QQuickToolTipAttached); + return d->instance(true); +} + +/*! + \qmlattachedmethod void Qt.labs.controls::ToolTip::show(string text, int timeout = -1) + + This attached method shows the shared tooltip with \a text and \a timeout (milliseconds). + The method can be attached to any item. +*/ +void QQuickToolTipAttached::show(const QString &text, int ms) +{ + Q_D(QQuickToolTipAttached); + QQuickToolTip *tip = d->instance(true); + tip->resetWidth(); + tip->resetHeight(); + tip->setParentItem(qobject_cast(parent())); + tip->setTimeout(ms >= 0 ? ms : d->timeout); + tip->setDelay(d->delay); + tip->setText(text); + tip->open(); +} + +/*! + \qmlattachedmethod void Qt.labs.controls::ToolTip::hide() + + This attached method hides the shared tooltip. The method can be attached to any item. +*/ +void QQuickToolTipAttached::hide() +{ + Q_D(QQuickToolTipAttached); + QQuickToolTip *tip = d->instance(false); + if (!tip) + return; + + tip->close(); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquicktooltip_p.h b/src/quicktemplates2/qquicktooltip_p.h new file mode 100644 index 00000000..a4e00eb2 --- /dev/null +++ b/src/quicktemplates2/qquicktooltip_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKTOOLTIP_P_H +#define QQUICKTOOLTIP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickToolTipPrivate; +class QQuickToolTipAttached; +class QQuickToolTipAttachedPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickToolTip : public QQuickPopup +{ + Q_OBJECT + Q_PROPERTY(int delay READ delay WRITE setDelay NOTIFY delayChanged FINAL) + Q_PROPERTY(int timeout READ timeout WRITE setTimeout NOTIFY timeoutChanged FINAL) + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL) + +public: + explicit QQuickToolTip(QQuickItem *parent = nullptr); + + QString text() const; + void setText(const QString &text); + + int delay() const; + void setDelay(int delay); + + int timeout() const; + void setTimeout(int timeout); + + static QQuickToolTipAttached *qmlAttachedProperties(QObject *object); + +public Q_SLOTS: + void open(); + void close(); + +Q_SIGNALS: + void textChanged(); + void delayChanged(); + void timeoutChanged(); + +protected: + void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) override; + void timerEvent(QTimerEvent *event) override; + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::Role accessibleRole() const override; +#endif + +private: + Q_DISABLE_COPY(QQuickToolTip) + Q_DECLARE_PRIVATE(QQuickToolTip) +}; + +class Q_QUICKTEMPLATES2_EXPORT QQuickToolTipAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL) + Q_PROPERTY(int delay READ delay WRITE setDelay NOTIFY delayChanged FINAL) + Q_PROPERTY(int timeout READ timeout WRITE setTimeout NOTIFY timeoutChanged FINAL) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL) + Q_PROPERTY(QQuickToolTip *toolTip READ toolTip CONSTANT FINAL) + +public: + explicit QQuickToolTipAttached(QQuickItem *item); + + QString text() const; + void setText(const QString &text); + + int delay() const; + void setDelay(int delay); + + int timeout() const; + void setTimeout(int timeout); + + bool isVisible() const; + void setVisible(bool visible); + + QQuickToolTip *toolTip() const; + +Q_SIGNALS: + void textChanged(); + void delayChanged(); + void timeoutChanged(); + void visibleChanged(); + +public Q_SLOTS: + void show(const QString &text, int ms = -1); + void hide(); + +private: + Q_DISABLE_COPY(QQuickToolTipAttached) + Q_DECLARE_PRIVATE(QQuickToolTipAttached) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickToolTip) +QML_DECLARE_TYPEINFO(QQuickToolTip, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QQUICKTOOLTIP_P_H diff --git a/src/quicktemplates2/qquicktumbler.cpp b/src/quicktemplates2/qquicktumbler.cpp new file mode 100644 index 00000000..ee82128f --- /dev/null +++ b/src/quicktemplates2/qquicktumbler.cpp @@ -0,0 +1,548 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicktumbler_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Tumbler + \inherits Control + \instantiates QQuickTumbler + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-input + \brief A spinnable wheel of items that can be selected. + + \code + Tumbler { + model: 5 + // ... + } + \endcode + + \section1 Non-wrapping Tumbler + + The default contentItem of Tumbler is a \l PathView, which wraps when it + reaches the top and bottom. To achieve a non-wrapping Tumbler, use ListView + as the contentItem: + + \snippet tst_tumbler.qml contentItem + + \image qtquickcontrols-tumbler-wrap.gif + + \labs + + \sa {Customizing Tumbler}, {Input Controls} +*/ + +class QQuickTumblerPrivate : public QQuickControlPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickTumbler) + +public: + QQuickTumblerPrivate() : + delegate(nullptr), + visibleItemCount(3) + { + } + + ~QQuickTumblerPrivate() + { + } + + QVariant model; + QQmlComponent *delegate; + int visibleItemCount; + + void _q_updateItemHeights(); + void _q_updateItemWidths(); + + void itemChildAdded(QQuickItem *, QQuickItem *) override; + void itemChildRemoved(QQuickItem *, QQuickItem *) override; +}; + +static QList contentItemChildItems(QQuickItem *contentItem) +{ + if (!contentItem) + return QList(); + + // PathView has no contentItem property, but ListView does. + QQuickFlickable *flickable = qobject_cast(contentItem); + return flickable ? flickable->contentItem()->childItems() : contentItem->childItems(); +} + +namespace { + static inline qreal delegateHeight(const QQuickTumbler *tumbler) + { + return tumbler->availableHeight() / tumbler->visibleItemCount(); + } + + enum ContentItemType { + UnsupportedContentItemType, + PathViewContentItem, + ListViewContentItem + }; + + static inline QQuickItem *actualContentItem(QQuickItem *rootContentItem, ContentItemType contentType) + { + if (contentType == PathViewContentItem) + return rootContentItem; + else if (contentType == ListViewContentItem) + return qobject_cast(rootContentItem)->contentItem(); + + return nullptr; + } + + static inline ContentItemType contentItemType(QQuickItem *rootContentItem) + { + if (rootContentItem->inherits("QQuickPathView")) + return PathViewContentItem; + else if (rootContentItem->inherits("QQuickListView")) + return ListViewContentItem; + + return UnsupportedContentItemType; + } + + static inline ContentItemType contentItemTypeFromDelegate(QQuickItem *delegateItem) + { + if (delegateItem->parentItem()->inherits("QQuickPathView")) { + return PathViewContentItem; + } else if (delegateItem->parentItem()->parentItem() + && delegateItem->parentItem()->parentItem()->inherits("QQuickListView")) { + return ListViewContentItem; + } + + return UnsupportedContentItemType; + } +} + +void QQuickTumblerPrivate::_q_updateItemHeights() +{ + // Can't use our own private padding members here, as the padding property might be set, + // which doesn't affect them, only their getters. + Q_Q(const QQuickTumbler); + const qreal itemHeight = delegateHeight(q); + const auto items = contentItemChildItems(contentItem); + for (QQuickItem *childItem : items) + childItem->setHeight(itemHeight); +} + +void QQuickTumblerPrivate::_q_updateItemWidths() +{ + Q_Q(const QQuickTumbler); + const qreal availableWidth = q->availableWidth(); + const auto items = contentItemChildItems(contentItem); + for (QQuickItem *childItem : items) + childItem->setWidth(availableWidth); +} + +void QQuickTumblerPrivate::itemChildAdded(QQuickItem *, QQuickItem *) +{ + _q_updateItemWidths(); + _q_updateItemHeights(); +} + +void QQuickTumblerPrivate::itemChildRemoved(QQuickItem *, QQuickItem *) +{ + _q_updateItemWidths(); + _q_updateItemHeights(); +} + +QQuickTumbler::QQuickTumbler(QQuickItem *parent) : + QQuickControl(*(new QQuickTumblerPrivate), parent) +{ + setActiveFocusOnTab(true); + + connect(this, SIGNAL(leftPaddingChanged()), this, SLOT(_q_updateItemWidths())); + connect(this, SIGNAL(rightPaddingChanged()), this, SLOT(_q_updateItemWidths())); + connect(this, SIGNAL(topPaddingChanged()), this, SLOT(_q_updateItemHeights())); + connect(this, SIGNAL(bottomPaddingChanged()), this, SLOT(_q_updateItemHeights())); +} + +QQuickTumbler::~QQuickTumbler() +{ +} + +/*! + \qmlproperty variant Qt.labs.controls::Tumbler::model + + This property holds the model that provides data for this tumbler. +*/ +QVariant QQuickTumbler::model() const +{ + Q_D(const QQuickTumbler); + return d->model; +} + +void QQuickTumbler::setModel(const QVariant &model) +{ + Q_D(QQuickTumbler); + if (model == d->model) + return; + + d->model = model; + emit modelChanged(); +} + +/*! + \qmlproperty int Qt.labs.controls::Tumbler::count + \readonly + + This property holds the number of items in the model. +*/ +int QQuickTumbler::count() const +{ + Q_D(const QQuickTumbler); + return d->contentItem->property("count").toInt(); +} + +/*! + \qmlproperty int Qt.labs.controls::Tumbler::currentIndex + + This property holds the index of the current item. +*/ +int QQuickTumbler::currentIndex() const +{ + Q_D(const QQuickTumbler); + return d->contentItem ? d->contentItem->property("currentIndex").toInt() : -1; +} + +void QQuickTumbler::setCurrentIndex(int currentIndex) +{ + Q_D(QQuickTumbler); + d->contentItem->setProperty("currentIndex", currentIndex); +} + +/*! + \qmlproperty Item Qt.labs.controls::Tumbler::currentItem + \readonly + + This property holds the item at the current index. +*/ +QQuickItem *QQuickTumbler::currentItem() const +{ + Q_D(const QQuickTumbler); + return d->contentItem ? d->contentItem->property("currentItem").value() : nullptr; +} + +/*! + \qmlproperty component Qt.labs.controls::Tumbler::delegate + + This property holds the delegate used to display each item. +*/ +QQmlComponent *QQuickTumbler::delegate() const +{ + Q_D(const QQuickTumbler); + return d->delegate; +} + +void QQuickTumbler::setDelegate(QQmlComponent *delegate) +{ + Q_D(QQuickTumbler); + if (delegate == d->delegate) + return; + + d->delegate = delegate; + emit delegateChanged(); +} + +/*! + \qmlproperty int Qt.labs.controls::Tumbler::visibleItemCount + + This property holds the number of items visible in the tumbler. It must be + an odd number, as the current item is always vertically centered. +*/ +int QQuickTumbler::visibleItemCount() const +{ + Q_D(const QQuickTumbler); + return d->visibleItemCount; +} + +void QQuickTumbler::setVisibleItemCount(int visibleItemCount) +{ + Q_D(QQuickTumbler); + if (visibleItemCount == d->visibleItemCount) + return; + + d->visibleItemCount = visibleItemCount; + d->_q_updateItemHeights(); + emit visibleItemCountChanged(); +} + +QQuickTumblerAttached *QQuickTumbler::qmlAttachedProperties(QObject *object) +{ + QQuickItem *delegateItem = qobject_cast(object); + if (!delegateItem) { + qWarning() << "Tumbler: attached properties of Tumbler must be accessed from within a delegate item"; + return nullptr; + } + + return new QQuickTumblerAttached(delegateItem); +} + +void QQuickTumbler::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickTumbler); + + QQuickControl::geometryChanged(newGeometry, oldGeometry); + + d->_q_updateItemHeights(); + + if (newGeometry.width() != oldGeometry.width()) + d->_q_updateItemWidths(); +} + +void QQuickTumbler::componentComplete() +{ + Q_D(QQuickTumbler); + QQuickControl::componentComplete(); + d->_q_updateItemHeights(); + d->_q_updateItemWidths(); +} + +void QQuickTumbler::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_D(QQuickTumbler); + + QQuickControl::contentItemChange(newItem, oldItem); + + // Since we use the currentIndex of the contentItem directly, we must + // ensure that we keep track of the currentIndex so it doesn't get lost + // between contentItem changes. + const int previousCurrentIndex = currentIndex(); + + if (oldItem) { + disconnect(oldItem, SIGNAL(currentIndexChanged()), this, SIGNAL(currentIndexChanged())); + disconnect(oldItem, SIGNAL(currentItemChanged()), this, SIGNAL(currentItemChanged())); + disconnect(oldItem, SIGNAL(countChanged()), this, SIGNAL(countChanged())); + + ContentItemType oldContentItemType = contentItemType(oldItem); + QQuickItem *actualOldContentItem = actualContentItem(oldItem, oldContentItemType); + QQuickItemPrivate *actualContentItemPrivate = QQuickItemPrivate::get(actualOldContentItem); + actualContentItemPrivate->removeItemChangeListener(d, QQuickItemPrivate::Children); + } + + if (newItem) { + ContentItemType contentType = contentItemType(newItem); + if (contentType == UnsupportedContentItemType) { + qWarning() << "Tumbler: contentItems other than PathView and ListView are not supported"; + return; + } + + connect(newItem, SIGNAL(currentIndexChanged()), this, SIGNAL(currentIndexChanged())); + connect(newItem, SIGNAL(currentItemChanged()), this, SIGNAL(currentItemChanged())); + connect(newItem, SIGNAL(countChanged()), this, SIGNAL(countChanged())); + + QQuickItem *actualNewContentItem = actualContentItem(newItem, contentType); + QQuickItemPrivate *actualContentItemPrivate = QQuickItemPrivate::get(actualNewContentItem); + actualContentItemPrivate->addItemChangeListener(d, QQuickItemPrivate::Children); + + // If the previous currentIndex is -1, it means we had no contentItem previously. + if (previousCurrentIndex != -1) { + // Can't call setCurrentIndex here, as contentItemChange() is + // called *before* the contentItem is set. + newItem->setProperty("currentIndex", previousCurrentIndex); + } + } +} + +void QQuickTumbler::keyPressEvent(QKeyEvent *event) +{ + Q_D(QQuickTumbler); + + QQuickControl::keyPressEvent(event); + + if (event->isAutoRepeat()) + return; + + if (event->key() == Qt::Key_Up) { + QMetaObject::invokeMethod(d->contentItem, "decrementCurrentIndex"); + } else if (event->key() == Qt::Key_Down) { + QMetaObject::invokeMethod(d->contentItem, "incrementCurrentIndex"); + } +} + +class QQuickTumblerAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickTumblerAttached) +public: + QQuickTumblerAttachedPrivate(QQuickItem *delegateItem) : + tumbler(nullptr), + index(-1), + displacement(1) + { + if (!delegateItem->parentItem()) { + qWarning() << "Tumbler: attached properties must be accessed from within a delegate item that has a parent"; + return; + } + + QVariant indexContextProperty = qmlContext(delegateItem)->contextProperty(QStringLiteral("index")); + if (!indexContextProperty.isValid()) { + qWarning() << "Tumbler: attempting to access attached property on item without an \"index\" property"; + return; + } + + index = indexContextProperty.toInt(); + const ContentItemType contentItemType = contentItemTypeFromDelegate(delegateItem); + if (contentItemType == UnsupportedContentItemType) + return; + + // ListView has an "additional" content item. + tumbler = qobject_cast(contentItemType == PathViewContentItem + ? delegateItem->parentItem()->parentItem() : delegateItem->parentItem()->parentItem()->parentItem()); + Q_ASSERT(tumbler); + } + + ~QQuickTumblerAttachedPrivate() { + } + + void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override; + void itemChildAdded(QQuickItem *, QQuickItem *) override; + void itemChildRemoved(QQuickItem *, QQuickItem *) override; + + void _q_calculateDisplacement(); + + // The Tumbler that contains the delegate. Required to calculated the displacement. + QQuickTumbler *tumbler; + // The index of the delegate. Used to calculate the displacement. + int index; + // The displacement for our delegate. + qreal displacement; +}; + +void QQuickTumblerAttachedPrivate::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) +{ + _q_calculateDisplacement(); +} + +void QQuickTumblerAttachedPrivate::itemChildAdded(QQuickItem *, QQuickItem *) +{ + _q_calculateDisplacement(); +} + +void QQuickTumblerAttachedPrivate::itemChildRemoved(QQuickItem *item, QQuickItem *child) +{ + _q_calculateDisplacement(); + + if (parent == child) { + // The child that was removed from the contentItem was the delegate + // that our properties are attached to. If we don't remove the change + // listener, the contentItem will attempt to notify a destroyed + // listener, causing a crash. + + // item is the "actual content item" of Tumbler's contentItem, i.e. a PathView or ListView.contentItem + QQuickItemPrivate *p = QQuickItemPrivate::get(item); + p->removeItemChangeListener(this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Children); + } +} + +void QQuickTumblerAttachedPrivate::_q_calculateDisplacement() +{ + const int previousDisplacement = displacement; + displacement = 0; + + const int count = tumbler->count(); + // This can happen in tests, so it may happen in normal usage too. + if (count == 0) + return; + + ContentItemType contentType = contentItemType(tumbler->contentItem()); + if (contentType == UnsupportedContentItemType) + return; + + qreal offset = 0; + + if (contentType == PathViewContentItem) { + offset = tumbler->contentItem()->property("offset").toReal(); + + displacement = count - index - offset; + int halfVisibleItems = tumbler->visibleItemCount() / 2 + 1; + if (displacement > halfVisibleItems) + displacement -= count; + else if (displacement < -halfVisibleItems) + displacement += count; + } else { + const qreal contentY = tumbler->contentItem()->property("contentY").toReal(); + const qreal delegateH = delegateHeight(tumbler); + const qreal preferredHighlightBegin = tumbler->contentItem()->property("preferredHighlightBegin").toReal(); + // Tumbler's displacement goes from negative at the top to positive towards the bottom, so we must switch this around. + const qreal reverseDisplacement = (contentY + preferredHighlightBegin) / delegateH; + displacement = reverseDisplacement - index; + } + + Q_Q(QQuickTumblerAttached); + if (displacement != previousDisplacement) + emit q->displacementChanged(); +} + +QQuickTumblerAttached::QQuickTumblerAttached(QQuickItem *delegateItem) : + QObject(*(new QQuickTumblerAttachedPrivate(delegateItem)), delegateItem) +{ + Q_D(QQuickTumblerAttached); + if (d->tumbler) { + QQuickItem *rootContentItem = d->tumbler->contentItem(); + const ContentItemType contentType = contentItemType(rootContentItem); + QQuickItemPrivate *p = QQuickItemPrivate::get(actualContentItem(rootContentItem, contentType)); + p->addItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Children); + + const char *contentItemSignal = contentType == PathViewContentItem + ? SIGNAL(offsetChanged()) : SIGNAL(contentYChanged()); + connect(d->tumbler->contentItem(), contentItemSignal, this, SLOT(_q_calculateDisplacement())); + } +} + +QQuickTumblerAttached::~QQuickTumblerAttached() +{ +} + +QQuickTumbler *QQuickTumblerAttached::tumbler() const +{ + Q_D(const QQuickTumblerAttached); + return d->tumbler; +} + +qreal QQuickTumblerAttached::displacement() const +{ + Q_D(const QQuickTumblerAttached); + return d->displacement; +} + +QT_END_NAMESPACE + +#include "moc_qquicktumbler_p.cpp" diff --git a/src/quicktemplates2/qquicktumbler_p.h b/src/quicktemplates2/qquicktumbler_p.h new file mode 100644 index 00000000..0fdccca8 --- /dev/null +++ b/src/quicktemplates2/qquicktumbler_p.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKTUMBLER_H +#define QQUICKTUMBLER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickTumblerAttached; +class QQuickTumblerPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickTumbler : public QQuickControl +{ + Q_OBJECT + Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged FINAL) + Q_PROPERTY(int count READ count NOTIFY countChanged FINAL) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL) + Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL) + Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL) + Q_PROPERTY(int visibleItemCount READ visibleItemCount WRITE setVisibleItemCount NOTIFY visibleItemCountChanged FINAL) + +public: + explicit QQuickTumbler(QQuickItem *parent = nullptr); + ~QQuickTumbler(); + + QVariant model() const; + void setModel(const QVariant &model); + + int count() const; + + int currentIndex() const; + void setCurrentIndex(int currentIndex); + QQuickItem *currentItem() const; + + QQmlComponent *delegate() const; + void setDelegate(QQmlComponent *delegate); + + int visibleItemCount() const; + void setVisibleItemCount(int visibleItemCount); + + static QQuickTumblerAttached *qmlAttachedProperties(QObject *object); + +Q_SIGNALS: + void modelChanged(); + void countChanged(); + void currentIndexChanged(); + void currentItemChanged(); + void delegateChanged(); + void visibleItemCountChanged(); + +protected: + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + void componentComplete() override; + void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; + void keyPressEvent(QKeyEvent *event) override; + +private: + Q_DISABLE_COPY(QQuickTumbler) + Q_DECLARE_PRIVATE(QQuickTumbler) + + Q_PRIVATE_SLOT(d_func(), void _q_updateItemWidths()) + Q_PRIVATE_SLOT(d_func(), void _q_updateItemHeights()) +}; + +class QQuickTumblerAttachedPrivate; + +class Q_QUICKTEMPLATES2_EXPORT QQuickTumblerAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQuickTumbler *tumbler READ tumbler CONSTANT) + Q_PROPERTY(qreal displacement READ displacement NOTIFY displacementChanged FINAL) + +public: + explicit QQuickTumblerAttached(QQuickItem *delegateItem); + ~QQuickTumblerAttached(); + + QQuickTumbler *tumbler() const; + qreal displacement() const; + +Q_SIGNALS: + void displacementChanged(); + +private: + Q_DISABLE_COPY(QQuickTumblerAttached) + Q_DECLARE_PRIVATE(QQuickTumblerAttached) + + Q_PRIVATE_SLOT(d_func(), void _q_calculateDisplacement()) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickTumbler) +QML_DECLARE_TYPEINFO(QQuickTumbler, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QQUICKTUMBLER_H diff --git a/src/quicktemplates2/qquickvelocitycalculator.cpp b/src/quicktemplates2/qquickvelocitycalculator.cpp new file mode 100644 index 00000000..3d5fa4a4 --- /dev/null +++ b/src/quicktemplates2/qquickvelocitycalculator.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickvelocitycalculator_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/* + Usage: + + QQuickVelocityCalculator velocityCalculator; + + // ... + + velocityCalcular.startMeasuring(event->pos(), event->timestamp()); + velocityCalcular.stopMeasuring(event->pos(), event->timestamp()); + + // ... + + if (velocityCalculator.velocity().x() > someAmount) + doSomething(); + else if (velocityCalculator.velocity().x() < -someAmount) + doSomethingElse(); +*/ + +QQuickVelocityCalculator::QQuickVelocityCalculator() : + m_point1Timestamp(0), + m_point2Timestamp(0) +{ +} + +void QQuickVelocityCalculator::startMeasuring(const QPointF &point1, qint64 timestamp) +{ + m_point1 = point1; + + if (timestamp != 0) + m_point1Timestamp = timestamp; + else + m_timer.start(); +} + +void QQuickVelocityCalculator::stopMeasuring(const QPointF &point2, qint64 timestamp) +{ + if (timestamp == 0 && !m_timer.isValid()) { + qWarning() << "QQuickVelocityCalculator: a call to stopMeasuring() must be preceded by a call to startMeasuring()"; + return; + } + + m_point2 = point2; + m_point2Timestamp = timestamp != 0 ? timestamp : m_timer.elapsed(); + m_timer.invalidate(); +} + +void QQuickVelocityCalculator::reset() +{ + m_point1 = QPointF(); + m_point2 = QPointF(); + m_point1Timestamp = 0; + m_point2Timestamp = 0; + m_timer.invalidate(); +} + +QPointF QQuickVelocityCalculator::velocity() const +{ + if ((m_point2Timestamp == 0 || m_point1Timestamp == m_point2Timestamp) && !m_timer.isValid()) + return QPointF(); + + const qreal secondsElapsed = (m_point2Timestamp != 0 ? m_point2Timestamp - m_point1Timestamp : m_timer.elapsed()) / 1000.0; + const QPointF distance = m_point2 - m_point1; + return distance / secondsElapsed; +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickvelocitycalculator_p_p.h b/src/quicktemplates2/qquickvelocitycalculator_p_p.h new file mode 100644 index 00000000..bb4733ac --- /dev/null +++ b/src/quicktemplates2/qquickvelocitycalculator_p_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKVELOCITYCALCULATOR_P_P_H +#define QQUICKVELOCITYCALCULATOR_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickVelocityCalculator +{ +public: + QQuickVelocityCalculator(); + + void startMeasuring(const QPointF &point1, qint64 timestamp = 0); + void stopMeasuring(const QPointF &m_point2, qint64 timestamp = 0); + void reset(); + QPointF velocity() const; + +private: + QPointF m_point1; + QPointF m_point2; + qint64 m_point1Timestamp; + qint64 m_point2Timestamp; + // When a timestamp isn't available, we must use a timer. + // When stopMeasuring() has been called, we store the elapsed time in point2timestamp. + QElapsedTimer m_timer; +}; + +QT_END_NAMESPACE + +#endif // QQUICKVELOCITYCALCULATOR_P_P_H diff --git a/src/quicktemplates2/qtquicktemplates2global_p.h b/src/quicktemplates2/qtquicktemplates2global_p.h new file mode 100644 index 00000000..f962dc04 --- /dev/null +++ b/src/quicktemplates2/qtquicktemplates2global_p.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTQUICKTEMPLATES2GLOBAL_H +#define QTQUICKTEMPLATES2GLOBAL_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +#ifndef QT_STATIC +# if defined(QT_BUILD_QUICKTEMPLATES2_LIB) +# define Q_QUICKTEMPLATES2_EXPORT Q_DECL_EXPORT +# else +# define Q_QUICKTEMPLATES2_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_QUICKTEMPLATES2_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // QTQUICKTEMPLATES2GLOBAL_H diff --git a/src/quicktemplates2/quicktemplates2.pri b/src/quicktemplates2/quicktemplates2.pri new file mode 100644 index 00000000..e16d8b69 --- /dev/null +++ b/src/quicktemplates2/quicktemplates2.pri @@ -0,0 +1,109 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/qquickabstractbutton_p.h \ + $$PWD/qquickabstractbutton_p_p.h \ + $$PWD/qquickapplicationwindow_p.h \ + $$PWD/qquickbusyindicator_p.h \ + $$PWD/qquickbutton_p.h \ + $$PWD/qquickbuttongroup_p.h \ + $$PWD/qquickcheckbox_p.h \ + $$PWD/qquickcheckdelegate_p.h \ + $$PWD/qquickcombobox_p.h \ + $$PWD/qquickcontainer_p.h \ + $$PWD/qquickcontainer_p_p.h \ + $$PWD/qquickcontrol_p.h \ + $$PWD/qquickcontrol_p_p.h \ + $$PWD/qquickdial_p.h \ + $$PWD/qquickdrawer_p.h \ + $$PWD/qquickframe_p.h \ + $$PWD/qquickframe_p_p.h \ + $$PWD/qquickgroupbox_p.h \ + $$PWD/qquickitemdelegate_p.h \ + $$PWD/qquicklabel_p.h \ + $$PWD/qquicklabel_p_p.h \ + $$PWD/qquickmenu_p.h \ + $$PWD/qquickmenu_p_p.h \ + $$PWD/qquickmenuitem_p.h \ + $$PWD/qquickoverlay_p.h \ + $$PWD/qquickpage_p.h \ + $$PWD/qquickpageindicator_p.h \ + $$PWD/qquickpane_p.h \ + $$PWD/qquickpane_p_p.h \ + $$PWD/qquickpopup_p.h \ + $$PWD/qquickpopup_p_p.h \ + $$PWD/qquickpresshandler_p_p.h \ + $$PWD/qquickprogressbar_p.h \ + $$PWD/qquickradiobutton_p.h \ + $$PWD/qquickradiodelegate_p.h \ + $$PWD/qquickrangeslider_p.h \ + $$PWD/qquickscrollbar_p.h \ + $$PWD/qquickscrollindicator_p.h \ + $$PWD/qquickslider_p.h \ + $$PWD/qquickspinbox_p.h \ + $$PWD/qquickstackview_p.h \ + $$PWD/qquickstackview_p_p.h \ + $$PWD/qquickswipedelegate_p.h \ + $$PWD/qquickswipeview_p.h \ + $$PWD/qquickswitch_p.h \ + $$PWD/qquickswitchdelegate_p.h \ + $$PWD/qquicktabbar_p.h \ + $$PWD/qquicktabbutton_p.h \ + $$PWD/qquicktextarea_p.h \ + $$PWD/qquicktextarea_p_p.h \ + $$PWD/qquicktextfield_p.h \ + $$PWD/qquicktextfield_p_p.h \ + $$PWD/qquicktoolbar_p.h \ + $$PWD/qquicktoolbutton_p.h \ + $$PWD/qquicktooltip_p.h \ + $$PWD/qquicktumbler_p.h \ + $$PWD/qquickvelocitycalculator_p_p.h + +SOURCES += \ + $$PWD/qquickabstractbutton.cpp \ + $$PWD/qquickapplicationwindow.cpp \ + $$PWD/qquickbusyindicator.cpp \ + $$PWD/qquickbutton.cpp \ + $$PWD/qquickbuttongroup.cpp \ + $$PWD/qquickcheckbox.cpp \ + $$PWD/qquickcheckdelegate.cpp \ + $$PWD/qquickcombobox.cpp \ + $$PWD/qquickcontainer.cpp \ + $$PWD/qquickcontrol.cpp \ + $$PWD/qquickdial.cpp \ + $$PWD/qquickdrawer.cpp \ + $$PWD/qquickframe.cpp \ + $$PWD/qquickgroupbox.cpp \ + $$PWD/qquickitemdelegate.cpp \ + $$PWD/qquicklabel.cpp \ + $$PWD/qquickmenu.cpp \ + $$PWD/qquickmenuitem.cpp \ + $$PWD/qquickoverlay.cpp \ + $$PWD/qquickpage.cpp \ + $$PWD/qquickpageindicator.cpp \ + $$PWD/qquickpane.cpp \ + $$PWD/qquickpopup.cpp \ + $$PWD/qquickpresshandler.cpp \ + $$PWD/qquickprogressbar.cpp \ + $$PWD/qquickradiobutton.cpp \ + $$PWD/qquickradiodelegate.cpp \ + $$PWD/qquickrangeslider.cpp \ + $$PWD/qquickscrollbar.cpp \ + $$PWD/qquickscrollindicator.cpp \ + $$PWD/qquickslider.cpp \ + $$PWD/qquickspinbox.cpp \ + $$PWD/qquickstackview.cpp \ + $$PWD/qquickstackview_p.cpp \ + $$PWD/qquickswipedelegate.cpp \ + $$PWD/qquickswipeview.cpp \ + $$PWD/qquickswitch.cpp \ + $$PWD/qquickswitchdelegate.cpp \ + $$PWD/qquicktabbar.cpp \ + $$PWD/qquicktabbutton.cpp \ + $$PWD/qquicktextarea.cpp \ + $$PWD/qquicktextfield.cpp \ + $$PWD/qquicktoolbar.cpp \ + $$PWD/qquicktoolbutton.cpp \ + $$PWD/qquicktooltip.cpp \ + $$PWD/qquicktumbler.cpp \ + $$PWD/qquickvelocitycalculator.cpp diff --git a/src/quicktemplates2/quicktemplates2.pro b/src/quicktemplates2/quicktemplates2.pro new file mode 100644 index 00000000..59871a54 --- /dev/null +++ b/src/quicktemplates2/quicktemplates2.pro @@ -0,0 +1,14 @@ +TARGET = QtQuickTemplates2 +MODULE = quicktemplates2 +CONFIG += internal_module + +QT += quick +QT_PRIVATE += core-private gui-private qml-private quick-private + +DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII + +HEADERS += \ + $$PWD/qtquicktemplates2global_p.h + +include(quicktemplates2.pri) +load(qt_module) -- cgit v1.2.3