aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicktemplates2/qquicktooltip.cpp
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@theqtcompany.com>2016-04-13 15:59:53 +0200
committerJ-P Nurmi <jpnurmi@theqtcompany.com>2016-04-13 15:28:11 +0000
commita60c8e60d508117ddf48876b44d31e6d5ab98da6 (patch)
tree8bf008a1bf8dc34338450eee86d2b55e84cba36c /src/quicktemplates2/qquicktooltip.cpp
parente719087dce50d739c723c5ef9af2a9226318aa02 (diff)
Templates: rename the C++ module to qtquicktemplates2
Change-Id: I146da903b46f5c2caf865e37291c25376b49021a Reviewed-by: J-P Nurmi <jpnurmi@theqtcompany.com>
Diffstat (limited to 'src/quicktemplates2/qquicktooltip.cpp')
-rw-r--r--src/quicktemplates2/qquicktooltip.cpp560
1 files changed, 560 insertions, 0 deletions
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 <QtCore/qbasictimer.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQuick/qquickwindow.h>
+
+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<QQuickItem *>(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<QQuickToolTipAttached *>(qmlAttachedPropertiesObject<QQuickToolTip>(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<QQuickToolTip> 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<QQuickToolTip *>(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<QQuickItem *>(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