Skip to content

Commit

Permalink
Add SH_ItemView_ScrollMode style hint and use it in QMacStyle
Browse files Browse the repository at this point in the history
On OS X, the default scrolling mode of item views should be
per pixel instead of per item. We enforce this through a new
style hint. On all other platforms, the behavior remains the
same.

It's still possible to override the style hint by using the
regular scroll mode setters. Any subsequent style change will
result in a no-op once the setters have been called and until
the properties are reset.

Some auto-tests had to be update to to take the new behavior
into account.

[ChangeLog][QtWidgets][Styles] Added SH_ItemView_ScrollMode
style hint.

[ChangeLog][QtWidgets][Item Views] Item views scroll per pixel
on OS X now.

[ChangeLog][QtWidgets][Item Views] QAbstractItemView::verticalScrollMode
and QAbstractItemView::horizontalScrollMode are now resettable.

Change-Id: I3f923275c99aa4389323b52fc1c5455fe71f8d73
Task-number: QTBUG-50102
Reviewed-by: Jake Petroules <[email protected]>
  • Loading branch information
Gabriel de Dietrich committed Feb 11, 2016
1 parent cc2938b commit 9e8c84a
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 13 deletions.
33 changes: 30 additions & 3 deletions src/widgets/itemviews/qabstractitemview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ QAbstractItemViewPrivate::QAbstractItemViewPrivate()
currentIndexSet(false),
wrapItemText(false),
delayedPendingLayout(true),
moveCursorUpdatedView(false)
moveCursorUpdatedView(false),
verticalScrollModeSet(false),
horizontalScrollModeSet(false)
{
keyboardInputTime.invalidate();
}
Expand Down Expand Up @@ -137,6 +139,9 @@ void QAbstractItemViewPrivate::init()
viewport->setBackgroundRole(QPalette::Base);

q->setAttribute(Qt::WA_InputMethodEnabled);

verticalScrollMode = static_cast<QAbstractItemView::ScrollMode>(q->style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, q, 0));
horizontalScrollMode = static_cast<QAbstractItemView::ScrollMode>(q->style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, q, 0));
}

void QAbstractItemViewPrivate::setHoverIndex(const QPersistentModelIndex &index)
Expand Down Expand Up @@ -1237,12 +1242,14 @@ QAbstractItemView::EditTriggers QAbstractItemView::editTriggers() const
\brief how the view scrolls its contents in the vertical direction
This property controls how the view scroll its contents vertically.
Scrolling can be done either per pixel or per item.
Scrolling can be done either per pixel or per item. Its default value
comes from the style via the QStyle::SH_ItemView_ScrollMode style hint.
*/

void QAbstractItemView::setVerticalScrollMode(ScrollMode mode)
{
Q_D(QAbstractItemView);
d->verticalScrollModeSet = true;
if (mode == d->verticalScrollMode)
return;
QModelIndex topLeft = indexAt(QPoint(0, 0));
Expand All @@ -1261,18 +1268,27 @@ QAbstractItemView::ScrollMode QAbstractItemView::verticalScrollMode() const
return d->verticalScrollMode;
}

void QAbstractItemView::resetVerticalScrollMode()
{
auto sm = static_cast<ScrollMode>(style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, this, 0));
setVerticalScrollMode(sm);
d_func()->verticalScrollModeSet = false;
}

/*!
\since 4.2
\property QAbstractItemView::horizontalScrollMode
\brief how the view scrolls its contents in the horizontal direction
This property controls how the view scroll its contents horizontally.
Scrolling can be done either per pixel or per item.
Scrolling can be done either per pixel or per item. Its default value
comes from the style via the QStyle::SH_ItemView_ScrollMode style hint.
*/

void QAbstractItemView::setHorizontalScrollMode(ScrollMode mode)
{
Q_D(QAbstractItemView);
d->horizontalScrollModeSet = true;
if (mode == d->horizontalScrollMode)
return;
d->horizontalScrollMode = mode;
Expand All @@ -1289,6 +1305,13 @@ QAbstractItemView::ScrollMode QAbstractItemView::horizontalScrollMode() const
return d->horizontalScrollMode;
}

void QAbstractItemView::resetHorizontalScrollMode()
{
auto sm = static_cast<ScrollMode>(style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, this, 0));
setHorizontalScrollMode(sm);
d_func()->horizontalScrollModeSet = false;
}

#ifndef QT_NO_DRAGANDDROP
/*!
\since 4.2
Expand Down Expand Up @@ -1627,6 +1650,10 @@ bool QAbstractItemView::event(QEvent *event)
break;
case QEvent::StyleChange:
doItemsLayout();
if (!d->verticalScrollModeSet)
resetVerticalScrollMode();
if (!d->horizontalScrollModeSet)
resetHorizontalScrollMode();
break;
case QEvent::FocusOut:
d->checkPersistentEditorFocus();
Expand Down
6 changes: 4 additions & 2 deletions src/widgets/itemviews/qabstractitemview.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ class Q_WIDGETS_EXPORT QAbstractItemView : public QAbstractScrollArea
Q_PROPERTY(SelectionBehavior selectionBehavior READ selectionBehavior WRITE setSelectionBehavior)
Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize NOTIFY iconSizeChanged)
Q_PROPERTY(Qt::TextElideMode textElideMode READ textElideMode WRITE setTextElideMode)
Q_PROPERTY(ScrollMode verticalScrollMode READ verticalScrollMode WRITE setVerticalScrollMode)
Q_PROPERTY(ScrollMode horizontalScrollMode READ horizontalScrollMode WRITE setHorizontalScrollMode)
Q_PROPERTY(ScrollMode verticalScrollMode READ verticalScrollMode WRITE setVerticalScrollMode RESET resetVerticalScrollMode)
Q_PROPERTY(ScrollMode horizontalScrollMode READ horizontalScrollMode WRITE setHorizontalScrollMode RESET resetHorizontalScrollMode)

public:
enum SelectionMode {
Expand Down Expand Up @@ -147,9 +147,11 @@ class Q_WIDGETS_EXPORT QAbstractItemView : public QAbstractScrollArea

void setVerticalScrollMode(ScrollMode mode);
ScrollMode verticalScrollMode() const;
void resetVerticalScrollMode();

void setHorizontalScrollMode(ScrollMode mode);
ScrollMode horizontalScrollMode() const;
void resetHorizontalScrollMode();

void setAutoScroll(bool enable);
bool hasAutoScroll() const;
Expand Down
4 changes: 4 additions & 0 deletions src/widgets/itemviews/qabstractitemview_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,10 @@ class Q_AUTOTEST_EXPORT QAbstractItemViewPrivate : public QAbstractScrollAreaPri
mutable bool delayedPendingLayout;
bool moveCursorUpdatedView;

// Whether scroll mode has been explicitly set or its value come from SH_ItemView_ScrollMode
bool verticalScrollModeSet;
bool horizontalScrollModeSet;

private:
mutable QBasicTimer delayedLayout;
mutable QBasicTimer fetchMoreTimer;
Expand Down
3 changes: 3 additions & 0 deletions src/widgets/styles/qcommonstyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5215,6 +5215,9 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget
case SH_Splitter_OpaqueResize:
ret = true;
break;
case SH_ItemView_ScrollMode:
ret = QAbstractItemView::ScrollPerItem;
break;
default:
ret = 0;
break;
Expand Down
3 changes: 3 additions & 0 deletions src/widgets/styles/qmacstyle_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3043,6 +3043,9 @@ AHIG would have (20, 8, 10) here but that makes
ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay;
}
break;
case SH_ItemView_ScrollMode:
ret = QAbstractItemView::ScrollPerPixel;
break;
default:
ret = QCommonStyle::styleHint(sh, opt, w, hret);
break;
Expand Down
4 changes: 4 additions & 0 deletions src/widgets/styles/qstyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1978,6 +1978,10 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
tab is changed while dragging over the tabbar, in milliseconds. This
enum value has been introduced in Qt 5.4
\value SH_ItemView_ScrollMode The default vertical and horizontal scroll mode as specified
by the style. Can be overridden with QAbstractItemView::setVerticalScrollMode() and
QAbstractItemView::setHorizontalScrollMode(). This enum value has been introduced in Qt 5.7.
\sa styleHint()
*/

Expand Down
1 change: 1 addition & 0 deletions src/widgets/styles/qstyle.h
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@ class Q_WIDGETS_EXPORT QStyle : public QObject
SH_Menu_SubMenuSloppyCloseTimeout,
SH_Menu_SubMenuResetWhenReenteringParent,
SH_Menu_SubMenuDontStartSloppyOnLeave,
SH_ItemView_ScrollMode,
// Add new style hint values here

SH_CustomBase = 0xf0000000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include <qstyleditemdelegate.h>
#include <qstringlistmodel.h>
#include <qsortfilterproxymodel.h>
#include <qproxystyle.h>

static inline void setFrameless(QWidget *w)
{
Expand Down Expand Up @@ -246,6 +247,7 @@ private slots:
void sizeHintChangeTriggersLayout();
void shiftSelectionAfterChangingModelContents();
void QTBUG48968_reentrant_updateEditorGeometries();
void QTBUG50102_SH_ItemView_ScrollMode();
};

class MyAbstractItemDelegate : public QAbstractItemDelegate
Expand Down Expand Up @@ -2018,5 +2020,53 @@ void tst_QAbstractItemView::QTBUG48968_reentrant_updateEditorGeometries()
// No crash, all fine.
}

class ScrollModeProxyStyle: public QProxyStyle
{
public:
ScrollModeProxyStyle(QAbstractItemView::ScrollMode sm, QStyle *style = 0)
: QProxyStyle(style)
, scrollMode(sm == QAbstractItemView::ScrollPerItem ?
QAbstractItemView::ScrollPerPixel : QAbstractItemView::ScrollPerItem)
{ }

int styleHint(QStyle::StyleHint hint, const QStyleOption *opt, const QWidget *w, QStyleHintReturn *returnData) const override
{
if (hint == SH_ItemView_ScrollMode)
return scrollMode;

return baseStyle()->styleHint(hint, opt, w, returnData);
}

QAbstractItemView::ScrollMode scrollMode;
};

void tst_QAbstractItemView::QTBUG50102_SH_ItemView_ScrollMode()
{
QListView view;

// Default comes from the style
auto styleScrollMode = static_cast<QAbstractItemView::ScrollMode>(view.style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, &view, 0));
QCOMPARE(view.verticalScrollMode(), styleScrollMode);
QCOMPARE(view.horizontalScrollMode(), styleScrollMode);

// Change style, get new value
view.setStyle(new ScrollModeProxyStyle(styleScrollMode));
auto proxyScrollMode = static_cast<QAbstractItemView::ScrollMode>(view.style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, &view, 0));
QVERIFY(styleScrollMode != proxyScrollMode);
QCOMPARE(view.verticalScrollMode(), proxyScrollMode);
QCOMPARE(view.horizontalScrollMode(), proxyScrollMode);

// Explicitly set vertical, same value
view.setVerticalScrollMode(proxyScrollMode);
QCOMPARE(view.verticalScrollMode(), proxyScrollMode);
QCOMPARE(view.horizontalScrollMode(), proxyScrollMode);

// Change style, won't change value for vertical, will change for horizontal
view.setStyle(new ScrollModeProxyStyle(proxyScrollMode));
QCOMPARE(view.verticalScrollMode(), proxyScrollMode);
QCOMPARE(view.horizontalScrollMode(), styleScrollMode);
}


QTEST_MAIN(tst_QAbstractItemView)
#include "tst_qabstractitemview.moc"
28 changes: 21 additions & 7 deletions tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,18 @@ class QtTestModel: public QAbstractListModel
mutable bool wrongIndex;
};

class ScrollPerItemListView : public QListView
{
public:
explicit ScrollPerItemListView(QWidget *parent = Q_NULLPTR)
: QListView(parent)
{
// Force per item scroll mode since it comes from the style by default
setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
}
};

void tst_QListView::initTestCase()
{
#ifdef Q_OS_WINCE //disable magic for WindowsCE
Expand Down Expand Up @@ -823,7 +835,7 @@ void tst_QListView::setCurrentIndex()
{
QStringListModel model(generateList(QLatin1String("item "), 20));

QListView view;
ScrollPerItemListView view;
view.setModel(&model);

view.resize(220,182);
Expand Down Expand Up @@ -1153,7 +1165,7 @@ void tst_QListView::scrollTo()
{
QWidget topLevel;
setFrameless(&topLevel);
QListView lv(&topLevel);
ScrollPerItemListView lv(&topLevel);
QStringListModel model(&lv);
QStringList list;
list << "Short item 1";
Expand Down Expand Up @@ -1189,6 +1201,7 @@ void tst_QListView::scrollTo()
model.setStringList(list);
lv.setModel(&model);
lv.setFixedSize(110, 200);

topLevel.show();
QVERIFY(QTest::qWaitForWindowExposed(&topLevel));

Expand Down Expand Up @@ -1262,7 +1275,7 @@ void tst_QListView::scrollBarRanges()
const int rowHeight = 20;

QWidget topLevel;
QListView lv(&topLevel);
ScrollPerItemListView lv(&topLevel);
QStringListModel model(&lv);
QStringList list;
for (int i = 0; i < rowCount; ++i)
Expand All @@ -1271,6 +1284,7 @@ void tst_QListView::scrollBarRanges()
model.setStringList(list);
lv.setModel(&model);
lv.resize(250, 130);

TestDelegate *delegate = new TestDelegate(&lv);
delegate->m_sizeHint = QSize(100, rowHeight);
lv.setItemDelegate(delegate);
Expand Down Expand Up @@ -1814,7 +1828,7 @@ void tst_QListView::taskQTBUG_2233_scrollHiddenItems()

QWidget topLevel;
setFrameless(&topLevel);
QListView view(&topLevel);
ScrollPerItemListView view(&topLevel);
QStringListModel model(&view);
QStringList list;
for (int i = 0; i < rowCount; ++i)
Expand Down Expand Up @@ -2060,7 +2074,7 @@ void tst_QListView::taskQTBUG_21115_scrollToAndHiddenItems()
{
QFETCH(int, flow);

QListView lv;
ScrollPerItemListView lv;
lv.setUniformItemSizes(true);
lv.setFlow(static_cast<QListView::Flow>(flow));

Expand Down Expand Up @@ -2155,7 +2169,7 @@ void tst_QListView::taskQTBUG_21804_hiddenItemsAndScrollingWithKeys()
model.setStringList(list);

// create listview
QListView lv;
ScrollPerItemListView lv;
lv.setFlow(static_cast<QListView::Flow>(flow));
lv.setSpacing(spacing);
lv.setModel(&model);
Expand Down Expand Up @@ -2227,7 +2241,7 @@ void tst_QListView::spacing()
model.setStringList(list);

// create listview
QListView lv;
ScrollPerItemListView lv;
lv.setFlow(static_cast<QListView::Flow>(flow));
lv.setModel(&model);
lv.setSpacing(spacing);
Expand Down
2 changes: 1 addition & 1 deletion tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ void tst_QTreeView::construction()
QCOMPARE(view.sizeHintForRow(1), -1);
QVERIFY(!view.tabKeyNavigation());
QCOMPARE(view.textElideMode(), Qt::ElideRight);
QCOMPARE(view.verticalScrollMode(), QAbstractItemView::ScrollPerItem);
QCOMPARE(static_cast<int>(view.verticalScrollMode()), view.style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, &view));
QCOMPARE(view.visualRect(QModelIndex()), QRect());

// QTreeView properties
Expand Down

0 comments on commit 9e8c84a

Please sign in to comment.