Qt 6.x
The Qt SDK
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
55{
56 m_phase = WaveExit;
57 m_from = m_value;
59 restart();
61}
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());
89 rectNode->setRect(QRectF(0, 0, m_value, m_value));
90 rectNode->setRadius(m_value / 2);
91 rectNode->update();
92}
93
95{
96 QQuickMaterialRipple *ripple = static_cast<QQuickMaterialRipple *>(item);
97 m_to = ripple->diameter();
98 m_anchor = ripple->anchorPoint();
99 m_bounds = ripple->boundingRect();
100
101 QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(firstChild());
102 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
103
104 QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
106 rectNode->setColor(ripple->color());
107}
108
110{
112
113public:
115
116 void updateCurrentTime(int time) override;
117 void sync(QQuickItem *item) override;
118
119private:
120 bool m_active = false;
121};
122
124 : QQuickAnimatedNode(ripple)
125{
127
128 QSGOpacityNode *opacityNode = new QSGOpacityNode;
129 opacityNode->setOpacity(0.0);
130 appendChildNode(opacityNode);
131
133 QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
134 rectNode->setAntialiasing(true);
135 opacityNode->appendChildNode(rectNode);
136}
137
139{
140 qreal opacity = time / static_cast<qreal>(duration());
141 if (!m_active)
142 opacity = 1.0 - opacity;
143
144 QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(firstChild());
145 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
146 opacityNode->setOpacity(opacity);
147}
148
150{
151 QQuickMaterialRipple *ripple = static_cast<QQuickMaterialRipple *>(item);
152 if (m_active != ripple->isActive()) {
153 m_active = ripple->isActive();
155 restart();
156 }
157
158 QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(firstChild());
159 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
160
161 QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
163
164 const qreal w = ripple->width();
165 const qreal h = ripple->height();
166 const qreal sz = qSqrt(w * w + h * h);
167
169 if (qFuzzyIsNull(ripple->clipRadius())) {
170 matrix.translate(qRound((w - sz) / 2), qRound((h - sz) / 2));
171 rectNode->setRect(QRectF(0, 0, sz, sz));
172 rectNode->setRadius(sz / 2);
173 } else {
174 rectNode->setRect(QRectF(0, 0, w, h));
175 rectNode->setRadius(ripple->clipRadius());
176 }
177
179 rectNode->setColor(ripple->color());
180 rectNode->update();
181}
182
185{
187}
188
190{
191 return m_active;
192}
193
195{
196 if (active == m_active)
197 return;
198
199 m_active = active;
200 update();
201}
202
204{
205 return m_color;
206}
207
209{
210 if (m_color == color)
211 return;
212
213 m_color = color;
214 update();
215}
216
218{
219 return m_clipRadius;
220}
221
223{
224 if (qFuzzyCompare(m_clipRadius, radius))
225 return;
226
227 m_clipRadius = radius;
228 update();
229}
230
232{
233 return m_pressed;
234}
235
237{
238 if (pressed == m_pressed)
239 return;
240
241 m_pressed = pressed;
242
243 if (!isEnabled()) {
244 exitWave();
245 return;
246 }
247
248 if (pressed) {
249 if (m_trigger == Press)
250 prepareWave();
251 else
252 exitWave();
253 } else {
254 if (m_trigger == Release)
255 enterWave();
256 else
257 exitWave();
258 }
259}
260
262{
263 return m_trigger;
264}
265
267{
268 m_trigger = trigger;
269}
270
272{
273 const QRectF bounds = boundingRect();
274 const QPointF center = bounds.center();
275 if (!m_anchor)
276 return center;
277
278 QPointF anchorPoint = bounds.center();
279 if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(m_anchor))
282
283 // calculate whether the anchor point is within the ripple circle bounds,
284 // that is, whether waves should start expanding from the anchor point
285 const qreal r = qSqrt(bounds.width() * bounds.width() + bounds.height() * bounds.height()) / 2;
286 if (QLineF(center, anchorPoint).length() < r)
287 return anchorPoint;
288
289 // if the anchor point is outside the ripple circle bounds, start expanding
290 // from the intersection point of the ripple circle and a line from its center
291 // to the the anchor point
292 const qreal p = qAtan2(anchorPoint.y() - center.y(), anchorPoint.x() - center.x());
293 return QPointF(center.x() + r * qCos(p), center.y() + r * qSin(p));
294}
295
297{
298 return m_anchor;
299}
300
302{
303 m_anchor = item;
304}
305
307{
308 const qreal w = width();
309 const qreal h = height();
310 return qSqrt(w * w + h * h);
311}
312
314{
316}
317
319{
321 QQuickDefaultClipNode *clipNode = d->clipNode();
322 if (clipNode) {
323 clipNode->setRadius(m_clipRadius);
324 clipNode->setRect(boundingRect());
325 clipNode->update();
326 }
327
328 QSGNode *container = oldNode;
329 if (!container)
330 container = new QSGNode;
331
332 QQuickMaterialRippleBackgroundNode *backgroundNode = static_cast<QQuickMaterialRippleBackgroundNode *>(container->firstChild());
333 if (!backgroundNode) {
334 backgroundNode = new QQuickMaterialRippleBackgroundNode(this);
335 backgroundNode->setObjectName(objectName());
336 container->appendChildNode(backgroundNode);
337 }
338 backgroundNode->sync(this);
339
340 // enter new waves
341 int i = m_waves;
342 QQuickMaterialRippleWaveNode *enterNode = static_cast<QQuickMaterialRippleWaveNode *>(backgroundNode->nextSibling());
343 while (i-- > 0) {
344 if (!enterNode) {
345 enterNode = new QQuickMaterialRippleWaveNode(this);
346 container->appendChildNode(enterNode);
347 }
348 enterNode->sync(this);
349 enterNode = static_cast<QQuickMaterialRippleWaveNode *>(enterNode->nextSibling());
350 }
351
352 // exit old waves
353 int j = container->childCount() - 1 - m_waves;
354 while (j-- > 0) {
355 QQuickMaterialRippleWaveNode *exitNode = static_cast<QQuickMaterialRippleWaveNode *>(backgroundNode->nextSibling());
356 if (exitNode) {
357 exitNode->exit();
358 exitNode->sync(this);
359 }
360 }
361
362 return container;
363}
364
366{
368
369 if (event->timerId() == m_enterDelay)
370 enterWave();
371}
372
374{
375 if (m_enterDelay <= 0)
376 m_enterDelay = startTimer(RIPPLE_ENTER_DELAY);
377}
378
380{
381 if (m_enterDelay > 0) {
382 killTimer(m_enterDelay);
383 m_enterDelay = 0;
384 }
385
386 ++m_waves;
387 update();
388}
389
391{
392 if (m_enterDelay > 0) {
393 killTimer(m_enterDelay);
394 m_enterDelay = 0;
395 }
396
397 if (m_waves > 0) {
398 --m_waves;
399 update();
400 }
401}
402
404
405#include "moc_qquickmaterialripple_p.cpp"
406
407#include "qquickmaterialripple.moc"
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
\inmodule QtCore
Definition qline.h:182
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:1792
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
QString objectName
the name of this object
Definition qobject.h:94
virtual void timerEvent(QTimerEvent *event)
This event handler can be reimplemented in a subclass to receive timer events for the object.
Definition qobject.cpp:1433
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:114
void killTimer(int id)
Kills the timer with timer identifier, id.
Definition qobject.cpp:1872
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:338
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:64
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:76
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:77
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:143
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:483
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
constexpr QPointF center() const noexcept
Returns the center point of the rectangle.
Definition qrect.h:685
virtual void setRadius(qreal radius)=0
virtual void setAntialiasing(bool antialiasing)
virtual void setRect(const QRectF &rect)=0
virtual void update()=0
virtual void setColor(const QColor &color)=0
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
QSGNode * nextSibling() const
Returns the node after this in the parent's list of children.
Definition qsgnode.h:107
int childCount() const
Returns the number of child nodes.
Definition qsgnode.cpp:554
void appendChildNode(QSGNode *node)
Appends node to this node's list of children.
Definition qsgnode.cpp:396
@ 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:279
void setOpacity(qreal opacity)
Sets the opacity of this node to opacity.
Definition qsgnode.cpp:1310
void setMatrix(const QMatrix4x4 &matrix)
Sets this transform node's matrix to matrix.
Definition qsgnode.cpp:1160
const QMatrix4x4 & matrix() const
Returns this transform node's matrix.
Definition qsgnode.h:250
\inmodule QtCore
Definition qcoreevent.h:359
QPushButton * button
[2]
Combined button and popup list for selecting options.
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:287
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:303
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:243
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:281
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 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:92
QGraphicsItem * item
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent
\inmodule QtQuick
Definition qquickitem.h:158