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 | |
4 | #include "qquickscrollindicator_p.h" |
5 | #include "qquickcontrol_p_p.h" |
6 | |
7 | #include <QtQml/qqmlinfo.h> |
8 | #include <QtQuick/private/qquickflickable_p.h> |
9 | #include <QtQuick/private/qquickitemchangelistener_p.h> |
10 | |
11 | QT_BEGIN_NAMESPACE |
12 | |
13 | /*! |
14 | \qmltype ScrollIndicator |
15 | \inherits Control |
16 | //! \instantiates QQuickScrollIndicator |
17 | \inqmlmodule QtQuick.Controls |
18 | \since 5.7 |
19 | \ingroup qtquickcontrols-indicators |
20 | \brief Vertical or horizontal non-interactive scroll indicator. |
21 | |
22 | \image qtquickcontrols-scrollindicator.gif |
23 | |
24 | ScrollIndicator is a non-interactive indicator that indicates the current scroll |
25 | position. A scroll indicator can be either \l vertical or \l horizontal, and can |
26 | be attached to any \l Flickable, such as \l ListView and \l GridView. |
27 | |
28 | \code |
29 | Flickable { |
30 | // ... |
31 | ScrollIndicator.vertical: ScrollIndicator { } |
32 | } |
33 | \endcode |
34 | |
35 | \section1 Attaching ScrollIndicator to a Flickable |
36 | |
37 | \note When ScrollIndicator is attached \l {ScrollIndicator::vertical}{vertically} |
38 | or \l {ScrollIndicator::horizontal}{horizontally} to a Flickable, its geometry and |
39 | the following properties are automatically set and updated as appropriate: |
40 | |
41 | \list |
42 | \li \l orientation |
43 | \li \l position |
44 | \li \l size |
45 | \li \l active |
46 | \endlist |
47 | |
48 | An attached ScrollIndicator re-parents itself to the target Flickable. A vertically |
49 | attached ScrollIndicator resizes itself to the height of the Flickable, and positions |
50 | itself to either side of it based on the \l {Control::mirrored}{layout direction}. |
51 | A horizontally attached ScrollIndicator resizes itself to the width of the Flickable, |
52 | and positions itself to the bottom. The automatic geometry management can be disabled |
53 | by specifying another parent for the attached ScrollIndicator. This can be useful, for |
54 | example, if the ScrollIndicator should be placed outside a clipping Flickable. This is |
55 | demonstrated by the following example: |
56 | |
57 | \code |
58 | Flickable { |
59 | id: flickable |
60 | clip: true |
61 | // ... |
62 | ScrollIndicator.vertical: ScrollIndicator { |
63 | parent: flickable.parent |
64 | anchors.top: flickable.top |
65 | anchors.left: flickable.right |
66 | anchors.bottom: flickable.bottom |
67 | } |
68 | } |
69 | \endcode |
70 | |
71 | \section1 Binding the Active State of Horizontal and Vertical Scroll Indicators |
72 | |
73 | Horizontal and vertical scroll indicators do not share the \l active state with |
74 | each other by default. In order to keep both indicators visible whilst scrolling |
75 | to either direction, establish a two-way binding between the active states as |
76 | presented by the following example: |
77 | |
78 | \snippet qtquickcontrols-scrollindicator-active.qml 1 |
79 | |
80 | \section1 Non-attached Scroll Indicators |
81 | |
82 | It is possible to create an instance of ScrollIndicator without using the |
83 | attached property API. This is useful when the behavior of the attached |
84 | scoll indicator is not sufficient or a \l Flickable is not in use. In the |
85 | following example, horizontal and vertical scroll indicators are used to |
86 | indicate how far the user has scrolled over the text (using \l MouseArea |
87 | instead of \l Flickable): |
88 | |
89 | \snippet qtquickcontrols-scrollindicator-non-attached.qml 1 |
90 | |
91 | \image qtquickcontrols-scrollindicator-non-attached.png |
92 | |
93 | \sa ScrollBar, {Customizing ScrollIndicator}, {Indicator Controls} |
94 | */ |
95 | |
96 | static const QQuickItemPrivate::ChangeTypes QsiChangeTypes = QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed; |
97 | static const QQuickItemPrivate::ChangeTypes QsiHorizontalChangeTypes = QsiChangeTypes | QQuickItemPrivate::ImplicitHeight; |
98 | static const QQuickItemPrivate::ChangeTypes QsiVerticalChangeTypes = QsiChangeTypes | QQuickItemPrivate::ImplicitWidth; |
99 | |
100 | class QQuickScrollIndicatorPrivate : public QQuickControlPrivate |
101 | { |
102 | Q_DECLARE_PUBLIC(QQuickScrollIndicator) |
103 | |
104 | public: |
105 | struct VisualArea |
106 | { |
107 | VisualArea(qreal pos, qreal sz) |
108 | : position(pos), size(sz) { } |
109 | qreal position = 0; |
110 | qreal size = 0; |
111 | }; |
112 | VisualArea visualArea() const; |
113 | void visualAreaChange(const VisualArea &newVisualArea, const VisualArea &oldVisualArea); |
114 | |
115 | void resizeContent() override; |
116 | |
117 | qreal size = 0; |
118 | qreal minimumSize = 0; |
119 | qreal position = 0; |
120 | bool active = false; |
121 | Qt::Orientation orientation = Qt::Vertical; |
122 | }; |
123 | |
124 | QQuickScrollIndicatorPrivate::VisualArea QQuickScrollIndicatorPrivate::visualArea() const |
125 | { |
126 | qreal visualPos = position; |
127 | if (minimumSize > size) |
128 | visualPos = position / (1.0 - size) * (1.0 - minimumSize); |
129 | |
130 | qreal maximumSize = qMax<qreal>(a: 0.0, b: 1.0 - visualPos); |
131 | qreal visualSize = qMax<qreal>(a: minimumSize, |
132 | b: qMin<qreal>(a: qMax(a: size, b: minimumSize) + qMin<qreal>(a: 0, b: visualPos), |
133 | b: maximumSize)); |
134 | |
135 | visualPos = qMax<qreal>(a: 0,b: qMin<qreal>(a: visualPos,b: qMax<qreal>(a: 0, b: 1.0 - visualSize))); |
136 | |
137 | return VisualArea(visualPos, visualSize); |
138 | } |
139 | |
140 | void QQuickScrollIndicatorPrivate::visualAreaChange(const VisualArea &newVisualArea, const VisualArea &oldVisualArea) |
141 | { |
142 | Q_Q(QQuickScrollIndicator); |
143 | if (!qFuzzyCompare(p1: newVisualArea.size, p2: oldVisualArea.size)) |
144 | emit q->visualSizeChanged(); |
145 | if (!qFuzzyCompare(p1: newVisualArea.position, p2: oldVisualArea.position)) |
146 | emit q->visualPositionChanged(); |
147 | } |
148 | |
149 | void QQuickScrollIndicatorPrivate::resizeContent() |
150 | { |
151 | Q_Q(QQuickScrollIndicator); |
152 | if (!contentItem) |
153 | return; |
154 | |
155 | // - negative overshoot (pos < 0): clamp the pos to 0, and deduct the overshoot from the size |
156 | // - positive overshoot (pos + size > 1): clamp the size to 1-pos |
157 | const VisualArea visual = visualArea(); |
158 | |
159 | if (orientation == Qt::Horizontal) { |
160 | contentItem->setPosition(QPointF(q->leftPadding() + visual.position * q->availableWidth(), q->topPadding())); |
161 | contentItem->setSize(QSizeF(q->availableWidth() * visual.size, q->availableHeight())); |
162 | } else { |
163 | contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding() + visual.position * q->availableHeight())); |
164 | contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight() * visual.size)); |
165 | } |
166 | } |
167 | |
168 | QQuickScrollIndicator::QQuickScrollIndicator(QQuickItem *parent) |
169 | : QQuickControl(*(new QQuickScrollIndicatorPrivate), parent) |
170 | { |
171 | } |
172 | |
173 | QQuickScrollIndicatorAttached *QQuickScrollIndicator::qmlAttachedProperties(QObject *object) |
174 | { |
175 | return new QQuickScrollIndicatorAttached(object); |
176 | } |
177 | |
178 | /*! |
179 | \qmlproperty real QtQuick.Controls::ScrollIndicator::size |
180 | |
181 | This property holds the size of the indicator, scaled to \c {0.0 - 1.0}. |
182 | |
183 | \sa {Flickable::visibleArea.heightRatio}{Flickable::visibleArea} |
184 | |
185 | This property is automatically set when the scroll indicator is |
186 | \l {Attaching ScrollIndicator to a Flickable}{attached to a flickable}. |
187 | |
188 | \sa minimumSize, visualSize |
189 | */ |
190 | qreal QQuickScrollIndicator::size() const |
191 | { |
192 | Q_D(const QQuickScrollIndicator); |
193 | return d->size; |
194 | } |
195 | |
196 | void QQuickScrollIndicator::setSize(qreal size) |
197 | { |
198 | Q_D(QQuickScrollIndicator); |
199 | if (qFuzzyCompare(p1: d->size, p2: size)) |
200 | return; |
201 | |
202 | auto oldVisualArea = d->visualArea(); |
203 | d->size = size; |
204 | if (d->size + d->position > 1.0) { |
205 | setPosition(1.0 - d->size); |
206 | oldVisualArea = d->visualArea(); |
207 | } |
208 | if (isComponentComplete()) |
209 | d->resizeContent(); |
210 | emit sizeChanged(); |
211 | d->visualAreaChange(newVisualArea: d->visualArea(), oldVisualArea); |
212 | } |
213 | |
214 | /*! |
215 | \qmlproperty real QtQuick.Controls::ScrollIndicator::position |
216 | |
217 | This property holds the position of the indicator, scaled to \c {0.0 - 1.0}. |
218 | |
219 | This property is automatically set when the scroll indicator is |
220 | \l {Attaching ScrollIndicator to a Flickable}{attached to a flickable}. |
221 | |
222 | \sa {Flickable::visibleArea.yPosition}{Flickable::visibleArea}, visualPosition |
223 | */ |
224 | qreal QQuickScrollIndicator::position() const |
225 | { |
226 | Q_D(const QQuickScrollIndicator); |
227 | return d->position; |
228 | } |
229 | |
230 | void QQuickScrollIndicator::setPosition(qreal position) |
231 | { |
232 | Q_D(QQuickScrollIndicator); |
233 | if (qFuzzyCompare(p1: d->position, p2: position)) |
234 | return; |
235 | |
236 | auto oldVisualArea = d->visualArea(); |
237 | d->position = position; |
238 | if (isComponentComplete()) |
239 | d->resizeContent(); |
240 | emit positionChanged(); |
241 | d->visualAreaChange(newVisualArea: d->visualArea(), oldVisualArea); |
242 | } |
243 | |
244 | /*! |
245 | \qmlproperty bool QtQuick.Controls::ScrollIndicator::active |
246 | |
247 | This property holds whether the indicator is active, that is, when the |
248 | attached Flickable is \l {Flickable::moving}{moving}. |
249 | |
250 | It is possible to keep \l {Binding the Active State of Horizontal and Vertical Scroll Indicators} |
251 | {both horizontal and vertical indicators visible} while scrolling in either direction. |
252 | |
253 | This property is automatically set when the scroll indicator is |
254 | \l {Attaching ScrollIndicator to a Flickable}{attached to a flickable}. |
255 | */ |
256 | bool QQuickScrollIndicator::isActive() const |
257 | { |
258 | Q_D(const QQuickScrollIndicator); |
259 | return d->active; |
260 | } |
261 | |
262 | void QQuickScrollIndicator::setActive(bool active) |
263 | { |
264 | Q_D(QQuickScrollIndicator); |
265 | if (d->active == active) |
266 | return; |
267 | |
268 | d->active = active; |
269 | emit activeChanged(); |
270 | } |
271 | |
272 | /*! |
273 | \qmlproperty enumeration QtQuick.Controls::ScrollIndicator::orientation |
274 | |
275 | This property holds the orientation of the indicator. |
276 | |
277 | Possible values: |
278 | \value Qt.Horizontal Horizontal |
279 | \value Qt.Vertical Vertical (default) |
280 | |
281 | This property is automatically set when the scroll indicator is |
282 | \l {Attaching ScrollIndicator to a Flickable}{attached to a flickable}. |
283 | |
284 | \sa horizontal, vertical |
285 | */ |
286 | Qt::Orientation QQuickScrollIndicator::orientation() const |
287 | { |
288 | Q_D(const QQuickScrollIndicator); |
289 | return d->orientation; |
290 | } |
291 | |
292 | void QQuickScrollIndicator::setOrientation(Qt::Orientation orientation) |
293 | { |
294 | Q_D(QQuickScrollIndicator); |
295 | if (d->orientation == orientation) |
296 | return; |
297 | |
298 | d->orientation = orientation; |
299 | if (isComponentComplete()) |
300 | d->resizeContent(); |
301 | emit orientationChanged(); |
302 | } |
303 | |
304 | /*! |
305 | \since QtQuick.Controls 2.3 (Qt 5.10) |
306 | \qmlproperty bool QtQuick.Controls::ScrollIndicator::horizontal |
307 | \readonly |
308 | |
309 | This property holds whether the scroll indicator is horizontal. |
310 | |
311 | \sa orientation |
312 | */ |
313 | bool QQuickScrollIndicator::isHorizontal() const |
314 | { |
315 | Q_D(const QQuickScrollIndicator); |
316 | return d->orientation == Qt::Horizontal; |
317 | } |
318 | |
319 | /*! |
320 | \since QtQuick.Controls 2.3 (Qt 5.10) |
321 | \qmlproperty bool QtQuick.Controls::ScrollIndicator::vertical |
322 | \readonly |
323 | |
324 | This property holds whether the scroll indicator is vertical. |
325 | |
326 | \sa orientation |
327 | */ |
328 | bool QQuickScrollIndicator::isVertical() const |
329 | { |
330 | Q_D(const QQuickScrollIndicator); |
331 | return d->orientation == Qt::Vertical; |
332 | } |
333 | |
334 | /*! |
335 | \since QtQuick.Controls 2.4 (Qt 5.11) |
336 | \qmlproperty real QtQuick.Controls::ScrollIndicator::minimumSize |
337 | |
338 | This property holds the minimum size of the indicator, scaled to \c {0.0 - 1.0}. |
339 | |
340 | \sa size, visualSize, visualPosition |
341 | */ |
342 | qreal QQuickScrollIndicator::minimumSize() const |
343 | { |
344 | Q_D(const QQuickScrollIndicator); |
345 | return d->minimumSize; |
346 | } |
347 | |
348 | void QQuickScrollIndicator::setMinimumSize(qreal minimumSize) |
349 | { |
350 | Q_D(QQuickScrollIndicator); |
351 | if (qFuzzyCompare(p1: d->minimumSize, p2: minimumSize)) |
352 | return; |
353 | |
354 | auto oldVisualArea = d->visualArea(); |
355 | d->minimumSize = minimumSize; |
356 | if (isComponentComplete()) |
357 | d->resizeContent(); |
358 | emit minimumSizeChanged(); |
359 | d->visualAreaChange(newVisualArea: d->visualArea(), oldVisualArea); |
360 | } |
361 | |
362 | /*! |
363 | \since QtQuick.Controls 2.4 (Qt 5.11) |
364 | \qmlproperty real QtQuick.Controls::ScrollIndicator::visualSize |
365 | |
366 | This property holds the effective visual size of the indicator, |
367 | which may be limited by the \l {minimumSize}{minimum size}. |
368 | |
369 | \sa size, minimumSize |
370 | */ |
371 | qreal QQuickScrollIndicator::visualSize() const |
372 | { |
373 | Q_D(const QQuickScrollIndicator); |
374 | return d->visualArea().size; |
375 | } |
376 | |
377 | /*! |
378 | \since QtQuick.Controls 2.4 (Qt 5.11) |
379 | \qmlproperty real QtQuick.Controls::ScrollIndicator::visualPosition |
380 | |
381 | This property holds the effective visual position of the indicator, |
382 | which may be limited by the \l {minimumSize}{minimum size}. |
383 | |
384 | \sa position, minimumSize |
385 | */ |
386 | qreal QQuickScrollIndicator::visualPosition() const |
387 | { |
388 | Q_D(const QQuickScrollIndicator); |
389 | return d->visualArea().position; |
390 | } |
391 | |
392 | class QQuickScrollIndicatorAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener |
393 | { |
394 | public: |
395 | void activateHorizontal(); |
396 | void activateVertical(); |
397 | |
398 | void layoutHorizontal(bool move = true); |
399 | void layoutVertical(bool move = true); |
400 | |
401 | void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override; |
402 | void itemImplicitWidthChanged(QQuickItem *item) override; |
403 | void itemImplicitHeightChanged(QQuickItem *item) override; |
404 | void itemDestroyed(QQuickItem *item) override; |
405 | |
406 | QQuickFlickable *flickable = nullptr; |
407 | QQuickScrollIndicator *horizontal = nullptr; |
408 | QQuickScrollIndicator *vertical = nullptr; |
409 | }; |
410 | |
411 | void QQuickScrollIndicatorAttachedPrivate::activateHorizontal() |
412 | { |
413 | horizontal->setActive(flickable->isMovingHorizontally()); |
414 | } |
415 | |
416 | void QQuickScrollIndicatorAttachedPrivate::activateVertical() |
417 | { |
418 | vertical->setActive(flickable->isMovingVertically()); |
419 | } |
420 | |
421 | void QQuickScrollIndicatorAttachedPrivate::layoutHorizontal(bool move) |
422 | { |
423 | Q_ASSERT(horizontal && flickable); |
424 | if (horizontal->parentItem() != flickable) |
425 | return; |
426 | horizontal->setWidth(flickable->width()); |
427 | if (move) |
428 | horizontal->setY(flickable->height() - horizontal->height()); |
429 | } |
430 | |
431 | void QQuickScrollIndicatorAttachedPrivate::layoutVertical(bool move) |
432 | { |
433 | Q_ASSERT(vertical && flickable); |
434 | if (vertical->parentItem() != flickable) |
435 | return; |
436 | vertical->setHeight(flickable->height()); |
437 | if (move && !QQuickItemPrivate::get(item: vertical)->isMirrored()) |
438 | vertical->setX(flickable->width() - vertical->width()); |
439 | } |
440 | |
441 | void QQuickScrollIndicatorAttachedPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) |
442 | { |
443 | Q_UNUSED(item); |
444 | Q_UNUSED(change); |
445 | if (horizontal && horizontal->height() > 0) { |
446 | #ifdef QT_QUICK_NEW_GEOMETRY_CHANGED_HANDLING // TODO: correct/rename diff to oldGeometry |
447 | bool move = qFuzzyIsNull(d: horizontal->y()) || qFuzzyCompare(p1: horizontal->y(), p2: diff.height() - horizontal->height()); |
448 | #else |
449 | bool move = qFuzzyIsNull(horizontal->y()) || qFuzzyCompare(horizontal->y(), item->height() - diff.height() - horizontal->height()); |
450 | #endif |
451 | layoutHorizontal(move); |
452 | } |
453 | if (vertical && vertical->width() > 0) { |
454 | #ifdef QT_QUICK_NEW_GEOMETRY_CHANGED_HANDLING // TODO: correct/rename diff to oldGeometry |
455 | bool move = qFuzzyIsNull(d: vertical->x()) || qFuzzyCompare(p1: vertical->x(), p2: diff.width() - vertical->width()); |
456 | #else |
457 | bool move = qFuzzyIsNull(vertical->x()) || qFuzzyCompare(vertical->x(), item->width() - diff.width() - vertical->width()); |
458 | #endif |
459 | layoutVertical(move); |
460 | } |
461 | } |
462 | |
463 | void QQuickScrollIndicatorAttachedPrivate::itemImplicitWidthChanged(QQuickItem *item) |
464 | { |
465 | if (item == vertical) |
466 | layoutVertical(move: true); |
467 | } |
468 | |
469 | void QQuickScrollIndicatorAttachedPrivate::itemImplicitHeightChanged(QQuickItem *item) |
470 | { |
471 | if (item == horizontal) |
472 | layoutHorizontal(move: true); |
473 | } |
474 | |
475 | void QQuickScrollIndicatorAttachedPrivate::itemDestroyed(QQuickItem *item) |
476 | { |
477 | if (item == horizontal) |
478 | horizontal = nullptr; |
479 | if (item == vertical) |
480 | vertical = nullptr; |
481 | } |
482 | |
483 | QQuickScrollIndicatorAttached::QQuickScrollIndicatorAttached(QObject *parent) |
484 | : QObject(*(new QQuickScrollIndicatorAttachedPrivate), parent) |
485 | { |
486 | Q_D(QQuickScrollIndicatorAttached); |
487 | d->flickable = qobject_cast<QQuickFlickable *>(object: parent); |
488 | if (d->flickable) |
489 | QQuickItemPrivate::get(item: d->flickable)->updateOrAddGeometryChangeListener(listener: d, types: QQuickGeometryChange::Size); |
490 | else if (parent) |
491 | qmlWarning(me: parent) << "ScrollIndicator must be attached to a Flickable" ; |
492 | } |
493 | |
494 | QQuickScrollIndicatorAttached::~QQuickScrollIndicatorAttached() |
495 | { |
496 | Q_D(QQuickScrollIndicatorAttached); |
497 | if (d->flickable) { |
498 | if (d->horizontal) |
499 | QQuickItemPrivate::get(item: d->horizontal)->removeItemChangeListener(d, types: QsiHorizontalChangeTypes); |
500 | if (d->vertical) |
501 | QQuickItemPrivate::get(item: d->vertical)->removeItemChangeListener(d, types: QsiVerticalChangeTypes); |
502 | // NOTE: Use removeItemChangeListener(Geometry) instead of updateOrRemoveGeometryChangeListener(Size). |
503 | // The latter doesn't remove the listener but only resets its types. Thus, it leaves behind a dangling |
504 | // pointer on destruction. |
505 | QQuickItemPrivate::get(item: d->flickable)->removeItemChangeListener(d, types: QQuickItemPrivate::Geometry); |
506 | } |
507 | } |
508 | |
509 | /*! |
510 | \qmlattachedproperty ScrollIndicator QtQuick.Controls::ScrollIndicator::horizontal |
511 | |
512 | This property attaches a horizontal scroll indicator to a \l Flickable. |
513 | |
514 | \code |
515 | Flickable { |
516 | contentWidth: 2000 |
517 | ScrollIndicator.horizontal: ScrollIndicator { } |
518 | } |
519 | \endcode |
520 | |
521 | \sa {Attaching ScrollIndicator to a Flickable} |
522 | */ |
523 | QQuickScrollIndicator *QQuickScrollIndicatorAttached::horizontal() const |
524 | { |
525 | Q_D(const QQuickScrollIndicatorAttached); |
526 | return d->horizontal; |
527 | } |
528 | |
529 | void QQuickScrollIndicatorAttached::setHorizontal(QQuickScrollIndicator *horizontal) |
530 | { |
531 | Q_D(QQuickScrollIndicatorAttached); |
532 | if (d->horizontal == horizontal) |
533 | return; |
534 | |
535 | if (d->horizontal && d->flickable) { |
536 | QQuickItemPrivate::get(item: d->horizontal)->removeItemChangeListener(d, types: QsiHorizontalChangeTypes); |
537 | QObjectPrivate::disconnect(sender: d->flickable, signal: &QQuickFlickable::movingHorizontallyChanged, receiverPrivate: d, slot: &QQuickScrollIndicatorAttachedPrivate::activateHorizontal); |
538 | |
539 | // TODO: export QQuickFlickableVisibleArea |
540 | QObject *area = d->flickable->property(name: "visibleArea" ).value<QObject *>(); |
541 | disconnect(sender: area, SIGNAL(widthRatioChanged(qreal)), receiver: d->horizontal, SLOT(setSize(qreal))); |
542 | disconnect(sender: area, SIGNAL(xPositionChanged(qreal)), receiver: d->horizontal, SLOT(setPosition(qreal))); |
543 | } |
544 | |
545 | d->horizontal = horizontal; |
546 | |
547 | if (horizontal && d->flickable) { |
548 | if (!horizontal->parentItem()) |
549 | horizontal->setParentItem(d->flickable); |
550 | horizontal->setOrientation(Qt::Horizontal); |
551 | |
552 | QQuickItemPrivate::get(item: horizontal)->addItemChangeListener(listener: d, types: QsiHorizontalChangeTypes); |
553 | QObjectPrivate::connect(sender: d->flickable, signal: &QQuickFlickable::movingHorizontallyChanged, receiverPrivate: d, slot: &QQuickScrollIndicatorAttachedPrivate::activateHorizontal); |
554 | |
555 | // TODO: export QQuickFlickableVisibleArea |
556 | QObject *area = d->flickable->property(name: "visibleArea" ).value<QObject *>(); |
557 | connect(sender: area, SIGNAL(widthRatioChanged(qreal)), receiver: horizontal, SLOT(setSize(qreal))); |
558 | connect(sender: area, SIGNAL(xPositionChanged(qreal)), receiver: horizontal, SLOT(setPosition(qreal))); |
559 | |
560 | d->layoutHorizontal(); |
561 | horizontal->setSize(area->property(name: "widthRatio" ).toReal()); |
562 | horizontal->setPosition(area->property(name: "xPosition" ).toReal()); |
563 | } |
564 | emit horizontalChanged(); |
565 | } |
566 | |
567 | /*! |
568 | \qmlattachedproperty ScrollIndicator QtQuick.Controls::ScrollIndicator::vertical |
569 | |
570 | This property attaches a vertical scroll indicator to a \l Flickable. |
571 | |
572 | \code |
573 | Flickable { |
574 | contentHeight: 2000 |
575 | ScrollIndicator.vertical: ScrollIndicator { } |
576 | } |
577 | \endcode |
578 | |
579 | \sa {Attaching ScrollIndicator to a Flickable} |
580 | */ |
581 | QQuickScrollIndicator *QQuickScrollIndicatorAttached::vertical() const |
582 | { |
583 | Q_D(const QQuickScrollIndicatorAttached); |
584 | return d->vertical; |
585 | } |
586 | |
587 | void QQuickScrollIndicatorAttached::setVertical(QQuickScrollIndicator *vertical) |
588 | { |
589 | Q_D(QQuickScrollIndicatorAttached); |
590 | if (d->vertical == vertical) |
591 | return; |
592 | |
593 | if (d->vertical && d->flickable) { |
594 | QQuickItemPrivate::get(item: d->vertical)->removeItemChangeListener(d, types: QsiVerticalChangeTypes); |
595 | QObjectPrivate::disconnect(sender: d->flickable, signal: &QQuickFlickable::movingVerticallyChanged, receiverPrivate: d, slot: &QQuickScrollIndicatorAttachedPrivate::activateVertical); |
596 | |
597 | // TODO: export QQuickFlickableVisibleArea |
598 | QObject *area = d->flickable->property(name: "visibleArea" ).value<QObject *>(); |
599 | disconnect(sender: area, SIGNAL(heightRatioChanged(qreal)), receiver: d->vertical, SLOT(setSize(qreal))); |
600 | disconnect(sender: area, SIGNAL(yPositionChanged(qreal)), receiver: d->vertical, SLOT(setPosition(qreal))); |
601 | } |
602 | |
603 | d->vertical = vertical; |
604 | |
605 | if (vertical && d->flickable) { |
606 | if (!vertical->parentItem()) |
607 | vertical->setParentItem(d->flickable); |
608 | vertical->setOrientation(Qt::Vertical); |
609 | |
610 | QQuickItemPrivate::get(item: vertical)->addItemChangeListener(listener: d, types: QsiVerticalChangeTypes); |
611 | QObjectPrivate::connect(sender: d->flickable, signal: &QQuickFlickable::movingVerticallyChanged, receiverPrivate: d, slot: &QQuickScrollIndicatorAttachedPrivate::activateVertical); |
612 | |
613 | // TODO: export QQuickFlickableVisibleArea |
614 | QObject *area = d->flickable->property(name: "visibleArea" ).value<QObject *>(); |
615 | connect(sender: area, SIGNAL(heightRatioChanged(qreal)), receiver: vertical, SLOT(setSize(qreal))); |
616 | connect(sender: area, SIGNAL(yPositionChanged(qreal)), receiver: vertical, SLOT(setPosition(qreal))); |
617 | |
618 | d->layoutVertical(); |
619 | vertical->setSize(area->property(name: "heightRatio" ).toReal()); |
620 | vertical->setPosition(area->property(name: "yPosition" ).toReal()); |
621 | } |
622 | emit verticalChanged(); |
623 | } |
624 | |
625 | #if QT_CONFIG(quicktemplates2_multitouch) |
626 | void QQuickScrollIndicator::touchEvent(QTouchEvent *event) |
627 | { |
628 | event->ignore(); // QTBUG-61785 |
629 | } |
630 | #endif |
631 | |
632 | #if QT_CONFIG(accessibility) |
633 | QAccessible::Role QQuickScrollIndicator::accessibleRole() const |
634 | { |
635 | return QAccessible::Indicator; |
636 | } |
637 | #endif |
638 | |
639 | QT_END_NAMESPACE |
640 | |
641 | #include "moc_qquickscrollindicator_p.cpp" |
642 | |