Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickmaterialripple.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtCore/qmath.h>
7#include <QtQuick/private/qquickitem_p.h>
8#include <QtQuick/private/qsgadaptationlayer_p.h>
9#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
10#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
11#include <QtQuickTemplates2/private/qquickabstractbutton_p_p.h>
12
14
16
17static const int RIPPLE_ENTER_DELAY = 80;
18static const int OPACITY_ENTER_DURATION_FAST = 120;
19static const int WAVE_OPACITY_DECAY_DURATION = 333;
20static const qreal WAVE_TOUCH_DOWN_ACCELERATION = 1024.0;
21
23{
24public:
26
27 void exit();
28 void updateCurrentTime(int time) override;
29 void sync(QQuickItem *item) override;
30
31private:
32 qreal m_from = 0;
33 qreal m_to = 0;
34 qreal m_value = 0;
35 WavePhase m_phase = WaveEnter;
36 QPointF m_anchor;
37 QRectF m_bounds;
38};
39
41 : QQuickAnimatedNode(ripple)
42{
43 start(qRound(1000.0 * qSqrt(ripple->diameter() / 2.0 / WAVE_TOUCH_DOWN_ACCELERATION)));
44
45 QSGOpacityNode *opacityNode = new QSGOpacityNode;
46 appendChildNode(opacityNode);
47
49 QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
50 rectNode->setAntialiasing(true);
51 opacityNode->appendChildNode(rectNode);
52}
53
62
64{
65 qreal p = 1.0;
66 if (duration() > 0)
67 p = time / static_cast<qreal>(duration());
68
69 m_value = m_from + (m_to - m_from) * p;
70 p = m_value / m_to;
71
72 const qreal dx = (1.0 - p) * (m_anchor.x() - m_bounds.width() / 2);
73 const qreal dy = (1.0 - p) * (m_anchor.y() - m_bounds.height() / 2);
74
76 m.translate(qRound((m_bounds.width() - m_value) / 2 + dx),
77 qRound((m_bounds.height() - m_value) / 2 + dy));
78 setMatrix(m);
79
80 QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(firstChild());
81 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
82 qreal opacity = 1.0;
83 if (m_phase == WaveExit)
84 opacity -= static_cast<qreal>(time) / WAVE_OPACITY_DECAY_DURATION;
85 opacityNode->setOpacity(opacity);
86
87 QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
88 Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
89 rectNode->setRect(QRectF(0, 0, m_value, m_value));
90 rectNode->setRadius(m_value / 2);
91 rectNode->setTopLeftRadius(-1);
92 rectNode->setTopRightRadius(-1);
93 rectNode->setBottomLeftRadius(-1);
94 rectNode->setBottomRightRadius(-1);
95 rectNode->update();
96}
97
99{
100 QQuickMaterialRipple *ripple = static_cast<QQuickMaterialRipple *>(item);
101 m_to = ripple->diameter();
102 m_anchor = ripple->anchorPoint();
103 m_bounds = ripple->boundingRect();
104
105 QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(firstChild());
106 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
107
108 QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
109 Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
110 rectNode->setColor(ripple->color());
111}
112
114{
116
117public:
119
120 void updateCurrentTime(int time) override;
121 void sync(QQuickItem *item) override;
122
123private:
124 bool m_active = false;
125};
126
128 : QQuickAnimatedNode(ripple)
129{
131
132 QSGOpacityNode *opacityNode = new QSGOpacityNode;
133 opacityNode->setOpacity(0.0);
134 appendChildNode(opacityNode);
135
137 QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
138 rectNode->setAntialiasing(true);
139 opacityNode->appendChildNode(rectNode);
140}
141
143{
144 qreal opacity = time / static_cast<qreal>(duration());
145 if (!m_active)
146 opacity = 1.0 - opacity;
147
148 QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(firstChild());
149 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
150 opacityNode->setOpacity(opacity);
151}
152
154{
155 QQuickMaterialRipple *ripple = static_cast<QQuickMaterialRipple *>(item);
156 if (m_active != ripple->isActive()) {
157 m_active = ripple->isActive();
159 restart();
160 }
161
162 QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(firstChild());
163 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
164
165 QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
166 Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
167
168 const qreal w = ripple->width();
169 const qreal h = ripple->height();
170 const qreal sz = qSqrt(w * w + h * h);
171
173 if (qFuzzyIsNull(ripple->clipRadius())) {
174 matrix.translate(qRound((w - sz) / 2), qRound((h - sz) / 2));
175 rectNode->setRect(QRectF(0, 0, sz, sz));
176 rectNode->setRadius(sz / 2);
177 } else {
178 rectNode->setRect(QRectF(0, 0, w, h));
179 rectNode->setRadius(ripple->clipRadius());
180 }
181 rectNode->setTopLeftRadius(-1);
182 rectNode->setTopRightRadius(-1);
183 rectNode->setBottomLeftRadius(-1);
184 rectNode->setBottomRightRadius(-1);
185
187 rectNode->setColor(ripple->color());
188 rectNode->update();
189}
190
196
198{
199 return m_active;
200}
201
203{
204 if (active == m_active)
205 return;
206
207 m_active = active;
208 update();
209}
210
212{
213 return m_color;
214}
215
217{
218 if (m_color == color)
219 return;
220
221 m_color = color;
222 update();
223}
224
226{
227 return m_clipRadius;
228}
229
231{
232 if (qFuzzyCompare(m_clipRadius, radius))
233 return;
234
235 m_clipRadius = radius;
236 update();
237}
238
240{
241 return m_pressed;
242}
243
245{
246 if (pressed == m_pressed)
247 return;
248
249 m_pressed = pressed;
250
251 if (!isEnabled()) {
252 exitWave();
253 return;
254 }
255
256 if (pressed) {
257 if (m_trigger == Press)
258 prepareWave();
259 else
260 exitWave();
261 } else {
262 if (m_trigger == Release)
263 enterWave();
264 else
265 exitWave();
266 }
267}
268
270{
271 return m_trigger;
272}
273
275{
276 m_trigger = trigger;
277}
278
280{
281 const QRectF bounds = boundingRect();
282 const QPointF center = bounds.center();
283 if (!m_anchor)
284 return center;
285
286 QPointF anchorPoint = bounds.center();
287 if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(m_anchor))
290
291 // calculate whether the anchor point is within the ripple circle bounds,
292 // that is, whether waves should start expanding from the anchor point
293 const qreal r = qSqrt(bounds.width() * bounds.width() + bounds.height() * bounds.height()) / 2;
294 if (QLineF(center, anchorPoint).length() < r)
295 return anchorPoint;
296
297 // if the anchor point is outside the ripple circle bounds, start expanding
298 // from the intersection point of the ripple circle and a line from its center
299 // to the the anchor point
300 const qreal p = qAtan2(anchorPoint.y() - center.y(), anchorPoint.x() - center.x());
301 return QPointF(center.x() + r * qCos(p), center.y() + r * qSin(p));
302}
303
305{
306 return m_anchor;
307}
308
310{
311 m_anchor = item;
312}
313
315{
316 const qreal w = width();
317 const qreal h = height();
318 return qSqrt(w * w + h * h);
319}
320
325
327{
329 QQuickDefaultClipNode *clipNode = d->clipNode();
330 if (clipNode) {
331 clipNode->setRadius(m_clipRadius);
332 clipNode->setRect(boundingRect());
333 clipNode->update();
334 }
335
336 QSGNode *container = oldNode;
337 if (!container)
338 container = new QSGNode;
339
340 QQuickMaterialRippleBackgroundNode *backgroundNode = static_cast<QQuickMaterialRippleBackgroundNode *>(container->firstChild());
341 if (!backgroundNode) {
342 backgroundNode = new QQuickMaterialRippleBackgroundNode(this);
343 backgroundNode->setObjectName(objectName());
344 container->appendChildNode(backgroundNode);
345 }
346 backgroundNode->sync(this);
347
348 // enter new waves
349 int i = m_waves;
350 QQuickMaterialRippleWaveNode *enterNode = static_cast<QQuickMaterialRippleWaveNode *>(backgroundNode->nextSibling());
351 while (i-- > 0) {
352 if (!enterNode) {
353 enterNode = new QQuickMaterialRippleWaveNode(this);
354 container->appendChildNode(enterNode);
355 }
356 enterNode->sync(this);
357 enterNode = static_cast<QQuickMaterialRippleWaveNode *>(enterNode->nextSibling());
358 }
359
360 // exit old waves
361 int j = container->childCount() - 1 - m_waves;
362 while (j-- > 0) {
363 QQuickMaterialRippleWaveNode *exitNode = static_cast<QQuickMaterialRippleWaveNode *>(backgroundNode->nextSibling());
364 if (exitNode) {
365 exitNode->exit();
366 exitNode->sync(this);
367 }
368 }
369
370 return container;
371}
372
374{
376
377 if (event->timerId() == m_enterDelay)
378 enterWave();
379}
380
382{
383 if (m_enterDelay <= 0)
384 m_enterDelay = startTimer(RIPPLE_ENTER_DELAY);
385}
386
388{
389 if (m_enterDelay > 0) {
390 killTimer(m_enterDelay);
391 m_enterDelay = 0;
392 }
393
394 ++m_waves;
395 update();
396}
397
399{
400 if (m_enterDelay > 0) {
401 killTimer(m_enterDelay);
402 m_enterDelay = 0;
403 }
404
405 if (m_waves > 0) {
406 --m_waves;
407 update();
408 }
409}
410
412
413#include "moc_qquickmaterialripple_p.cpp"
414
415#include "qquickmaterialripple.moc"
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
void translate(const QVector3D &vector)
Multiplies this matrix by another that translates coordinates by the components of vector.
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
This is an overloaded function that will start a timer of type timerType and a timeout of interval mi...
Definition qobject.cpp:1817
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QString objectName
the name of this object
Definition qobject.h:107
virtual void timerEvent(QTimerEvent *event)
This event handler can be reimplemented in a subclass to receive timer events for the object.
Definition qobject.cpp:1470
void killTimer(int id)
Kills the timer with timer identifier, id.
Definition qobject.cpp:1912
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
static QQuickAbstractButtonPrivate * get(QQuickAbstractButton *button)
void setDuration(int duration)
void setRect(const QRectF &)
void setRadius(qreal radius)
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
Q_INVOKABLE QPointF mapFromItem(const QQuickItem *item, const QPointF &point) const
Maps the given point in item's coordinate system to the equivalent point within this item's coordinat...
void setFlag(Flag flag, bool enabled=true)
Enables the specified flag for this item if enabled is true; if enabled is false, the flag is disable...
virtual QRectF boundingRect() const
Returns the extents of the item in its own coordinate system: a rectangle from {0,...
qreal width
This property holds the width of this item.
Definition qquickitem.h:75
virtual void itemChange(ItemChange, const ItemChangeData &)
Called when change occurs for this item.
bool isEnabled() const
qreal height
This property holds the height of this item.
Definition qquickitem.h:76
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:144
void update()
Schedules a call to updatePaintNode() for this item.
QQuickMaterialRippleBackgroundNode(QQuickMaterialRipple *ripple)
void sync(QQuickItem *item) override
void updateCurrentTime(int time) override
void sync(QQuickItem *item) override
QQuickMaterialRippleWaveNode(QQuickMaterialRipple *ripple)
void setPressed(bool pressed)
QSGNode * updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override
Called on the render thread when it is time to sync the state of the item with the scene graph.
void setClipRadius(qreal radius)
void setAnchor(QQuickItem *anchor)
void itemChange(ItemChange change, const ItemChangeData &data) override
Called when change occurs for this item.
void setColor(const QColor &color)
void setTrigger(Trigger trigger)
void timerEvent(QTimerEvent *event) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
QQuickMaterialRipple(QQuickItem *parent=nullptr)
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr QPointF center() const noexcept
Returns the center point of the rectangle.
Definition qrect.h:699
virtual void setAntialiasing(bool antialiasing)
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
int childCount() const
Returns the number of child nodes.
Definition qsgnode.cpp:556
void appendChildNode(QSGNode *node)
Appends node to this node's list of children.
Definition qsgnode.cpp:398
@ GeometryNodeType
Definition qsgnode.h:41
@ OpacityNodeType
Definition qsgnode.h:44
QSGNode * firstChild() const
Returns the first child of this node.
Definition qsgnode.h:105
NodeType type() const
Returns the type of this node.
Definition qsgnode.h:110
The QSGOpacityNode class is used to change opacity of nodes.
Definition qsgnode.h:276
void setOpacity(qreal opacity)
Sets the opacity of this node to opacity.
Definition qsgnode.cpp:1312
void setMatrix(const QMatrix4x4 &matrix)
Sets this transform node's matrix to matrix.
Definition qsgnode.cpp:1162
const QMatrix4x4 & matrix() const
Returns this transform node's matrix.
Definition qsgnode.h:247
\inmodule QtCore
Definition qcoreevent.h:366
QPushButton * button
[2]
Combined button and popup list for selecting options.
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:289
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
auto qAtan2(T1 y, T2 x)
Definition qmath.h:90
auto qCos(T v)
Definition qmath.h:60
auto qSin(T v)
Definition qmath.h:54
const GLfloat * m
GLfloat GLfloat GLfloat w
[0]
GLboolean r
[2]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint color
[2]
GLuint start
GLfloat GLfloat GLfloat GLfloat h
struct _cl_event * event
GLuint GLenum matrix
GLfloat GLfloat p
[1]
static const int WAVE_OPACITY_DECAY_DURATION
static const qreal WAVE_TOUCH_DOWN_ACCELERATION
static const int RIPPLE_ENTER_DELAY
static const int OPACITY_ENTER_DURATION_FAST
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_OBJECT
double qreal
Definition qtypes.h:187
QGraphicsItem * item
\inmodule QtQuick
Definition qquickitem.h:159