| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2019 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the QtQuick module of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:LGPL$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU Lesser General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | 
| 21 | ** packaging of this file. Please review the following information to | 
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements | 
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | 
| 24 | ** | 
| 25 | ** GNU General Public License Usage | 
| 26 | ** Alternatively, this file may be used under the terms of the GNU | 
| 27 | ** General Public License version 2.0 or (at your option) the GNU General | 
| 28 | ** Public license version 3 or any later version approved by the KDE Free | 
| 29 | ** Qt Foundation. The licenses are as published by the Free Software | 
| 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
| 31 | ** included in the packaging of this file. Please review the following | 
| 32 | ** information to ensure the GNU General Public License requirements will | 
| 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
| 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
| 35 | ** | 
| 36 | ** $QT_END_LICENSE$ | 
| 37 | ** | 
| 38 | ****************************************************************************/ | 
| 39 |  | 
| 40 | #include "qquickboundaryrule_p.h" | 
| 41 |  | 
| 42 | #include <qqmlcontext.h> | 
| 43 | #include <qqmlinfo.h> | 
| 44 | #include <private/qqmlproperty_p.h> | 
| 45 | #include <private/qqmlengine_p.h> | 
| 46 | #include <private/qobject_p.h> | 
| 47 | #include <private/qquickanimation_p_p.h> | 
| 48 | #include <QtCore/qloggingcategory.h> | 
| 49 |  | 
| 50 | QT_BEGIN_NAMESPACE | 
| 51 |  | 
| 52 | Q_LOGGING_CATEGORY(lcBR, "qt.quick.boundaryrule" ) | 
| 53 |  | 
| 54 | class QQuickBoundaryReturnJob; | 
| 55 | class QQuickBoundaryRulePrivate : public QObjectPrivate | 
| 56 | { | 
| 57 |     Q_DECLARE_PUBLIC(QQuickBoundaryRule) | 
| 58 | public: | 
| 59 |     QQuickBoundaryRulePrivate() {} | 
| 60 |  | 
| 61 |     QQmlProperty property; | 
| 62 |     QEasingCurve easing = QEasingCurve(QEasingCurve::OutQuad); | 
| 63 |     QQuickBoundaryReturnJob *returnAnimationJob = nullptr; | 
| 64 |     // read-only properties, updated on each write() | 
| 65 |     qreal targetValue = 0; // after easing was applied | 
| 66 |     qreal peakOvershoot = 0; | 
| 67 |     qreal currentOvershoot = 0; | 
| 68 |     // settable properties | 
| 69 |     qreal minimum = 0; | 
| 70 |     qreal maximum = 0; | 
| 71 |     qreal minimumOvershoot = 0; | 
| 72 |     qreal maximumOvershoot = 0; | 
| 73 |     qreal overshootScale = 0.5; | 
| 74 |     int returnDuration = 100; | 
| 75 |     QQuickBoundaryRule::OvershootFilter overshootFilter = QQuickBoundaryRule::OvershootFilter::None; | 
| 76 |     bool enabled = true; | 
| 77 |     bool finalized = false; | 
| 78 |  | 
| 79 |     qreal easedOvershoot(qreal overshootingValue); | 
| 80 |     void resetOvershoot(); | 
| 81 | }; | 
| 82 |  | 
| 83 | class QQuickBoundaryReturnJob : public QAbstractAnimationJob | 
| 84 | { | 
| 85 | public: | 
| 86 |     QQuickBoundaryReturnJob(QQuickBoundaryRulePrivate *br, qreal to) | 
| 87 |         : QAbstractAnimationJob() | 
| 88 |         , boundaryRule(br) | 
| 89 |         , fromValue(br->targetValue) | 
| 90 |         , toValue(to) {} | 
| 91 |  | 
| 92 |     int duration() const override { return boundaryRule->returnDuration; } | 
| 93 |  | 
| 94 |     void updateCurrentTime(int) override; | 
| 95 |  | 
| 96 |     void updateState(QAbstractAnimationJob::State newState, | 
| 97 |                      QAbstractAnimationJob::State oldState) override; | 
| 98 |  | 
| 99 |     QQuickBoundaryRulePrivate *boundaryRule; | 
| 100 |     qreal fromValue;    // snapshot of initial value from which we're returning | 
| 101 |     qreal toValue;      // target property value to which we're returning | 
| 102 | }; | 
| 103 |  | 
| 104 | void QQuickBoundaryReturnJob::updateCurrentTime(int t) | 
| 105 | { | 
| 106 |     // The easing property tells how to behave when the property is being | 
| 107 |     // externally manipulated beyond the bounds.  During returnToBounds() | 
| 108 |     // we run it in reverse, by reversing time. | 
| 109 |     qreal progress = (duration() - t) / qreal(duration()); | 
| 110 |     qreal easingValue = boundaryRule->easing.valueForProgress(progress); | 
| 111 |     qreal delta = qAbs(t: fromValue - toValue) * easingValue; | 
| 112 |     qreal value = (fromValue > toValue ? toValue + delta : toValue - delta); | 
| 113 |     qCDebug(lcBR) << t << "ms"  << qRound(d: progress * 100) << "% easing"  << easingValue << "->"  << value; | 
| 114 |     QQmlPropertyPrivate::write(that: boundaryRule->property, value, | 
| 115 |                                QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); | 
| 116 | } | 
| 117 |  | 
| 118 | void QQuickBoundaryReturnJob::updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState) | 
| 119 | { | 
| 120 |     Q_UNUSED(oldState) | 
| 121 |     if (newState == QAbstractAnimationJob::Stopped) { | 
| 122 |         qCDebug(lcBR) << "return animation done" ; | 
| 123 |         boundaryRule->resetOvershoot(); | 
| 124 |         boundaryRule->returnAnimationJob = nullptr; | 
| 125 |         delete this; | 
| 126 |     } | 
| 127 | } | 
| 128 |  | 
| 129 | /*! | 
| 130 |     \qmltype BoundaryRule | 
| 131 |     \instantiates QQuickBoundaryRule | 
| 132 |     \inqmlmodule Qt.labs.animation | 
| 133 |     \ingroup qtquick-transitions-animations | 
| 134 |     \ingroup qtquick-interceptors | 
| 135 |     \brief Defines a restriction on the range of values that can be set on a numeric property. | 
| 136 |     \since 5.14 | 
| 137 |  | 
| 138 |     A BoundaryRule defines the range of values that a particular property is | 
| 139 |     allowed to have.  When an out-of-range value would otherwise be set, | 
| 140 |     it applies "resistance" via an easing curve. | 
| 141 |  | 
| 142 |     For example, the following BoundaryRule prevents DragHandler from dragging | 
| 143 |     the Rectangle too far: | 
| 144 |  | 
| 145 |     \snippet qml/boundaryRule.qml 0 | 
| 146 |  | 
| 147 |     Note that a property cannot have more than one assigned BoundaryRule. | 
| 148 |  | 
| 149 |     \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation#Behaviors}{Behavior example}, {Qt QML} | 
| 150 | */ | 
| 151 |  | 
| 152 | QQuickBoundaryRule::QQuickBoundaryRule(QObject *parent) | 
| 153 |     : QObject(*(new QQuickBoundaryRulePrivate), parent) | 
| 154 |     , QQmlPropertyValueInterceptor() | 
| 155 | { | 
| 156 | } | 
| 157 |  | 
| 158 | QQuickBoundaryRule::~QQuickBoundaryRule() | 
| 159 | { | 
| 160 |     Q_D(QQuickBoundaryRule); | 
| 161 |     // stop any running animation and | 
| 162 |     // prevent QQuickBoundaryReturnJob::updateState() from accessing QQuickBoundaryRulePrivate | 
| 163 |     delete d->returnAnimationJob; | 
| 164 | } | 
| 165 |  | 
| 166 | /*! | 
| 167 |     \qmlproperty bool QtQuick::BoundaryRule::enabled | 
| 168 |  | 
| 169 |     This property holds whether the rule will be enforced when the tracked | 
| 170 |     property changes value. | 
| 171 |  | 
| 172 |     By default a BoundaryRule is enabled. | 
| 173 | */ | 
| 174 | bool QQuickBoundaryRule::enabled() const | 
| 175 | { | 
| 176 |     Q_D(const QQuickBoundaryRule); | 
| 177 |     return d->enabled; | 
| 178 | } | 
| 179 |  | 
| 180 | void QQuickBoundaryRule::setEnabled(bool enabled) | 
| 181 | { | 
| 182 |     Q_D(QQuickBoundaryRule); | 
| 183 |     if (d->enabled == enabled) | 
| 184 |         return; | 
| 185 |     d->enabled = enabled; | 
| 186 |     emit enabledChanged(); | 
| 187 | } | 
| 188 |  | 
| 189 | /*! | 
| 190 |     \qmlproperty qreal QtQuick::BoundaryRule::minimum | 
| 191 |  | 
| 192 |     This property holds the smallest unconstrained value that the property is | 
| 193 |     allowed to have.  If the property is set to a smaller value, it will be | 
| 194 |     constrained by \l easing and \l minimumOvershoot. | 
| 195 |  | 
| 196 |     The default is \c 0. | 
| 197 | */ | 
| 198 | qreal QQuickBoundaryRule::minimum() const | 
| 199 | { | 
| 200 |     Q_D(const QQuickBoundaryRule); | 
| 201 |     return d->minimum; | 
| 202 | } | 
| 203 |  | 
| 204 | void QQuickBoundaryRule::setMinimum(qreal minimum) | 
| 205 | { | 
| 206 |     Q_D(QQuickBoundaryRule); | 
| 207 |     if (qFuzzyCompare(p1: d->minimum, p2: minimum)) | 
| 208 |         return; | 
| 209 |     d->minimum = minimum; | 
| 210 |     emit minimumChanged(); | 
| 211 | } | 
| 212 |  | 
| 213 | /*! | 
| 214 |     \qmlproperty qreal QtQuick::BoundaryRule::minimumOvershoot | 
| 215 |  | 
| 216 |     This property holds the amount that the property is allowed to be | 
| 217 |     less than \l minimum.  Whenever the value is less than \l minimum | 
| 218 |     and greater than \c {minimum - minimumOvershoot}, it is constrained | 
| 219 |     by the \l easing curve.  When the value attempts to go under | 
| 220 |     \c {minimum - minimumOvershoots} there is a hard stop. | 
| 221 |  | 
| 222 |     The default is \c 0. | 
| 223 | */ | 
| 224 | qreal QQuickBoundaryRule::minimumOvershoot() const | 
| 225 | { | 
| 226 |     Q_D(const QQuickBoundaryRule); | 
| 227 |     return d->minimumOvershoot; | 
| 228 | } | 
| 229 |  | 
| 230 | void QQuickBoundaryRule::setMinimumOvershoot(qreal minimumOvershoot) | 
| 231 | { | 
| 232 |     Q_D(QQuickBoundaryRule); | 
| 233 |     if (qFuzzyCompare(p1: d->minimumOvershoot, p2: minimumOvershoot)) | 
| 234 |         return; | 
| 235 |     d->minimumOvershoot = minimumOvershoot; | 
| 236 |     emit minimumOvershootChanged(); | 
| 237 | } | 
| 238 |  | 
| 239 | /*! | 
| 240 |     \qmlproperty qreal QtQuick::BoundaryRule::maximum | 
| 241 |  | 
| 242 |     This property holds the largest unconstrained value that the property is | 
| 243 |     allowed to have.  If the property is set to a larger value, it will be | 
| 244 |     constrained by \l easing and \l maximumOvershoot. | 
| 245 |  | 
| 246 |     The default is \c 1. | 
| 247 | */ | 
| 248 | qreal QQuickBoundaryRule::maximum() const | 
| 249 | { | 
| 250 |     Q_D(const QQuickBoundaryRule); | 
| 251 |     return d->maximum; | 
| 252 | } | 
| 253 |  | 
| 254 | void QQuickBoundaryRule::setMaximum(qreal maximum) | 
| 255 | { | 
| 256 |     Q_D(QQuickBoundaryRule); | 
| 257 |     if (qFuzzyCompare(p1: d->maximum, p2: maximum)) | 
| 258 |         return; | 
| 259 |     d->maximum = maximum; | 
| 260 |     emit maximumChanged(); | 
| 261 | } | 
| 262 |  | 
| 263 | /*! | 
| 264 |     \qmlproperty qreal QtQuick::BoundaryRule::maximumOvershoot | 
| 265 |  | 
| 266 |     This property holds the amount that the property is allowed to be | 
| 267 |     more than \l maximum.  Whenever the value is greater than \l maximum | 
| 268 |     and less than \c {maximum + maximumOvershoot}, it is constrained | 
| 269 |     by the \l easing curve.  When the value attempts to exceed | 
| 270 |     \c {maximum + maximumOvershoot} there is a hard stop. | 
| 271 |  | 
| 272 |     The default is 0. | 
| 273 | */ | 
| 274 | qreal QQuickBoundaryRule::maximumOvershoot() const | 
| 275 | { | 
| 276 |     Q_D(const QQuickBoundaryRule); | 
| 277 |     return d->maximumOvershoot; | 
| 278 | } | 
| 279 |  | 
| 280 | void QQuickBoundaryRule::setMaximumOvershoot(qreal maximumOvershoot) | 
| 281 | { | 
| 282 |     Q_D(QQuickBoundaryRule); | 
| 283 |     if (qFuzzyCompare(p1: d->maximumOvershoot, p2: maximumOvershoot)) | 
| 284 |         return; | 
| 285 |     d->maximumOvershoot = maximumOvershoot; | 
| 286 |     emit maximumOvershootChanged(); | 
| 287 | } | 
| 288 |  | 
| 289 | /*! | 
| 290 |     \qmlproperty qreal QtQuick::BoundaryRule::overshootScale | 
| 291 |  | 
| 292 |     This property holds the amount by which the \l easing is scaled during the | 
| 293 |     overshoot condition. For example if an Item is restricted from moving more | 
| 294 |     than 100 pixels beyond some limit, and the user (by means of some Input | 
| 295 |     Handler) is trying to drag it 100 pixels past the limit, if overshootScale | 
| 296 |     is set to 1, the user will succeed: the only effect of the easing curve is | 
| 297 |     to change the rate at which the item moves from overshoot 0 to overshoot | 
| 298 |     100. But if it is set to 0.5, the BoundaryRule provides resistance such | 
| 299 |     that when the user tries to move 100 pixels, the Item will only move 50 | 
| 300 |     pixels; and the easing curve modulates the rate of movement such that it | 
| 301 |     may move in sync with the user's attempted movement at the beginning, and | 
| 302 |     then slows down, depending on the shape of the easing curve. | 
| 303 |  | 
| 304 |     The default is 0.5. | 
| 305 | */ | 
| 306 | qreal QQuickBoundaryRule::overshootScale() const | 
| 307 | { | 
| 308 |     Q_D(const QQuickBoundaryRule); | 
| 309 |     return d->overshootScale; | 
| 310 | } | 
| 311 |  | 
| 312 | void QQuickBoundaryRule::setOvershootScale(qreal overshootScale) | 
| 313 | { | 
| 314 |     Q_D(QQuickBoundaryRule); | 
| 315 |     if (qFuzzyCompare(p1: d->overshootScale, p2: overshootScale)) | 
| 316 |         return; | 
| 317 |     d->overshootScale = overshootScale; | 
| 318 |     emit overshootScaleChanged(); | 
| 319 | } | 
| 320 |  | 
| 321 | /*! | 
| 322 |     \qmlproperty qreal QtQuick::BoundaryRule::currentOvershoot | 
| 323 |  | 
| 324 |     This property holds the amount by which the most recently set value of the | 
| 325 |     intercepted property exceeds \l maximum or is less than \l minimum. | 
| 326 |  | 
| 327 |     It is positive if the property value exceeds \l maximum, negative if the | 
| 328 |     property value is less than \l minimum, or 0 if the property value is | 
| 329 |     within both boundaries. | 
| 330 | */ | 
| 331 | qreal QQuickBoundaryRule::currentOvershoot() const | 
| 332 | { | 
| 333 |     Q_D(const QQuickBoundaryRule); | 
| 334 |     return d->currentOvershoot; | 
| 335 | } | 
| 336 |  | 
| 337 | /*! | 
| 338 |     \qmlproperty qreal QtQuick::BoundaryRule::peakOvershoot | 
| 339 |  | 
| 340 |     This property holds the most-positive or most-negative value of | 
| 341 |     \l currentOvershoot that has been seen, until \l returnToBounds() is called. | 
| 342 |  | 
| 343 |     This can be useful when the intercepted property value is known to | 
| 344 |     fluctuate, and you want to find and react to the maximum amount of | 
| 345 |     overshoot rather than to the fluctuations. | 
| 346 |  | 
| 347 |     \sa overshootFilter | 
| 348 | */ | 
| 349 | qreal QQuickBoundaryRule::peakOvershoot() const | 
| 350 | { | 
| 351 |     Q_D(const QQuickBoundaryRule); | 
| 352 |     return d->peakOvershoot; | 
| 353 | } | 
| 354 |  | 
| 355 | /*! | 
| 356 |     \qmlproperty enum QtQuick::BoundaryRule::overshootFilter | 
| 357 |  | 
| 358 |     This property specifies the aggregation function that will be applied to | 
| 359 |     the intercepted property value. | 
| 360 |  | 
| 361 |     If this is set to \c BoundaryRule.None (the default), the intercepted | 
| 362 |     property will hold a value whose overshoot is limited to \l currentOvershoot. | 
| 363 |     If this is set to \c BoundaryRule.Peak, the intercepted property will hold | 
| 364 |     a value whose overshoot is limited to \l peakOvershoot. | 
| 365 | */ | 
| 366 | QQuickBoundaryRule::OvershootFilter QQuickBoundaryRule::overshootFilter() const | 
| 367 | { | 
| 368 |     Q_D(const QQuickBoundaryRule); | 
| 369 |     return d->overshootFilter; | 
| 370 | } | 
| 371 |  | 
| 372 | void QQuickBoundaryRule::setOvershootFilter(OvershootFilter overshootFilter) | 
| 373 | { | 
| 374 |     Q_D(QQuickBoundaryRule); | 
| 375 |     if (d->overshootFilter == overshootFilter) | 
| 376 |         return; | 
| 377 |     d->overshootFilter = overshootFilter; | 
| 378 |     emit overshootFilterChanged(); | 
| 379 | } | 
| 380 |  | 
| 381 | /*! | 
| 382 |     \qmlmethod bool QtQuick::BoundaryRule::returnToBounds | 
| 383 |  | 
| 384 |     Returns the intercepted property to a value between \l minimum and | 
| 385 |     \l maximum, such that \l currentOvershoot and \l peakOvershoot are both | 
| 386 |     zero. This will be animated if \l returnDuration is greater than zero. | 
| 387 |  | 
| 388 |     Returns true if the value needed to be adjusted, or false if it was already | 
| 389 |     within bounds. | 
| 390 | */ | 
| 391 | bool QQuickBoundaryRule::returnToBounds() | 
| 392 | { | 
| 393 |     Q_D(QQuickBoundaryRule); | 
| 394 |     if (d->returnAnimationJob) { | 
| 395 |         qCDebug(lcBR) << "animation already in progress" ; | 
| 396 |         return true; | 
| 397 |     } | 
| 398 |     if (currentOvershoot() > 0) { | 
| 399 |         if (d->returnDuration > 0) | 
| 400 |             d->returnAnimationJob = new QQuickBoundaryReturnJob(d, maximum()); | 
| 401 |         else | 
| 402 |             write(value: maximum()); | 
| 403 |     } else if (currentOvershoot() < 0) { | 
| 404 |         if (d->returnDuration > 0) | 
| 405 |             d->returnAnimationJob = new QQuickBoundaryReturnJob(d, minimum()); | 
| 406 |         else | 
| 407 |             write(value: minimum()); | 
| 408 |     } else { | 
| 409 |         return false; | 
| 410 |     } | 
| 411 |     if (d->returnAnimationJob) { | 
| 412 |         qCDebug(lcBR) << "animating from"  << d->returnAnimationJob->fromValue << "to"  << d->returnAnimationJob->toValue; | 
| 413 |         d->returnAnimationJob->start(); | 
| 414 |     } else { | 
| 415 |         d->resetOvershoot(); | 
| 416 |         qCDebug(lcBR) << "returned to"  << d->property.read(); | 
| 417 |     } | 
| 418 |     return true; | 
| 419 | } | 
| 420 |  | 
| 421 | /*! | 
| 422 |     \qmlproperty qreal QtQuick::BoundaryRule::easing | 
| 423 |  | 
| 424 |     This property holds the easing curve to be applied in overshoot mode | 
| 425 |     (whenever the \l minimum or \l maximum constraint is violated, while | 
| 426 |     the value is still within the respective overshoot range). | 
| 427 |  | 
| 428 |     The default easing curve is \l QEasingCurve::OutQuad. | 
| 429 | */ | 
| 430 | QEasingCurve QQuickBoundaryRule::easing() const | 
| 431 | { | 
| 432 |     Q_D(const QQuickBoundaryRule); | 
| 433 |     return d->easing; | 
| 434 | } | 
| 435 |  | 
| 436 | void QQuickBoundaryRule::setEasing(const QEasingCurve &easing) | 
| 437 | { | 
| 438 |     Q_D(QQuickBoundaryRule); | 
| 439 |     if (d->easing == easing) | 
| 440 |         return; | 
| 441 |     d->easing = easing; | 
| 442 |     emit easingChanged(); | 
| 443 | } | 
| 444 |  | 
| 445 | /*! | 
| 446 |     \qmlproperty int QtQuick::BoundaryRule::returnDuration | 
| 447 |  | 
| 448 |     This property holds the amount of time in milliseconds that | 
| 449 |     \l returnToBounds() will take to return the target property to the nearest bound. | 
| 450 |     If it is set to 0, returnToBounds() will set the property immediately | 
| 451 |     rather than creating an animation job. | 
| 452 |  | 
| 453 |     The default is 100 ms. | 
| 454 | */ | 
| 455 | int QQuickBoundaryRule::returnDuration() const | 
| 456 | { | 
| 457 |     Q_D(const QQuickBoundaryRule); | 
| 458 |     return d->returnDuration; | 
| 459 | } | 
| 460 |  | 
| 461 | void QQuickBoundaryRule::setReturnDuration(int duration) | 
| 462 | { | 
| 463 |     Q_D(QQuickBoundaryRule); | 
| 464 |     if (d->returnDuration == duration) | 
| 465 |         return; | 
| 466 |     d->returnDuration = duration; | 
| 467 |     emit returnDurationChanged(); | 
| 468 | } | 
| 469 |  | 
| 470 | void QQuickBoundaryRule::write(const QVariant &value) | 
| 471 | { | 
| 472 |     bool conversionOk = false; | 
| 473 |     qreal rValue = value.toReal(ok: &conversionOk); | 
| 474 |     if (!conversionOk) { | 
| 475 |         qWarning() << "BoundaryRule doesn't work with non-numeric values:"  << value; | 
| 476 |         return; | 
| 477 |     } | 
| 478 |     Q_D(QQuickBoundaryRule); | 
| 479 |     bool bypass = !d->enabled || !d->finalized || QQmlEnginePrivate::designerMode(); | 
| 480 |     if (bypass) { | 
| 481 |         QQmlPropertyPrivate::write(that: d->property, value, | 
| 482 |                                    QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); | 
| 483 |         return; | 
| 484 |     } | 
| 485 |  | 
| 486 |     qmlExecuteDeferred(this); | 
| 487 |     d->targetValue = d->easedOvershoot(overshootingValue: rValue); | 
| 488 |     QQmlPropertyPrivate::write(that: d->property, d->targetValue, | 
| 489 |                                QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); | 
| 490 | } | 
| 491 |  | 
| 492 | void QQuickBoundaryRule::setTarget(const QQmlProperty &property) | 
| 493 | { | 
| 494 |     Q_D(QQuickBoundaryRule); | 
| 495 |     d->property = property; | 
| 496 |  | 
| 497 |     QQmlEnginePrivate *engPriv = QQmlEnginePrivate::get(e: qmlEngine(this)); | 
| 498 |     static int finalizedIdx = -1; | 
| 499 |     if (finalizedIdx < 0) | 
| 500 |         finalizedIdx = metaObject()->indexOfSlot(slot: "componentFinalized()" ); | 
| 501 |     engPriv->registerFinalizeCallback(obj: this, index: finalizedIdx); | 
| 502 | } | 
| 503 |  | 
| 504 | void QQuickBoundaryRule::componentFinalized() | 
| 505 | { | 
| 506 |     Q_D(QQuickBoundaryRule); | 
| 507 |     d->finalized = true; | 
| 508 | } | 
| 509 |  | 
| 510 | /*! | 
| 511 |     \internal | 
| 512 |     Given that something is trying to set the target property to \a value, | 
| 513 |     this function applies the easing curve and returns the value that the | 
| 514 |     property should actually get instead. | 
| 515 | */ | 
| 516 | qreal QQuickBoundaryRulePrivate::easedOvershoot(qreal value) | 
| 517 | { | 
| 518 |     qreal ret = value; | 
| 519 |     Q_Q(QQuickBoundaryRule); | 
| 520 |     if (value > maximum) { | 
| 521 |         qreal overshootWas = currentOvershoot; | 
| 522 |         currentOvershoot = value - maximum; | 
| 523 |         if (!qFuzzyCompare(p1: overshootWas, p2: currentOvershoot)) | 
| 524 |             emit q->currentOvershootChanged(); | 
| 525 |         overshootWas = peakOvershoot; | 
| 526 |         peakOvershoot = qMax(a: currentOvershoot, b: peakOvershoot); | 
| 527 |         if (!qFuzzyCompare(p1: overshootWas, p2: peakOvershoot)) | 
| 528 |             emit q->peakOvershootChanged(); | 
| 529 |         ret = maximum + maximumOvershoot * easing.valueForProgress( | 
| 530 |                     progress: (overshootFilter == QQuickBoundaryRule::OvershootFilter::Peak ? peakOvershoot : currentOvershoot) | 
| 531 |                     * overshootScale / maximumOvershoot); | 
| 532 |         qCDebug(lcBR).nospace() << value << " overshoots maximum "  << maximum << " by "  | 
| 533 |                                 << currentOvershoot << " (peak "  << peakOvershoot << "): eased to "  << ret; | 
| 534 |     } else if (value < minimum) { | 
| 535 |         qreal overshootWas = currentOvershoot; | 
| 536 |         currentOvershoot = value - minimum; | 
| 537 |         if (!qFuzzyCompare(p1: overshootWas, p2: currentOvershoot)) | 
| 538 |             emit q->currentOvershootChanged(); | 
| 539 |         overshootWas = peakOvershoot; | 
| 540 |         peakOvershoot = qMin(a: currentOvershoot, b: peakOvershoot); | 
| 541 |         if (!qFuzzyCompare(p1: overshootWas, p2: peakOvershoot)) | 
| 542 |             emit q->peakOvershootChanged(); | 
| 543 |         ret = minimum - minimumOvershoot * easing.valueForProgress( | 
| 544 |                     progress: -(overshootFilter == QQuickBoundaryRule::OvershootFilter::Peak ? peakOvershoot : currentOvershoot) | 
| 545 |                     * overshootScale / minimumOvershoot); | 
| 546 |         qCDebug(lcBR).nospace() << value << " overshoots minimum "  << minimum << " by "  | 
| 547 |                                 << currentOvershoot << " (peak "  << peakOvershoot << "): eased to "  << ret; | 
| 548 |     } else { | 
| 549 |         resetOvershoot(); | 
| 550 |     } | 
| 551 |     return ret; | 
| 552 | } | 
| 553 |  | 
| 554 | /*! | 
| 555 |     \internal | 
| 556 |     Resets the currentOvershoot and peakOvershoot | 
| 557 |     properties to zero. | 
| 558 | */ | 
| 559 | void QQuickBoundaryRulePrivate::resetOvershoot() | 
| 560 | { | 
| 561 |     Q_Q(QQuickBoundaryRule); | 
| 562 |     if (!qFuzzyCompare(p1: peakOvershoot, p2: 0)) { | 
| 563 |         peakOvershoot = 0; | 
| 564 |         emit q->peakOvershootChanged(); | 
| 565 |     } | 
| 566 |     if (!qFuzzyCompare(p1: currentOvershoot, p2: 0)) { | 
| 567 |         currentOvershoot = 0; | 
| 568 |         emit q->currentOvershootChanged(); | 
| 569 |     } | 
| 570 | } | 
| 571 |  | 
| 572 | QT_END_NAMESPACE | 
| 573 |  | 
| 574 | #include "moc_qquickboundaryrule_p.cpp" | 
| 575 |  |