7#include <QtCore/qmath.h>
8#include <QtQuick/private/qquickitem_p.h>
9#include <QtQuick/private/qsgadaptationlayer_p.h>
10#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
11#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
12#include <QtQuickTemplates2/private/qquickabstractbutton_p_p.h>
30 void sync(QQuickItem *item)
override;
33 void updateWaveNode();
44 qreal m_opacity = 1.0;
45 qreal m_newOpacity = 1.0;
47 QQuickWindow *m_window =
nullptr;
48 QMetaObject::Connection m_animationConnection;
54 start(qRound(1000.0 * qSqrt(ripple->diameter() / 2.0 / WAVE_TOUCH_DOWN_ACCELERATION)));
56 QSGOpacityNode *opacityNode =
new QSGOpacityNode;
57 appendChildNode(opacityNode);
59 QQuickItemPrivate *d = QQuickItemPrivate::get(ripple);
60 QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
61 rectNode->setAntialiasing(
true);
62 opacityNode->appendChildNode(rectNode);
64 m_window = ripple->window();
66 connect(
this, &QQuickAnimatedNode::started,
this, [
this]() {
67 this->m_animationConnection = connect(
69 &QQuickWindow::beforeFrameBegin,
72 Qt::DirectConnection);
74 connect(
this, &QQuickAnimatedNode::stopped,
this, [
this]() {
75 disconnect(
this->m_animationConnection);
85 connect(
this, &QQuickAnimatedNode::stopped,
this, &QObject::deleteLater);
92 p = time /
static_cast<qreal>(duration());
94 m_newValue = m_from + (m_to - m_from) * p;
96 if (m_phase == WaveExit)
97 m_newOpacity = 1.0 -
static_cast<qreal>(time) / WAVE_OPACITY_DECAY_DURATION;
102 QQuickMaterialRipple *ripple =
static_cast<QQuickMaterialRipple *>(item);
103 m_to = ripple->diameter();
104 m_anchor = ripple->anchorPoint();
105 m_bounds = ripple->boundingRect();
107 QSGOpacityNode *opacityNode =
static_cast<QSGOpacityNode *>(firstChild());
108 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
110 QSGInternalRectangleNode *rectNode =
static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
111 Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
112 rectNode->setColor(ripple->color());
117 QSGOpacityNode *opacityNode =
static_cast<QSGOpacityNode *>(firstChild());
118 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
119 if (!qFuzzyCompare(m_opacity, m_newOpacity)) {
120 m_opacity = m_newOpacity;
121 opacityNode->setOpacity(m_opacity);
124 if (qFuzzyCompare(m_value, m_newValue))
127 m_value = m_newValue;
129 qreal p = m_value / m_to;
131 const qreal dx = (1.0 - p) * (m_anchor.x() - m_bounds.width() / 2);
132 const qreal dy = (1.0 - p) * (m_anchor.y() - m_bounds.height() / 2);
135 m.translate(qRound((m_bounds.width() - m_value) / 2 + dx),
136 qRound((m_bounds.height() - m_value) / 2 + dy));
139 QSGInternalRectangleNode *rectNode =
static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
140 Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
141 rectNode->setRect(QRectF(0, 0, m_value, m_value));
142 rectNode->setRadius(m_value / 2);
154 void sync(QQuickItem *item)
override;
157 void updateBackgroundNode();
159 bool m_active =
false;
161 qreal m_opacity = 0.0;
162 qreal m_newOpacity = 0.0;
164 QQuickWindow *m_window =
nullptr;
165 QMetaObject::Connection m_animationConnection;
169 : QQuickAnimatedNode(ripple)
173 QSGOpacityNode *opacityNode =
new QSGOpacityNode;
174 opacityNode->setOpacity(0.0);
175 appendChildNode(opacityNode);
177 QQuickItemPrivate *d = QQuickItemPrivate::get(ripple);
178 QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
179 rectNode->setAntialiasing(
true);
180 opacityNode->appendChildNode(rectNode);
182 m_window = ripple->window();
183 connect(
this, &QQuickAnimatedNode::started,
this, [
this]() {
184 this->m_animationConnection = connect(
186 &QQuickWindow::beforeFrameBegin,
189 Qt::DirectConnection);
191 connect(
this, &QQuickAnimatedNode::stopped,
192 this, [
this]() { disconnect(
this->m_animationConnection); });
197 qreal opacity = time /
static_cast<qreal>(duration());
199 opacity = 1.0 - opacity;
201 QSGOpacityNode *opacityNode =
static_cast<QSGOpacityNode *>(firstChild());
202 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
203 m_newOpacity = opacity;
208 QQuickMaterialRipple *ripple =
static_cast<QQuickMaterialRipple *>(item);
209 if (m_active != ripple->isActive()) {
210 m_active = ripple->isActive();
215 QSGOpacityNode *opacityNode =
static_cast<QSGOpacityNode *>(firstChild());
216 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
218 QSGInternalRectangleNode *rectNode =
static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
219 Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
221 const qreal w = ripple->width();
222 const qreal h = ripple->height();
223 const qreal sz = qSqrt(w * w + h * h);
226 if (qFuzzyIsNull(ripple->clipRadius())) {
227 matrix.translate(qRound((w - sz) / 2), qRound((h - sz) / 2));
228 rectNode->setRect(QRectF(0, 0, sz, sz));
229 rectNode->setRadius(sz / 2);
231 rectNode->setRect(QRectF(0, 0, w, h));
232 rectNode->setRadius(ripple->clipRadius());
236 rectNode->setColor(ripple->color());
242 if (m_opacity == m_newOpacity)
245 m_opacity = m_newOpacity;
246 QSGOpacityNode *opacityNode =
static_cast<QSGOpacityNode *>(firstChild());
247 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
248 opacityNode->setOpacity(m_opacity);
251QQuickMaterialRipple::QQuickMaterialRipple(QQuickItem *parent)
254 setFlag(ItemHasContents);
257bool QQuickMaterialRipple::isActive()
const
262void QQuickMaterialRipple::setActive(
bool active)
264 if (active == m_active)
271QColor QQuickMaterialRipple::color()
const
276void QQuickMaterialRipple::setColor(
const QColor &color)
278 if (m_color == color)
285qreal QQuickMaterialRipple::clipRadius()
const
290void QQuickMaterialRipple::setClipRadius(qreal radius)
292 if (qFuzzyCompare(m_clipRadius, radius))
295 m_clipRadius = radius;
299bool QQuickMaterialRipple::isPressed()
const
304void QQuickMaterialRipple::setPressed(
bool pressed)
306 if (pressed == m_pressed)
317 if (m_trigger == Press)
322 if (m_trigger == Release)
329QQuickMaterialRipple::Trigger QQuickMaterialRipple::trigger()
const
334void QQuickMaterialRipple::setTrigger(Trigger trigger)
339QPointF QQuickMaterialRipple::anchorPoint()
const
341 const QRectF bounds = boundingRect();
342 const QPointF center = bounds.center();
346 QPointF anchorPoint = bounds.center();
347 if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(m_anchor))
348 anchorPoint = QQuickAbstractButtonPrivate::get(button)->pressPoint;
349 anchorPoint = mapFromItem(m_anchor, anchorPoint);
353 const qreal r = qSqrt(bounds.width() * bounds.width() + bounds.height() * bounds.height()) / 2;
354 if (QLineF(center, anchorPoint).length() < r)
360 const qreal p = qAtan2(anchorPoint.y() - center.y(), anchorPoint.x() - center.x());
361 return QPointF(center.x() + r * qCos(p), center.y() + r * qSin(p));
364QQuickItem *QQuickMaterialRipple::anchor()
const
369void QQuickMaterialRipple::setAnchor(QQuickItem *item)
374qreal QQuickMaterialRipple::diameter()
const
376 const qreal w = width();
377 const qreal h = height();
378 return qSqrt(w * w + h * h);
381void QQuickMaterialRipple::itemChange(ItemChange change,
const ItemChangeData &data)
383 QQuickItem::itemChange(change, data);
386QSGNode *QQuickMaterialRipple::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
388 QQuickItemPrivate *d = QQuickItemPrivate::get(
this);
389 QQuickDefaultClipNode *clipNode = d->clipNode();
391 clipNode->setRadius(m_clipRadius);
392 clipNode->setRect(boundingRect());
396 QSGNode *container = oldNode;
398 container =
new QSGNode;
401 if (!backgroundNode) {
402 backgroundNode =
new QQuickMaterialRippleBackgroundNode(
this);
403 backgroundNode->setObjectName(objectName());
404 container->appendChildNode(backgroundNode);
406 backgroundNode->sync(
this);
414 container->appendChildNode(enterNode);
416 enterNode->sync(
this);
421 int j = container->childCount() - 1 - m_waves;
426 exitNode->sync(
this);
433void QQuickMaterialRipple::timerEvent(QTimerEvent *event)
435 QQuickItem::timerEvent(event);
437 if (event->timerId() == m_enterDelay)
441void QQuickMaterialRipple::prepareWave()
443 if (m_enterDelay <= 0)
447void QQuickMaterialRipple::enterWave()
449 if (m_enterDelay > 0) {
450 killTimer(m_enterDelay);
458void QQuickMaterialRipple::exitWave()
460 if (m_enterDelay > 0) {
461 killTimer(m_enterDelay);
473#include "moc_qquickmaterialripple_p.cpp"
475#include "qquickmaterialripple.moc"
void updateCurrentTime(int time) override
void sync(QQuickItem *item) override
void updateCurrentTime(int time) override
void sync(QQuickItem *item) override
QQuickMaterialRippleWaveNode(QQuickMaterialRipple *ripple)
Combined button and popup list for selecting options.
static const int WAVE_OPACITY_DECAY_DURATION
static const int RIPPLE_ENTER_DELAY
static const int OPACITY_ENTER_DURATION_FAST
static const qreal WAVE_TOUCH_DOWN_ACCELERATION