1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
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 http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | |
37 | #include "qquickscrollview_p.h" |
38 | #include "qquickpane_p_p.h" |
39 | #include "qquickscrollbar_p_p.h" |
40 | |
41 | #include <QtQml/qqmlinfo.h> |
42 | #include <QtQuick/private/qquickflickable_p.h> |
43 | |
44 | QT_BEGIN_NAMESPACE |
45 | |
46 | /*! |
47 | \qmltype ScrollView |
48 | \inherits Pane |
49 | //! \instantiates QQuickScrollView |
50 | \inqmlmodule QtQuick.Controls |
51 | \since 5.9 |
52 | \ingroup qtquickcontrols2-containers |
53 | \ingroup qtquickcontrols2-focusscopes |
54 | \brief Scrollable view. |
55 | |
56 | ScrollView provides scrolling for user-defined content. It can be used to |
57 | either replace a \l Flickable, or to decorate an existing one. |
58 | |
59 | \image qtquickcontrols2-scrollview.png |
60 | |
61 | The first example demonstrates the simplest usage of ScrollView. |
62 | |
63 | \snippet qtquickcontrols2-scrollview.qml file |
64 | |
65 | \note ScrollView does not automatically clip its contents. If it is not used as |
66 | a full-screen item, you should consider setting the \l {Item::}{clip} property |
67 | to \c true, as shown above. |
68 | |
69 | The second example illustrates using an existing \l Flickable, that is, |
70 | a \l ListView. |
71 | |
72 | \snippet qtquickcontrols2-scrollview-listview.qml file |
73 | |
74 | \section2 Sizing |
75 | |
76 | As with Flickable, there are several things to keep in mind when using |
77 | ScrollView: |
78 | \list |
79 | \li If only a single item is used within a ScrollView, the content size is |
80 | automatically calculated based on the implicit size of its contained item. |
81 | However, if more than one item is used (or an implicit size is not |
82 | provided), the \l {QtQuick.Controls::Pane::}{contentWidth} and |
83 | \l {QtQuick.Controls::Pane::}{contentHeight} properties must |
84 | be set to the combined size of its contained items. |
85 | \li If the content size is less than or equal to the size of the ScrollView, |
86 | it will not be scrollable. |
87 | \li If you want the ScrollView to only scroll vertically, you can bind |
88 | \l {QtQuick.Controls::Pane::}{contentWidth} to |
89 | \l {QtQuick.Controls::Control::}{availableWidth} |
90 | (and vice versa for contentHeight). This will let the contents fill |
91 | out all the available space horizontally inside the ScrollView, taking |
92 | any padding or scroll bars into account. |
93 | \endlist |
94 | |
95 | \section2 Scroll Bars |
96 | |
97 | The horizontal and vertical scroll bars can be accessed and customized using |
98 | the \l {ScrollBar::horizontal}{ScrollBar.horizontal} and \l {ScrollBar::vertical} |
99 | {ScrollBar.vertical} attached properties. The following example adjusts the scroll |
100 | bar policies so that the horizontal scroll bar is always off, and the vertical |
101 | scroll bar is always on. |
102 | |
103 | \snippet qtquickcontrols2-scrollview-policy.qml file |
104 | |
105 | \section2 Touch vs. Mouse Interaction |
106 | |
107 | On touch, ScrollView enables flicking and makes the scroll bars non-interactive. |
108 | |
109 | \image qtquickcontrols2-scrollindicator.gif |
110 | |
111 | When interacted with a mouse device, flicking is disabled and the scroll bars |
112 | are interactive. |
113 | |
114 | \image qtquickcontrols2-scrollbar.gif |
115 | |
116 | Scroll bars can be made interactive on touch, or non-interactive when interacted |
117 | with a mouse device, by setting the \l {ScrollBar::}{interactive} property explicitly |
118 | to \c true or \c false, respectively. |
119 | |
120 | \snippet qtquickcontrols2-scrollview-interactive.qml file |
121 | |
122 | \sa ScrollBar, ScrollIndicator, {Customizing ScrollView}, {Container Controls}, |
123 | {Focus Management in Qt Quick Controls} |
124 | */ |
125 | |
126 | class QQuickScrollViewPrivate : public QQuickPanePrivate |
127 | { |
128 | Q_DECLARE_PUBLIC(QQuickScrollView) |
129 | |
130 | public: |
131 | QQmlListProperty<QObject> contentData() override; |
132 | QQmlListProperty<QQuickItem> contentChildren() override; |
133 | QList<QQuickItem *> contentChildItems() const override; |
134 | |
135 | QQuickItem *getContentItem() override; |
136 | |
137 | QQuickFlickable *ensureFlickable(bool content); |
138 | bool setFlickable(QQuickFlickable *flickable, bool content); |
139 | |
140 | void flickableContentWidthChanged(); |
141 | void flickableContentHeightChanged(); |
142 | |
143 | qreal getContentWidth() const override; |
144 | qreal getContentHeight() const override; |
145 | |
146 | QQuickScrollBar *verticalScrollBar() const; |
147 | QQuickScrollBar *horizontalScrollBar() const; |
148 | |
149 | void setScrollBarsInteractive(bool interactive); |
150 | |
151 | static void contentData_append(QQmlListProperty<QObject> *prop, QObject *obj); |
152 | static int contentData_count(QQmlListProperty<QObject> *prop); |
153 | static QObject *contentData_at(QQmlListProperty<QObject> *prop, int index); |
154 | static void contentData_clear(QQmlListProperty<QObject> *prop); |
155 | |
156 | static void contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *obj); |
157 | static int contentChildren_count(QQmlListProperty<QQuickItem> *prop); |
158 | static QQuickItem *contentChildren_at(QQmlListProperty<QQuickItem> *prop, int index); |
159 | static void contentChildren_clear(QQmlListProperty<QQuickItem> *prop); |
160 | |
161 | void itemImplicitWidthChanged(QQuickItem *item) override; |
162 | |
163 | bool wasTouched = false; |
164 | QQuickFlickable *flickable = nullptr; |
165 | bool flickableHasExplicitContentWidth = true; |
166 | bool flickableHasExplicitContentHeight = true; |
167 | }; |
168 | |
169 | QList<QQuickItem *> QQuickScrollViewPrivate::contentChildItems() const |
170 | { |
171 | if (!flickable) |
172 | return QList<QQuickItem *>(); |
173 | |
174 | return flickable->contentItem()->childItems(); |
175 | } |
176 | |
177 | QQuickItem *QQuickScrollViewPrivate::getContentItem() |
178 | { |
179 | if (!contentItem) |
180 | executeContentItem(); |
181 | return ensureFlickable(content: false); |
182 | } |
183 | |
184 | QQuickFlickable *QQuickScrollViewPrivate::ensureFlickable(bool content) |
185 | { |
186 | Q_Q(QQuickScrollView); |
187 | if (!flickable) { |
188 | flickableHasExplicitContentWidth = false; |
189 | flickableHasExplicitContentHeight = false; |
190 | setFlickable(flickable: new QQuickFlickable(q), content); |
191 | } |
192 | return flickable; |
193 | } |
194 | |
195 | bool QQuickScrollViewPrivate::setFlickable(QQuickFlickable *item, bool content) |
196 | { |
197 | Q_Q(QQuickScrollView); |
198 | if (item == flickable) |
199 | return false; |
200 | |
201 | QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(object: qmlAttachedPropertiesObject<QQuickScrollBar>(obj: q, create: false)); |
202 | |
203 | if (flickable) { |
204 | flickable->removeEventFilter(obj: q); |
205 | |
206 | if (attached) |
207 | QQuickScrollBarAttachedPrivate::get(attached)->setFlickable(nullptr); |
208 | |
209 | QObjectPrivate::disconnect(sender: flickable->contentItem(), signal: &QQuickItem::childrenChanged, receiverPrivate: this, slot: &QQuickPanePrivate::contentChildrenChange); |
210 | QObjectPrivate::disconnect(sender: flickable, signal: &QQuickFlickable::contentWidthChanged, receiverPrivate: this, slot: &QQuickScrollViewPrivate::flickableContentWidthChanged); |
211 | QObjectPrivate::disconnect(sender: flickable, signal: &QQuickFlickable::contentHeightChanged, receiverPrivate: this, slot: &QQuickScrollViewPrivate::flickableContentHeightChanged); |
212 | } |
213 | |
214 | flickable = item; |
215 | if (content) |
216 | q->setContentItem(flickable); |
217 | |
218 | if (flickable) { |
219 | flickable->installEventFilter(filterObj: q); |
220 | if (hasContentWidth) |
221 | flickable->setContentWidth(contentWidth); |
222 | else |
223 | flickableContentWidthChanged(); |
224 | if (hasContentHeight) |
225 | flickable->setContentHeight(contentHeight); |
226 | else |
227 | flickableContentHeightChanged(); |
228 | |
229 | if (attached) |
230 | QQuickScrollBarAttachedPrivate::get(attached)->setFlickable(flickable); |
231 | |
232 | QObjectPrivate::connect(sender: flickable->contentItem(), signal: &QQuickItem::childrenChanged, receiverPrivate: this, slot: &QQuickPanePrivate::contentChildrenChange); |
233 | QObjectPrivate::connect(sender: flickable, signal: &QQuickFlickable::contentWidthChanged, receiverPrivate: this, slot: &QQuickScrollViewPrivate::flickableContentWidthChanged); |
234 | QObjectPrivate::connect(sender: flickable, signal: &QQuickFlickable::contentHeightChanged, receiverPrivate: this, slot: &QQuickScrollViewPrivate::flickableContentHeightChanged); |
235 | } |
236 | |
237 | return true; |
238 | } |
239 | |
240 | void QQuickScrollViewPrivate::flickableContentWidthChanged() |
241 | { |
242 | Q_Q(QQuickScrollView); |
243 | if (!flickable || !componentComplete) |
244 | return; |
245 | |
246 | const qreal cw = flickable->contentWidth(); |
247 | if (qFuzzyCompare(p1: cw, p2: implicitContentWidth)) |
248 | return; |
249 | |
250 | flickableHasExplicitContentWidth = true; |
251 | implicitContentWidth = cw; |
252 | emit q->implicitContentWidthChanged(); |
253 | } |
254 | |
255 | void QQuickScrollViewPrivate::flickableContentHeightChanged() |
256 | { |
257 | Q_Q(QQuickScrollView); |
258 | if (!flickable || !componentComplete) |
259 | return; |
260 | |
261 | const qreal ch = flickable->contentHeight(); |
262 | if (qFuzzyCompare(p1: ch, p2: implicitContentHeight)) |
263 | return; |
264 | |
265 | flickableHasExplicitContentHeight = true; |
266 | implicitContentHeight = ch; |
267 | emit q->implicitContentHeightChanged(); |
268 | } |
269 | |
270 | qreal QQuickScrollViewPrivate::getContentWidth() const |
271 | { |
272 | if (flickable && flickableHasExplicitContentWidth) |
273 | return flickable->contentWidth(); |
274 | |
275 | // The scrollview wraps a flickable created by us, and nobody searched for it and |
276 | // modified its contentWidth. In that case, since the application does not control |
277 | // this flickable, we fall back to calculate the content width based on the child |
278 | // items inside it. |
279 | return QQuickPanePrivate::getContentWidth(); |
280 | } |
281 | |
282 | qreal QQuickScrollViewPrivate::getContentHeight() const |
283 | { |
284 | if (flickable && flickableHasExplicitContentHeight) |
285 | return flickable->contentHeight(); |
286 | |
287 | // The scrollview wraps a flickable created by us, and nobody searched for it and |
288 | // modified its contentHeight. In that case, since the application does not control |
289 | // this flickable, we fall back to calculate the content height based on the child |
290 | // items inside it. |
291 | return QQuickPanePrivate::getContentHeight(); |
292 | } |
293 | |
294 | QQuickScrollBar *QQuickScrollViewPrivate::verticalScrollBar() const |
295 | { |
296 | Q_Q(const QQuickScrollView); |
297 | QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(object: qmlAttachedPropertiesObject<QQuickScrollBar>(obj: q, create: false)); |
298 | if (!attached) |
299 | return nullptr; |
300 | return attached->vertical(); |
301 | } |
302 | |
303 | QQuickScrollBar *QQuickScrollViewPrivate::horizontalScrollBar() const |
304 | { |
305 | Q_Q(const QQuickScrollView); |
306 | QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(object: qmlAttachedPropertiesObject<QQuickScrollBar>(obj: q, create: false)); |
307 | if (!attached) |
308 | return nullptr; |
309 | return attached->horizontal(); |
310 | } |
311 | |
312 | void QQuickScrollViewPrivate::setScrollBarsInteractive(bool interactive) |
313 | { |
314 | QQuickScrollBar *hbar = horizontalScrollBar(); |
315 | if (hbar) { |
316 | QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(bar: hbar); |
317 | if (!p->explicitInteractive) |
318 | p->setInteractive(interactive); |
319 | } |
320 | |
321 | QQuickScrollBar *vbar = verticalScrollBar(); |
322 | if (vbar) { |
323 | QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(bar: vbar); |
324 | if (!p->explicitInteractive) |
325 | p->setInteractive(interactive); |
326 | } |
327 | } |
328 | |
329 | void QQuickScrollViewPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj) |
330 | { |
331 | QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data); |
332 | if (!p->flickable && p->setFlickable(item: qobject_cast<QQuickFlickable *>(object: obj), content: true)) |
333 | return; |
334 | |
335 | QQuickFlickable *flickable = p->ensureFlickable(content: true); |
336 | Q_ASSERT(flickable); |
337 | QQmlListProperty<QObject> data = flickable->flickableData(); |
338 | data.append(&data, obj); |
339 | } |
340 | |
341 | int QQuickScrollViewPrivate::contentData_count(QQmlListProperty<QObject> *prop) |
342 | { |
343 | QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data); |
344 | if (!p->flickable) |
345 | return 0; |
346 | |
347 | QQmlListProperty<QObject> data = p->flickable->flickableData(); |
348 | return data.count(&data); |
349 | } |
350 | |
351 | QObject *QQuickScrollViewPrivate::contentData_at(QQmlListProperty<QObject> *prop, int index) |
352 | { |
353 | QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data); |
354 | if (!p->flickable) |
355 | return nullptr; |
356 | |
357 | QQmlListProperty<QObject> data = p->flickable->flickableData(); |
358 | return data.at(&data, index); |
359 | } |
360 | |
361 | void QQuickScrollViewPrivate::contentData_clear(QQmlListProperty<QObject> *prop) |
362 | { |
363 | QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data); |
364 | if (!p->flickable) |
365 | return; |
366 | |
367 | QQmlListProperty<QObject> data = p->flickable->flickableData(); |
368 | return data.clear(&data); |
369 | } |
370 | |
371 | void QQuickScrollViewPrivate::contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *item) |
372 | { |
373 | QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data); |
374 | if (!p->flickable) |
375 | p->setFlickable(item: qobject_cast<QQuickFlickable *>(object: item), content: true); |
376 | |
377 | QQuickFlickable *flickable = p->ensureFlickable(content: true); |
378 | Q_ASSERT(flickable); |
379 | QQmlListProperty<QQuickItem> children = flickable->flickableChildren(); |
380 | children.append(&children, item); |
381 | } |
382 | |
383 | int QQuickScrollViewPrivate::contentChildren_count(QQmlListProperty<QQuickItem> *prop) |
384 | { |
385 | QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data); |
386 | if (!p->flickable) |
387 | return 0; |
388 | |
389 | QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren(); |
390 | return children.count(&children); |
391 | } |
392 | |
393 | QQuickItem *QQuickScrollViewPrivate::contentChildren_at(QQmlListProperty<QQuickItem> *prop, int index) |
394 | { |
395 | QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data); |
396 | if (!p->flickable) |
397 | return nullptr; |
398 | |
399 | QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren(); |
400 | return children.at(&children, index); |
401 | } |
402 | |
403 | void QQuickScrollViewPrivate::contentChildren_clear(QQmlListProperty<QQuickItem> *prop) |
404 | { |
405 | QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data); |
406 | if (!p->flickable) |
407 | return; |
408 | |
409 | QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren(); |
410 | children.clear(&children); |
411 | } |
412 | |
413 | void QQuickScrollViewPrivate::itemImplicitWidthChanged(QQuickItem *item) |
414 | { |
415 | // a special case for width<->height dependent content (wrapping text) in ScrollView |
416 | if (contentWidth < 0 && !componentComplete) |
417 | return; |
418 | |
419 | QQuickPanePrivate::itemImplicitWidthChanged(item); |
420 | } |
421 | |
422 | QQuickScrollView::QQuickScrollView(QQuickItem *parent) |
423 | : QQuickPane(*(new QQuickScrollViewPrivate), parent) |
424 | { |
425 | Q_D(QQuickScrollView); |
426 | d->contentWidth = -1; |
427 | d->contentHeight = -1; |
428 | |
429 | setFiltersChildMouseEvents(true); |
430 | setWheelEnabled(true); |
431 | } |
432 | |
433 | /*! |
434 | \qmlproperty list<Object> QtQuick.Controls::ScrollView::contentData |
435 | \default |
436 | |
437 | This property holds the list of content data. |
438 | |
439 | The list contains all objects that have been declared in QML as children of the view. |
440 | |
441 | \note Unlike \c contentChildren, \c contentData does include non-visual QML objects. |
442 | |
443 | \sa Item::data, contentChildren |
444 | */ |
445 | QQmlListProperty<QObject> QQuickScrollViewPrivate::contentData() |
446 | { |
447 | Q_Q(QQuickScrollView); |
448 | return QQmlListProperty<QObject>(q, this, |
449 | QQuickScrollViewPrivate::contentData_append, |
450 | QQuickScrollViewPrivate::contentData_count, |
451 | QQuickScrollViewPrivate::contentData_at, |
452 | QQuickScrollViewPrivate::contentData_clear); |
453 | } |
454 | |
455 | /*! |
456 | \qmlproperty list<Item> QtQuick.Controls::ScrollView::contentChildren |
457 | |
458 | This property holds the list of content children. |
459 | |
460 | The list contains all items that have been declared in QML as children of the view. |
461 | |
462 | \note Unlike \c contentData, \c contentChildren does not include non-visual QML objects. |
463 | |
464 | \sa Item::children, contentData |
465 | */ |
466 | QQmlListProperty<QQuickItem> QQuickScrollViewPrivate::contentChildren() |
467 | { |
468 | Q_Q(QQuickScrollView); |
469 | return QQmlListProperty<QQuickItem>(q, this, |
470 | QQuickScrollViewPrivate::contentChildren_append, |
471 | QQuickScrollViewPrivate::contentChildren_count, |
472 | QQuickScrollViewPrivate::contentChildren_at, |
473 | QQuickScrollViewPrivate::contentChildren_clear); |
474 | } |
475 | |
476 | bool QQuickScrollView::childMouseEventFilter(QQuickItem *item, QEvent *event) |
477 | { |
478 | Q_D(QQuickScrollView); |
479 | switch (event->type()) { |
480 | case QEvent::TouchBegin: |
481 | d->wasTouched = true; |
482 | d->setScrollBarsInteractive(false); |
483 | return false; |
484 | |
485 | case QEvent::TouchEnd: |
486 | d->wasTouched = false; |
487 | return false; |
488 | |
489 | case QEvent::MouseButtonPress: |
490 | // NOTE: Flickable does not handle touch events, only synthesized mouse events |
491 | if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) { |
492 | d->wasTouched = false; |
493 | d->setScrollBarsInteractive(true); |
494 | return false; |
495 | } |
496 | return !d->wasTouched && item == d->flickable; |
497 | |
498 | case QEvent::MouseMove: |
499 | case QEvent::MouseButtonRelease: |
500 | if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) |
501 | return item == d->flickable; |
502 | break; |
503 | |
504 | case QEvent::HoverEnter: |
505 | case QEvent::HoverMove: |
506 | if (d->wasTouched && (item == d->verticalScrollBar() || item == d->horizontalScrollBar())) |
507 | d->setScrollBarsInteractive(true); |
508 | break; |
509 | |
510 | default: |
511 | break; |
512 | } |
513 | |
514 | return false; |
515 | } |
516 | |
517 | bool QQuickScrollView::eventFilter(QObject *object, QEvent *event) |
518 | { |
519 | Q_D(QQuickScrollView); |
520 | if (event->type() == QEvent::Wheel) { |
521 | d->setScrollBarsInteractive(true); |
522 | if (!d->wheelEnabled) |
523 | return true; |
524 | } |
525 | return QQuickPane::eventFilter(watched: object, event); |
526 | } |
527 | |
528 | void QQuickScrollView::keyPressEvent(QKeyEvent *event) |
529 | { |
530 | Q_D(QQuickScrollView); |
531 | QQuickPane::keyPressEvent(event); |
532 | switch (event->key()) { |
533 | case Qt::Key_Up: |
534 | if (QQuickScrollBar *vbar = d->verticalScrollBar()) { |
535 | vbar->decrease(); |
536 | event->accept(); |
537 | } |
538 | break; |
539 | case Qt::Key_Down: |
540 | if (QQuickScrollBar *vbar = d->verticalScrollBar()) { |
541 | vbar->increase(); |
542 | event->accept(); |
543 | } |
544 | break; |
545 | case Qt::Key_Left: |
546 | if (QQuickScrollBar *hbar = d->horizontalScrollBar()) { |
547 | hbar->decrease(); |
548 | event->accept(); |
549 | } |
550 | break; |
551 | case Qt::Key_Right: |
552 | if (QQuickScrollBar *hbar = d->horizontalScrollBar()) { |
553 | hbar->increase(); |
554 | event->accept(); |
555 | } |
556 | break; |
557 | default: |
558 | event->ignore(); |
559 | break; |
560 | } |
561 | } |
562 | |
563 | void QQuickScrollView::componentComplete() |
564 | { |
565 | Q_D(QQuickScrollView); |
566 | QQuickPane::componentComplete(); |
567 | if (!d->contentItem) |
568 | d->ensureFlickable(content: true); |
569 | } |
570 | |
571 | void QQuickScrollView::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) |
572 | { |
573 | Q_D(QQuickScrollView); |
574 | if (newItem != d->flickable) { |
575 | // The new flickable was not created by us. In that case, we always |
576 | // assume/require that it has an explicit content size assigned. |
577 | d->flickableHasExplicitContentWidth = true; |
578 | d->flickableHasExplicitContentHeight = true; |
579 | auto newItemAsFlickable = qobject_cast<QQuickFlickable *>(object: newItem); |
580 | if (newItem && !newItemAsFlickable) |
581 | qmlWarning(me: this) << "ScrollView only supports Flickable types as its contentItem" ; |
582 | d->setFlickable(item: newItemAsFlickable, content: false); |
583 | } |
584 | QQuickPane::contentItemChange(newItem, oldItem); |
585 | } |
586 | |
587 | void QQuickScrollView::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize) |
588 | { |
589 | Q_D(QQuickScrollView); |
590 | QQuickPane::contentSizeChange(newSize, oldSize); |
591 | if (d->flickable) { |
592 | // Only set the content size on the flickable if the flickable doesn't |
593 | // have an explicit assignment from before. Otherwise we can end up overwriting |
594 | // assignments done to those properties by the application. The |
595 | // exception is if the application has assigned a content size |
596 | // directly to the scrollview, which will then win even if the |
597 | // application has assigned something else to the flickable. |
598 | if (d->hasContentWidth || !d->flickableHasExplicitContentWidth) |
599 | d->flickable->setContentWidth(newSize.width()); |
600 | if (d->hasContentHeight || !d->flickableHasExplicitContentHeight) |
601 | d->flickable->setContentHeight(newSize.height()); |
602 | } |
603 | } |
604 | |
605 | #if QT_CONFIG(accessibility) |
606 | QAccessible::Role QQuickScrollView::accessibleRole() const |
607 | { |
608 | return QAccessible::Pane; |
609 | } |
610 | #endif |
611 | |
612 | QT_END_NAMESPACE |
613 | |
614 | #include "moc_qquickscrollview_p.cpp" |
615 | |