Add QStyle::SH_SpinBox_StepModifier style hint

This patch allows the developer to pick which keyboard modifier
increases the number of steps a QAbstractSpinBox takes when the user
interacts with it.

The modifier can be either Qt::ControlModifier (default),
Qt::ShiftModifier or Qt::NoModifier. Qt::NoModifier disables the step
modifier. Note that on macOS, Control corresponds to the Command key.

Holding the modifier increases the step rate when:
- scrolling;
- pressing the up/down keys;
- pressing the spin box up/down buttons.

[ChangeLog][QtWidgets][QStyle] QStyle::SH_SpinBox_StepModifier allows
the developer to pick which keyboard modifier increases the number of
steps a QAbstractSpinBox takes for the following interactions:
scrolling, up/down keyboard keys and the spin box buttons. The
Qt::ShiftModifier can now be used, or the feature can be disabled
using Qt::NoModifier. Previously, only Qt::ControlModifier could be
used as the modifier.

Change-Id: Ib5518127e86a8f67798a9a1d6e860c6e35896e6f
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
Nathan Collins 2018-05-18 16:27:43 +01:00 committed by Mitch Curtis
parent 21291d78c5
commit e40f23f098
7 changed files with 626 additions and 272 deletions

View File

@ -5306,6 +5306,9 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget
case SH_SpinBox_ButtonsInsideFrame: case SH_SpinBox_ButtonsInsideFrame:
ret = true; ret = true;
break; break;
case SH_SpinBox_StepModifier:
ret = Qt::ControlModifier;
break;
default: default:
ret = 0; ret = 0;
break; break;

View File

@ -2001,6 +2001,13 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
Determnines if the spin box buttons are inside the line edit frame. Determnines if the spin box buttons are inside the line edit frame.
This enum value has been introduced in Qt 5.11. This enum value has been introduced in Qt 5.11.
\value SH_SpinBox_StepModifier
Determines which Qt::KeyboardModifier increases the step rate of
QAbstractSpinBox. Possible values are Qt::NoModifier,
Qt::ControlModifier (default) or Qt::ShiftModifier. Qt::NoModifier
disables this feature.
This enum value has been introduced in Qt 5.12.
\sa styleHint() \sa styleHint()
*/ */

View File

@ -741,6 +741,7 @@ public:
SH_Widget_Animation_Duration, SH_Widget_Animation_Duration,
SH_ComboBox_AllowWheelScrolling, SH_ComboBox_AllowWheelScrolling,
SH_SpinBox_ButtonsInsideFrame, SH_SpinBox_ButtonsInsideFrame,
SH_SpinBox_StepModifier,
// Add new style hint values here // Add new style hint values here
SH_CustomBase = 0xf0000000 SH_CustomBase = 0xf0000000

View File

@ -106,6 +106,10 @@ QT_BEGIN_NAMESPACE
the spinbox buttons. Note that on macOS, Control corresponds to the the spinbox buttons. Note that on macOS, Control corresponds to the
Command key. Command key.
Since Qt 5.12, QStyle::SH_SpinBox_StepModifier can be used to select
which Qt::KeyboardModifier increases the step rate. Qt::NoModifier
disables this feature.
QAbstractSpinBox also provide a virtual function stepEnabled() to QAbstractSpinBox also provide a virtual function stepEnabled() to
determine whether stepping up/down is allowed at any point. This determine whether stepping up/down is allowed at any point. This
function returns a bitset of StepEnabled. function returns a bitset of StepEnabled.
@ -840,6 +844,7 @@ void QAbstractSpinBox::changeEvent(QEvent *event)
style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatThreshold, 0, this); style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatThreshold, 0, this);
if (d->edit) if (d->edit)
d->edit->setFrame(!style()->styleHint(QStyle::SH_SpinBox_ButtonsInsideFrame, nullptr, this)); d->edit->setFrame(!style()->styleHint(QStyle::SH_SpinBox_ButtonsInsideFrame, nullptr, this));
d->stepModifier = static_cast<Qt::KeyboardModifier>(style()->styleHint(QStyle::SH_SpinBox_StepModifier, nullptr, this));
d->reset(); d->reset();
d->updateEditFieldGeometry(); d->updateEditFieldGeometry();
break; break;

View File

@ -114,6 +114,26 @@ public:
} }
}; };
class StepModifierStyle : public QProxyStyle
{
Q_OBJECT
public:
using QProxyStyle::QProxyStyle;
int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr,
const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override
{
switch (hint) {
case QStyle::SH_SpinBox_StepModifier:
return stepModifier;
default:
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
}
Qt::KeyboardModifier stepModifier = Qt::ControlModifier;
};
class tst_QDateTimeEdit : public QObject class tst_QDateTimeEdit : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -295,6 +315,12 @@ static QLatin1String modifierToName(Qt::KeyboardModifier modifier)
case Qt::ShiftModifier: case Qt::ShiftModifier:
return QLatin1Literal("Shift"); return QLatin1Literal("Shift");
break; break;
case Qt::AltModifier:
return QLatin1Literal("Alt");
break;
case Qt::MetaModifier:
return QLatin1Literal("Meta");
break;
default: default:
qFatal("Unexpected keyboard modifier"); qFatal("Unexpected keyboard modifier");
return QLatin1String(); return QLatin1String();
@ -3110,6 +3136,7 @@ void tst_QDateTimeEdit::wheelEvent_data()
#if QT_CONFIG(wheelevent) #if QT_CONFIG(wheelevent)
QTest::addColumn<QPoint>("angleDelta"); QTest::addColumn<QPoint>("angleDelta");
QTest::addColumn<int>("qt4Delta"); QTest::addColumn<int>("qt4Delta");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); QTest::addColumn<Qt::KeyboardModifiers>("modifiers");
QTest::addColumn<Qt::MouseEventSource>("source"); QTest::addColumn<Qt::MouseEventSource>("source");
QTest::addColumn<QDateTimeEdit::Section>("section"); QTest::addColumn<QDateTimeEdit::Section>("section");
@ -3121,8 +3148,14 @@ void tst_QDateTimeEdit::wheelEvent_data()
const auto directions = {true, false}; const auto directions = {true, false};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ShiftModifier,
Qt::ControlModifier, Qt::ControlModifier,
Qt::ShiftModifier}; Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
const auto sources = {Qt::MouseEventNotSynthesized, const auto sources = {Qt::MouseEventNotSynthesized,
Qt::MouseEventSynthesizedBySystem, Qt::MouseEventSynthesizedBySystem,
@ -3148,73 +3181,82 @@ void tst_QDateTimeEdit::wheelEvent_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
for (auto source : sources) { const auto stepModifierName = modifierToName(stepModifier);
if (stepModifierName.isEmpty())
continue;
const int steps = (modifier & stepModifier ? 10 : 1)
* (up ? 1 : -1);
for (auto source : sources) {
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
QPoint angleDelta; QPoint angleDelta;
if ((modifier & Qt::ShiftModifier) && if ((modifier & Qt::ShiftModifier) &&
source == Qt::MouseEventNotSynthesized) { source == Qt::MouseEventNotSynthesized) {
// On macOS the Shift modifier converts vertical // On macOS the Shift modifier converts vertical
// mouse wheel events to horizontal. // mouse wheel events to horizontal.
angleDelta = { units, 0 }; angleDelta = { units, 0 };
} else { } else {
// However, this is not the case for trackpad scroll // However, this is not the case for trackpad scroll
// events. // events.
angleDelta = { 0, units }; angleDelta = { 0, units };
} }
#else #else
const QPoint angleDelta(0, units); const QPoint angleDelta(0, units);
#endif #endif
QLatin1String sourceName; QLatin1String sourceName;
switch (source) { switch (source) {
case Qt::MouseEventNotSynthesized: case Qt::MouseEventNotSynthesized:
sourceName = QLatin1Literal("NotSynthesized"); sourceName = QLatin1Literal("NotSynthesized");
break; break;
case Qt::MouseEventSynthesizedBySystem: case Qt::MouseEventSynthesizedBySystem:
sourceName = QLatin1Literal("SynthesizedBySystem"); sourceName = QLatin1Literal("SynthesizedBySystem");
break; break;
case Qt::MouseEventSynthesizedByQt: case Qt::MouseEventSynthesizedByQt:
sourceName = QLatin1Literal("SynthesizedByQt"); sourceName = QLatin1Literal("SynthesizedByQt");
break; break;
case Qt::MouseEventSynthesizedByApplication: case Qt::MouseEventSynthesizedByApplication:
sourceName = QLatin1Literal("SynthesizedByApplication"); sourceName = QLatin1Literal("SynthesizedByApplication");
break; break;
default: default:
qFatal("Unexpected wheel event source"); qFatal("Unexpected wheel event source");
continue;
}
for (const auto section : sections) {
DateList expectedDates;
if (fraction)
expectedDates << startDate;
const auto expectedDate = stepDate(startDate, section, steps);
if (!expectedDate.isValid())
continue; continue;
}
expectedDates << expectedDate; for (const auto section : sections) {
const QLatin1String sectionName = sectionToName(section); DateList expectedDates;
if (fraction)
expectedDates << startDate;
QTest::addRow("%s%s%sWith%sKeyboardModifier%s", const auto expectedDate = stepDate(startDate, section, steps);
fraction ? "half" : "full", if (!expectedDate.isValid())
up ? "Up" : "Down", continue;
sectionName.latin1(),
modifierName.latin1(), expectedDates << expectedDate;
sourceName.latin1())
<< angleDelta const QLatin1String sectionName = sectionToName(section);
<< units
<< modifiers QTest::addRow("%s%s%s%sWith%sKeyboardModifier%s",
<< source fraction ? "half" : "full",
<< section up ? "Up" : "Down",
<< startDate stepModifierName.latin1(),
<< expectedDates; sectionName.latin1(),
modifierName.latin1(),
sourceName.latin1())
<< angleDelta
<< units
<< static_cast<int>(stepModifier)
<< modifiers
<< source
<< section
<< startDate
<< expectedDates;
}
} }
} }
} }
@ -3230,6 +3272,7 @@ void tst_QDateTimeEdit::wheelEvent()
#if QT_CONFIG(wheelevent) #if QT_CONFIG(wheelevent)
QFETCH(QPoint, angleDelta); QFETCH(QPoint, angleDelta);
QFETCH(int, qt4Delta); QFETCH(int, qt4Delta);
QFETCH(int, stepModifier);
QFETCH(Qt::KeyboardModifiers, modifiers); QFETCH(Qt::KeyboardModifiers, modifiers);
QFETCH(Qt::MouseEventSource, source); QFETCH(Qt::MouseEventSource, source);
QFETCH(QDateTimeEdit::Section, section); QFETCH(QDateTimeEdit::Section, section);
@ -3240,6 +3283,11 @@ void tst_QDateTimeEdit::wheelEvent()
edit.setDate(startDate); edit.setDate(startDate);
edit.setCurrentSection(section); edit.setCurrentSection(section);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style(
new StepModifierStyle);
style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
edit.setStyle(style.data());
QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, qt4Delta, QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, qt4Delta,
Qt::Vertical, Qt::NoButton, modifiers, Qt::NoScrollPhase, Qt::Vertical, Qt::NoButton, modifiers, Qt::NoScrollPhase,
source); source);
@ -3977,6 +4025,7 @@ void tst_QDateTimeEdit::dateEditCorrectSectionSize()
void tst_QDateTimeEdit::stepModifierKeys_data() void tst_QDateTimeEdit::stepModifierKeys_data()
{ {
QTest::addColumn<QDate>("startDate"); QTest::addColumn<QDate>("startDate");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<QDateTimeEdit::Section>("section"); QTest::addColumn<QDateTimeEdit::Section>("section");
QTest::addColumn<QTestEventList>("keys"); QTest::addColumn<QTestEventList>("keys");
QTest::addColumn<QDate>("expectedDate"); QTest::addColumn<QDate>("expectedDate");
@ -3984,8 +4033,14 @@ void tst_QDateTimeEdit::stepModifierKeys_data()
const auto keyList = {Qt::Key_Up, Qt::Key_Down}; const auto keyList = {Qt::Key_Up, Qt::Key_Down};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ControlModifier, Qt::ShiftModifier,
Qt::ShiftModifier}; Qt::ControlModifier,
Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
const auto sections = {QDateTimeEdit::DaySection, const auto sections = {QDateTimeEdit::DaySection,
QDateTimeEdit::MonthSection, QDateTimeEdit::MonthSection,
@ -4007,25 +4062,34 @@ void tst_QDateTimeEdit::stepModifierKeys_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
for (const auto section : sections) { const auto stepModifierName = modifierToName(stepModifier);
if (stepModifierName.isEmpty())
const auto expectedDate = stepDate(startDate, section, steps);
if (!expectedDate.isValid())
continue; continue;
const auto sectionName = sectionToName(section); const int steps = (modifier & stepModifier ? 10 : 1)
* (up ? 1 : -1);
QTest::addRow("%s%sWith%sKeyboardModifier", for (const auto section : sections) {
up ? "up" : "down",
sectionName.latin1(), const auto expectedDate = stepDate(startDate, section, steps);
modifierName.latin1()) if (!expectedDate.isValid())
<< startDate continue;
<< section
<< keys const auto sectionName = sectionToName(section);
<< expectedDate;
QTest::addRow("%s%s%sWith%sKeyboardModifier",
up ? "up" : "down",
stepModifierName.latin1(),
sectionName.latin1(),
modifierName.latin1())
<< startDate
<< static_cast<int>(stepModifier)
<< section
<< keys
<< expectedDate;
}
} }
} }
} }
@ -4034,6 +4098,7 @@ void tst_QDateTimeEdit::stepModifierKeys_data()
void tst_QDateTimeEdit::stepModifierKeys() void tst_QDateTimeEdit::stepModifierKeys()
{ {
QFETCH(QDate, startDate); QFETCH(QDate, startDate);
QFETCH(int, stepModifier);
QFETCH(QDateTimeEdit::Section, section); QFETCH(QDateTimeEdit::Section, section);
QFETCH(QTestEventList, keys); QFETCH(QTestEventList, keys);
QFETCH(QDate, expectedDate); QFETCH(QDate, expectedDate);
@ -4044,6 +4109,11 @@ void tst_QDateTimeEdit::stepModifierKeys()
QVERIFY(QTest::qWaitForWindowActive(&edit)); QVERIFY(QTest::qWaitForWindowActive(&edit));
edit.setCurrentSection(section); edit.setCurrentSection(section);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style(
new StepModifierStyle);
style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
edit.setStyle(style.data());
QCOMPARE(edit.date(), startDate); QCOMPARE(edit.date(), startDate);
keys.simulate(&edit); keys.simulate(&edit);
QCOMPARE(edit.date(), expectedDate); QCOMPARE(edit.date(), expectedDate);
@ -4052,6 +4122,7 @@ void tst_QDateTimeEdit::stepModifierKeys()
void tst_QDateTimeEdit::stepModifierButtons_data() void tst_QDateTimeEdit::stepModifierButtons_data()
{ {
QTest::addColumn<QStyle::SubControl>("subControl"); QTest::addColumn<QStyle::SubControl>("subControl");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); QTest::addColumn<Qt::KeyboardModifiers>("modifiers");
QTest::addColumn<QDateTimeEdit::Section>("section"); QTest::addColumn<QDateTimeEdit::Section>("section");
QTest::addColumn<QTime>("startTime"); QTest::addColumn<QTime>("startTime");
@ -4060,8 +4131,14 @@ void tst_QDateTimeEdit::stepModifierButtons_data()
const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown}; const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ControlModifier, Qt::ShiftModifier,
Qt::ShiftModifier}; Qt::ControlModifier,
Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
const auto sections = {QDateTimeEdit::SecondSection, const auto sections = {QDateTimeEdit::SecondSection,
QDateTimeEdit::MinuteSection, QDateTimeEdit::MinuteSection,
@ -4082,26 +4159,35 @@ void tst_QDateTimeEdit::stepModifierButtons_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
for (const auto section : sections) { const auto stepModifierName = modifierToName(stepModifier);
if (stepModifierName.isEmpty())
const auto expectedTime = stepTime(startTime, section, steps);
if (!expectedTime.isValid())
continue; continue;
const auto sectionName = sectionToName(section); const int steps = (modifier & stepModifier ? 10 : 1)
* (up ? 1 : -1);
QTest::addRow("%s%sWith%sKeyboardModifier", for (const auto section : sections) {
up ? "up" : "down",
sectionName.latin1(), const auto expectedTime = stepTime(startTime, section, steps);
modifierName.latin1()) if (!expectedTime.isValid())
<< subControl continue;
<< modifiers
<< section const auto sectionName = sectionToName(section);
<< startTime
<< expectedTime; QTest::addRow("%s%s%sWith%sKeyboardModifier",
up ? "up" : "down",
stepModifierName.latin1(),
sectionName.latin1(),
modifierName.latin1())
<< subControl
<< static_cast<int>(stepModifier)
<< modifiers
<< section
<< startTime
<< expectedTime;
}
} }
} }
} }
@ -4110,6 +4196,7 @@ void tst_QDateTimeEdit::stepModifierButtons_data()
void tst_QDateTimeEdit::stepModifierButtons() void tst_QDateTimeEdit::stepModifierButtons()
{ {
QFETCH(QStyle::SubControl, subControl); QFETCH(QStyle::SubControl, subControl);
QFETCH(int, stepModifier);
QFETCH(Qt::KeyboardModifiers, modifiers); QFETCH(Qt::KeyboardModifiers, modifiers);
QFETCH(QDateTimeEdit::Section, section); QFETCH(QDateTimeEdit::Section, section);
QFETCH(QTime, startTime); QFETCH(QTime, startTime);
@ -4121,6 +4208,11 @@ void tst_QDateTimeEdit::stepModifierButtons()
QVERIFY(QTest::qWaitForWindowActive(&edit)); QVERIFY(QTest::qWaitForWindowActive(&edit));
edit.setCurrentSection(section); edit.setCurrentSection(section);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style(
new StepModifierStyle);
style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
edit.setStyle(style.data());
QStyleOptionSpinBox spinBoxStyleOption; QStyleOptionSpinBox spinBoxStyleOption;
edit.initStyleOption(&spinBoxStyleOption); edit.initStyleOption(&spinBoxStyleOption);
@ -4135,14 +4227,21 @@ void tst_QDateTimeEdit::stepModifierButtons()
void tst_QDateTimeEdit::stepModifierPressAndHold_data() void tst_QDateTimeEdit::stepModifierPressAndHold_data()
{ {
QTest::addColumn<QStyle::SubControl>("subControl"); QTest::addColumn<QStyle::SubControl>("subControl");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); QTest::addColumn<Qt::KeyboardModifiers>("modifiers");
QTest::addColumn<int>("expectedStepModifier"); QTest::addColumn<int>("expectedStepModifier");
const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown}; const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ShiftModifier,
Qt::ControlModifier, Qt::ControlModifier,
Qt::ShiftModifier}; Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
for (auto subControl : subControls) { for (auto subControl : subControls) {
@ -4157,15 +4256,24 @@ void tst_QDateTimeEdit::stepModifierPressAndHold_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
QTest::addRow("%sWith%sKeyboardModifier", const auto stepModifierName = modifierToName(stepModifier);
up ? "up" : "down", if (stepModifierName.isEmpty())
modifierName.latin1()) continue;
<< subControl
<< modifiers const int steps = (modifier & stepModifier ? 10 : 1)
<< steps; * (up ? 1 : -1);
QTest::addRow("%s%sWith%sKeyboardModifier",
up ? "up" : "down",
stepModifierName.latin1(),
modifierName.latin1())
<< subControl
<< static_cast<int>(stepModifier)
<< modifiers
<< steps;
}
} }
} }
} }
@ -4173,17 +4281,20 @@ void tst_QDateTimeEdit::stepModifierPressAndHold_data()
void tst_QDateTimeEdit::stepModifierPressAndHold() void tst_QDateTimeEdit::stepModifierPressAndHold()
{ {
QFETCH(QStyle::SubControl, subControl); QFETCH(QStyle::SubControl, subControl);
QFETCH(int, stepModifier);
QFETCH(Qt::KeyboardModifiers, modifiers); QFETCH(Qt::KeyboardModifiers, modifiers);
QFETCH(int, expectedStepModifier); QFETCH(int, expectedStepModifier);
const QDate startDate(2000, 1, 1); const QDate startDate(2000, 1, 1);
EditorDateEdit edit(0); EditorDateEdit edit(0);
QScopedPointer<PressAndHoldStyle, QScopedPointerDeleteLater> pressAndHoldStyle(
new PressAndHoldStyle);
edit.setStyle(pressAndHoldStyle.data());
edit.setDate(startDate); edit.setDate(startDate);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> stepModifierStyle(
new StepModifierStyle(new PressAndHoldStyle));
stepModifierStyle->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
edit.setStyle(stepModifierStyle.data());
QSignalSpy spy(&edit, &EditorDateEdit::dateChanged); QSignalSpy spy(&edit, &EditorDateEdit::dateChanged);
edit.show(); edit.show();

View File

@ -103,6 +103,26 @@ public:
} }
}; };
class StepModifierStyle : public QProxyStyle
{
Q_OBJECT
public:
using QProxyStyle::QProxyStyle;
int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr,
const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override
{
switch (hint) {
case QStyle::SH_SpinBox_StepModifier:
return stepModifier;
default:
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
}
Qt::KeyboardModifier stepModifier = Qt::ControlModifier;
};
class tst_QDoubleSpinBox : public QObject class tst_QDoubleSpinBox : public QObject
{ {
@ -209,6 +229,12 @@ static QLatin1String modifierToName(Qt::KeyboardModifier modifier)
case Qt::ShiftModifier: case Qt::ShiftModifier:
return QLatin1Literal("Shift"); return QLatin1Literal("Shift");
break; break;
case Qt::AltModifier:
return QLatin1Literal("Alt");
break;
case Qt::MetaModifier:
return QLatin1Literal("Meta");
break;
default: default:
qFatal("Unexpected keyboard modifier"); qFatal("Unexpected keyboard modifier");
return QLatin1String(); return QLatin1String();
@ -1338,6 +1364,7 @@ void tst_QDoubleSpinBox::wheelEvents_data()
#if QT_CONFIG(wheelevent) #if QT_CONFIG(wheelevent)
QTest::addColumn<QPoint>("angleDelta"); QTest::addColumn<QPoint>("angleDelta");
QTest::addColumn<int>("qt4Delta"); QTest::addColumn<int>("qt4Delta");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<Qt::KeyboardModifiers>("modifier"); QTest::addColumn<Qt::KeyboardModifiers>("modifier");
QTest::addColumn<Qt::MouseEventSource>("source"); QTest::addColumn<Qt::MouseEventSource>("source");
QTest::addColumn<double>("start"); QTest::addColumn<double>("start");
@ -1348,8 +1375,14 @@ void tst_QDoubleSpinBox::wheelEvents_data()
const auto directions = {true, false}; const auto directions = {true, false};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ShiftModifier,
Qt::ControlModifier, Qt::ControlModifier,
Qt::ShiftModifier}; Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
const auto sources = {Qt::MouseEventNotSynthesized, const auto sources = {Qt::MouseEventNotSynthesized,
Qt::MouseEventSynthesizedBySystem, Qt::MouseEventSynthesizedBySystem,
@ -1371,62 +1404,71 @@ void tst_QDoubleSpinBox::wheelEvents_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
for (auto source : sources) { const auto stepModifierName = modifierToName(stepModifier);
if (stepModifierName.isEmpty())
continue;
const int steps = (modifier & stepModifier ? 10 : 1)
* (up ? 1 : -1);
for (auto source : sources) {
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
QPoint angleDelta; QPoint angleDelta;
if ((modifier & Qt::ShiftModifier) && if ((modifier & Qt::ShiftModifier) &&
source == Qt::MouseEventNotSynthesized) { source == Qt::MouseEventNotSynthesized) {
// On macOS the Shift modifier converts vertical // On macOS the Shift modifier converts vertical
// mouse wheel events to horizontal. // mouse wheel events to horizontal.
angleDelta = { units, 0 }; angleDelta = { units, 0 };
} else { } else {
// However, this is not the case for trackpad scroll // However, this is not the case for trackpad scroll
// events. // events.
angleDelta = { 0, units }; angleDelta = { 0, units };
} }
#else #else
const QPoint angleDelta(0, units); const QPoint angleDelta(0, units);
#endif #endif
QLatin1String sourceName; QLatin1String sourceName;
switch (source) { switch (source) {
case Qt::MouseEventNotSynthesized: case Qt::MouseEventNotSynthesized:
sourceName = QLatin1Literal("NotSynthesized"); sourceName = QLatin1Literal("NotSynthesized");
break; break;
case Qt::MouseEventSynthesizedBySystem: case Qt::MouseEventSynthesizedBySystem:
sourceName = QLatin1Literal("SynthesizedBySystem"); sourceName = QLatin1Literal("SynthesizedBySystem");
break; break;
case Qt::MouseEventSynthesizedByQt: case Qt::MouseEventSynthesizedByQt:
sourceName = QLatin1Literal("SynthesizedByQt"); sourceName = QLatin1Literal("SynthesizedByQt");
break; break;
case Qt::MouseEventSynthesizedByApplication: case Qt::MouseEventSynthesizedByApplication:
sourceName = QLatin1Literal("SynthesizedByApplication"); sourceName = QLatin1Literal("SynthesizedByApplication");
break; break;
default: default:
qFatal("Unexpected wheel event source"); qFatal("Unexpected wheel event source");
continue; continue;
}
DoubleList expectedValues;
if (fraction)
expectedValues << startValue;
expectedValues << startValue + steps;
QTest::addRow("%s%s%sWith%sKeyboardModifier%s",
fraction ? "half" : "full",
up ? "Up" : "Down",
stepModifierName.latin1(),
modifierName.latin1(),
sourceName.latin1())
<< angleDelta
<< units
<< static_cast<int>(stepModifier)
<< modifiers
<< source
<< startValue
<< expectedValues;
} }
DoubleList expectedValues;
if (fraction)
expectedValues << startValue;
expectedValues << startValue + steps;
QTest::addRow("%s%sWith%sKeyboardModifier%s",
fraction ? "half" : "full",
up ? "Up" : "Down",
modifierName.latin1(),
sourceName.latin1())
<< angleDelta
<< units
<< modifiers
<< source
<< startValue
<< expectedValues;
} }
} }
} }
@ -1441,6 +1483,7 @@ void tst_QDoubleSpinBox::wheelEvents()
#if QT_CONFIG(wheelevent) #if QT_CONFIG(wheelevent)
QFETCH(QPoint, angleDelta); QFETCH(QPoint, angleDelta);
QFETCH(int, qt4Delta); QFETCH(int, qt4Delta);
QFETCH(int, stepModifier);
QFETCH(Qt::KeyboardModifiers, modifier); QFETCH(Qt::KeyboardModifiers, modifier);
QFETCH(Qt::MouseEventSource, source); QFETCH(Qt::MouseEventSource, source);
QFETCH(double, start); QFETCH(double, start);
@ -1450,6 +1493,11 @@ void tst_QDoubleSpinBox::wheelEvents()
spinBox.setRange(-20, 20); spinBox.setRange(-20, 20);
spinBox.setValue(start); spinBox.setValue(start);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style(
new StepModifierStyle);
style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
spinBox.setStyle(style.data());
QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, qt4Delta, QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, qt4Delta,
Qt::Vertical, Qt::NoButton, modifier, Qt::NoScrollPhase, Qt::Vertical, Qt::NoButton, modifier, Qt::NoScrollPhase,
source); source);
@ -1465,14 +1513,22 @@ void tst_QDoubleSpinBox::wheelEvents()
void tst_QDoubleSpinBox::stepModifierKeys_data() void tst_QDoubleSpinBox::stepModifierKeys_data()
{ {
QTest::addColumn<double>("startValue"); QTest::addColumn<double>("startValue");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<QTestEventList>("keys"); QTest::addColumn<QTestEventList>("keys");
QTest::addColumn<double>("expectedValue"); QTest::addColumn<double>("expectedValue");
const auto keyList = {Qt::Key_Up, Qt::Key_Down}; const auto keyList = {Qt::Key_Up, Qt::Key_Down};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ShiftModifier,
Qt::ControlModifier, Qt::ControlModifier,
Qt::ShiftModifier}; Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
for (auto key : keyList) { for (auto key : keyList) {
@ -1490,17 +1546,26 @@ void tst_QDoubleSpinBox::stepModifierKeys_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
const double expectedValue = startValue + steps; const auto stepModifierName = modifierToName(stepModifier);
if (stepModifierName.isEmpty())
continue;
QTest::addRow("%sWith%sKeyboardModifier", const int steps = (modifier & stepModifier ? 10 : 1)
up ? "up" : "down", * (up ? 1 : -1);
modifierName.latin1())
<< startValue const double expectedValue = startValue + steps;
<< keys
<< expectedValue; QTest::addRow("%s%sWith%sKeyboardModifier",
up ? "up" : "down",
stepModifierName.latin1(),
modifierName.latin1())
<< startValue
<< static_cast<int>(stepModifier)
<< keys
<< expectedValue;
}
} }
} }
} }
@ -1508,11 +1573,18 @@ void tst_QDoubleSpinBox::stepModifierKeys_data()
void tst_QDoubleSpinBox::stepModifierKeys() void tst_QDoubleSpinBox::stepModifierKeys()
{ {
QFETCH(double, startValue); QFETCH(double, startValue);
QFETCH(int, stepModifier);
QFETCH(QTestEventList, keys); QFETCH(QTestEventList, keys);
QFETCH(double, expectedValue); QFETCH(double, expectedValue);
QDoubleSpinBox spin(0); QDoubleSpinBox spin(0);
spin.setValue(startValue); spin.setValue(startValue);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style(
new StepModifierStyle);
style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
spin.setStyle(style.data());
spin.show(); spin.show();
QVERIFY(QTest::qWaitForWindowActive(&spin)); QVERIFY(QTest::qWaitForWindowActive(&spin));
@ -1524,6 +1596,7 @@ void tst_QDoubleSpinBox::stepModifierKeys()
void tst_QDoubleSpinBox::stepModifierButtons_data() void tst_QDoubleSpinBox::stepModifierButtons_data()
{ {
QTest::addColumn<QStyle::SubControl>("subControl"); QTest::addColumn<QStyle::SubControl>("subControl");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); QTest::addColumn<Qt::KeyboardModifiers>("modifiers");
QTest::addColumn<double>("startValue"); QTest::addColumn<double>("startValue");
QTest::addColumn<double>("expectedValue"); QTest::addColumn<double>("expectedValue");
@ -1531,8 +1604,14 @@ void tst_QDoubleSpinBox::stepModifierButtons_data()
const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown}; const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ControlModifier, Qt::ShiftModifier,
Qt::ShiftModifier}; Qt::ControlModifier,
Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
for (auto subControl : subControls) { for (auto subControl : subControls) {
@ -1549,18 +1628,27 @@ void tst_QDoubleSpinBox::stepModifierButtons_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
const double expectedValue = startValue + steps; const auto stepModifierName = modifierToName(stepModifier);
if (stepModifierName.isEmpty())
continue;
QTest::addRow("%sWith%sKeyboardModifier", const int steps = (modifier & stepModifier ? 10 : 1)
up ? "up" : "down", * (up ? 1 : -1);
modifierName.latin1())
<< subControl const double expectedValue = startValue + steps;
<< modifiers
<< startValue QTest::addRow("%s%sWith%sKeyboardModifier",
<< expectedValue; up ? "up" : "down",
stepModifierName.latin1(),
modifierName.latin1())
<< subControl
<< static_cast<int>(stepModifier)
<< modifiers
<< startValue
<< expectedValue;
}
} }
} }
} }
@ -1568,6 +1656,7 @@ void tst_QDoubleSpinBox::stepModifierButtons_data()
void tst_QDoubleSpinBox::stepModifierButtons() void tst_QDoubleSpinBox::stepModifierButtons()
{ {
QFETCH(QStyle::SubControl, subControl); QFETCH(QStyle::SubControl, subControl);
QFETCH(int, stepModifier);
QFETCH(Qt::KeyboardModifiers, modifiers); QFETCH(Qt::KeyboardModifiers, modifiers);
QFETCH(double, startValue); QFETCH(double, startValue);
QFETCH(double, expectedValue); QFETCH(double, expectedValue);
@ -1575,6 +1664,12 @@ void tst_QDoubleSpinBox::stepModifierButtons()
DoubleSpinBox spin(0); DoubleSpinBox spin(0);
spin.setRange(-20, 20); spin.setRange(-20, 20);
spin.setValue(startValue); spin.setValue(startValue);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style(
new StepModifierStyle);
style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
spin.setStyle(style.data());
spin.show(); spin.show();
QVERIFY(QTest::qWaitForWindowActive(&spin)); QVERIFY(QTest::qWaitForWindowActive(&spin));
@ -1592,14 +1687,21 @@ void tst_QDoubleSpinBox::stepModifierButtons()
void tst_QDoubleSpinBox::stepModifierPressAndHold_data() void tst_QDoubleSpinBox::stepModifierPressAndHold_data()
{ {
QTest::addColumn<QStyle::SubControl>("subControl"); QTest::addColumn<QStyle::SubControl>("subControl");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); QTest::addColumn<Qt::KeyboardModifiers>("modifiers");
QTest::addColumn<int>("expectedStepModifier"); QTest::addColumn<int>("expectedStepModifier");
const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown}; const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ShiftModifier,
Qt::ControlModifier, Qt::ControlModifier,
Qt::ShiftModifier}; Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
for (auto subControl : subControls) { for (auto subControl : subControls) {
@ -1614,15 +1716,24 @@ void tst_QDoubleSpinBox::stepModifierPressAndHold_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
QTest::addRow("%sWith%sKeyboardModifier", const auto stepModifierName = modifierToName(stepModifier);
up ? "up" : "down", if (stepModifierName.isEmpty())
modifierName.latin1()) continue;
<< subControl
<< modifiers const int steps = (modifier & stepModifier ? 10 : 1)
<< steps; * (up ? 1 : -1);
QTest::addRow("%s%sWith%sKeyboardModifier",
up ? "up" : "down",
stepModifierName.latin1(),
modifierName.latin1())
<< subControl
<< static_cast<int>(stepModifier)
<< modifiers
<< steps;
}
} }
} }
} }
@ -1630,16 +1741,19 @@ void tst_QDoubleSpinBox::stepModifierPressAndHold_data()
void tst_QDoubleSpinBox::stepModifierPressAndHold() void tst_QDoubleSpinBox::stepModifierPressAndHold()
{ {
QFETCH(QStyle::SubControl, subControl); QFETCH(QStyle::SubControl, subControl);
QFETCH(int, stepModifier);
QFETCH(Qt::KeyboardModifiers, modifiers); QFETCH(Qt::KeyboardModifiers, modifiers);
QFETCH(int, expectedStepModifier); QFETCH(int, expectedStepModifier);
DoubleSpinBox spin(0); DoubleSpinBox spin(0);
QScopedPointer<PressAndHoldStyle, QScopedPointerDeleteLater> pressAndHoldStyle(
new PressAndHoldStyle);
spin.setStyle(pressAndHoldStyle.data());
spin.setRange(-100.0, 100.0); spin.setRange(-100.0, 100.0);
spin.setValue(0.0); spin.setValue(0.0);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> stepModifierStyle(
new StepModifierStyle(new PressAndHoldStyle));
stepModifierStyle->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
spin.setStyle(stepModifierStyle.data());
QSignalSpy spy(&spin, QOverload<double>::of(&DoubleSpinBox::valueChanged)); QSignalSpy spy(&spin, QOverload<double>::of(&DoubleSpinBox::valueChanged));
spin.show(); spin.show();

View File

@ -106,6 +106,26 @@ public:
} }
}; };
class StepModifierStyle : public QProxyStyle
{
Q_OBJECT
public:
using QProxyStyle::QProxyStyle;
int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr,
const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override
{
switch (hint) {
case QStyle::SH_SpinBox_StepModifier:
return stepModifier;
default:
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
}
Qt::KeyboardModifier stepModifier = Qt::ControlModifier;
};
class tst_QSpinBox : public QObject class tst_QSpinBox : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -208,6 +228,12 @@ static QLatin1String modifierToName(Qt::KeyboardModifier modifier)
case Qt::ShiftModifier: case Qt::ShiftModifier:
return QLatin1Literal("Shift"); return QLatin1Literal("Shift");
break; break;
case Qt::AltModifier:
return QLatin1Literal("Alt");
break;
case Qt::MetaModifier:
return QLatin1Literal("Meta");
break;
default: default:
qFatal("Unexpected keyboard modifier"); qFatal("Unexpected keyboard modifier");
return QLatin1String(); return QLatin1String();
@ -1280,6 +1306,7 @@ void tst_QSpinBox::wheelEvents_data()
#if QT_CONFIG(wheelevent) #if QT_CONFIG(wheelevent)
QTest::addColumn<QPoint>("angleDelta"); QTest::addColumn<QPoint>("angleDelta");
QTest::addColumn<int>("qt4Delta"); QTest::addColumn<int>("qt4Delta");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<Qt::KeyboardModifiers>("modifier"); QTest::addColumn<Qt::KeyboardModifiers>("modifier");
QTest::addColumn<Qt::MouseEventSource>("source"); QTest::addColumn<Qt::MouseEventSource>("source");
QTest::addColumn<int>("start"); QTest::addColumn<int>("start");
@ -1290,8 +1317,14 @@ void tst_QSpinBox::wheelEvents_data()
const auto directions = {true, false}; const auto directions = {true, false};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ShiftModifier,
Qt::ControlModifier, Qt::ControlModifier,
Qt::ShiftModifier}; Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
const auto sources = {Qt::MouseEventNotSynthesized, const auto sources = {Qt::MouseEventNotSynthesized,
Qt::MouseEventSynthesizedBySystem, Qt::MouseEventSynthesizedBySystem,
@ -1313,62 +1346,71 @@ void tst_QSpinBox::wheelEvents_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
for (auto source : sources) { const auto stepModifierName = modifierToName(stepModifier);
if (stepModifierName.isEmpty())
continue;
const int steps = (modifier & stepModifier ? 10 : 1)
* (up ? 1 : -1);
for (auto source : sources) {
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
QPoint angleDelta; QPoint angleDelta;
if ((modifier & Qt::ShiftModifier) && if ((modifier & Qt::ShiftModifier) &&
source == Qt::MouseEventNotSynthesized) { source == Qt::MouseEventNotSynthesized) {
// On macOS the Shift modifier converts vertical // On macOS the Shift modifier converts vertical
// mouse wheel events to horizontal. // mouse wheel events to horizontal.
angleDelta = { units, 0 }; angleDelta = { units, 0 };
} else { } else {
// However, this is not the case for trackpad scroll // However, this is not the case for trackpad scroll
// events. // events.
angleDelta = { 0, units }; angleDelta = { 0, units };
} }
#else #else
const QPoint angleDelta(0, units); const QPoint angleDelta(0, units);
#endif #endif
QLatin1String sourceName; QLatin1String sourceName;
switch (source) { switch (source) {
case Qt::MouseEventNotSynthesized: case Qt::MouseEventNotSynthesized:
sourceName = QLatin1Literal("NotSynthesized"); sourceName = QLatin1Literal("NotSynthesized");
break; break;
case Qt::MouseEventSynthesizedBySystem: case Qt::MouseEventSynthesizedBySystem:
sourceName = QLatin1Literal("SynthesizedBySystem"); sourceName = QLatin1Literal("SynthesizedBySystem");
break; break;
case Qt::MouseEventSynthesizedByQt: case Qt::MouseEventSynthesizedByQt:
sourceName = QLatin1Literal("SynthesizedByQt"); sourceName = QLatin1Literal("SynthesizedByQt");
break; break;
case Qt::MouseEventSynthesizedByApplication: case Qt::MouseEventSynthesizedByApplication:
sourceName = QLatin1Literal("SynthesizedByApplication"); sourceName = QLatin1Literal("SynthesizedByApplication");
break; break;
default: default:
qFatal("Unexpected wheel event source"); qFatal("Unexpected wheel event source");
continue; continue;
}
IntList expectedValues;
if (fraction)
expectedValues << startValue;
expectedValues << startValue + steps;
QTest::addRow("%s%s%sWith%sKeyboardModifier%s",
fraction ? "half" : "full",
up ? "Up" : "Down",
stepModifierName.latin1(),
modifierName.latin1(),
sourceName.latin1())
<< angleDelta
<< units
<< static_cast<int>(stepModifier)
<< modifiers
<< source
<< startValue
<< expectedValues;
} }
IntList expectedValues;
if (fraction)
expectedValues << startValue;
expectedValues << startValue + steps;
QTest::addRow("%s%sWith%sKeyboardModifier%s",
fraction ? "half" : "full",
up ? "Up" : "Down",
modifierName.latin1(),
sourceName.latin1())
<< angleDelta
<< units
<< modifiers
<< source
<< startValue
<< expectedValues;
} }
} }
} }
@ -1383,6 +1425,7 @@ void tst_QSpinBox::wheelEvents()
#if QT_CONFIG(wheelevent) #if QT_CONFIG(wheelevent)
QFETCH(QPoint, angleDelta); QFETCH(QPoint, angleDelta);
QFETCH(int, qt4Delta); QFETCH(int, qt4Delta);
QFETCH(int, stepModifier);
QFETCH(Qt::KeyboardModifiers, modifier); QFETCH(Qt::KeyboardModifiers, modifier);
QFETCH(Qt::MouseEventSource, source); QFETCH(Qt::MouseEventSource, source);
QFETCH(int, start); QFETCH(int, start);
@ -1392,6 +1435,11 @@ void tst_QSpinBox::wheelEvents()
spinBox.setRange(-20, 20); spinBox.setRange(-20, 20);
spinBox.setValue(start); spinBox.setValue(start);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style(
new StepModifierStyle);
style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
spinBox.setStyle(style.data());
QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, qt4Delta, QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, qt4Delta,
Qt::Vertical, Qt::NoButton, modifier, Qt::NoScrollPhase, Qt::Vertical, Qt::NoButton, modifier, Qt::NoScrollPhase,
source); source);
@ -1486,14 +1534,21 @@ void tst_QSpinBox::adaptiveDecimalStep()
void tst_QSpinBox::stepModifierKeys_data() void tst_QSpinBox::stepModifierKeys_data()
{ {
QTest::addColumn<int>("startValue"); QTest::addColumn<int>("startValue");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<QTestEventList>("keys"); QTest::addColumn<QTestEventList>("keys");
QTest::addColumn<int>("expectedValue"); QTest::addColumn<int>("expectedValue");
const auto keyList = {Qt::Key_Up, Qt::Key_Down}; const auto keyList = {Qt::Key_Up, Qt::Key_Down};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ShiftModifier,
Qt::ControlModifier, Qt::ControlModifier,
Qt::ShiftModifier}; Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
for (auto key : keyList) { for (auto key : keyList) {
@ -1511,17 +1566,26 @@ void tst_QSpinBox::stepModifierKeys_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
const int expectedValue = startValue + steps; const auto stepModifierName = modifierToName(stepModifier);
if (stepModifierName.isEmpty())
continue;
QTest::addRow("%sWith%sKeyboardModifier", const int steps = (modifier & stepModifier ? 10 : 1)
up ? "up" : "down", * (up ? 1 : -1);
modifierName.latin1())
<< startValue const int expectedValue = startValue + steps;
<< keys
<< expectedValue; QTest::addRow("%s%sWith%sKeyboardModifier",
up ? "up" : "down",
stepModifierName.latin1(),
modifierName.latin1())
<< startValue
<< static_cast<int>(stepModifier)
<< keys
<< expectedValue;
}
} }
} }
} }
@ -1529,11 +1593,18 @@ void tst_QSpinBox::stepModifierKeys_data()
void tst_QSpinBox::stepModifierKeys() void tst_QSpinBox::stepModifierKeys()
{ {
QFETCH(int, startValue); QFETCH(int, startValue);
QFETCH(int, stepModifier);
QFETCH(QTestEventList, keys); QFETCH(QTestEventList, keys);
QFETCH(int, expectedValue); QFETCH(int, expectedValue);
QSpinBox spin(0); QSpinBox spin(0);
spin.setValue(startValue); spin.setValue(startValue);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style(
new StepModifierStyle);
style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
spin.setStyle(style.data());
spin.show(); spin.show();
QVERIFY(QTest::qWaitForWindowActive(&spin)); QVERIFY(QTest::qWaitForWindowActive(&spin));
@ -1545,6 +1616,7 @@ void tst_QSpinBox::stepModifierKeys()
void tst_QSpinBox::stepModifierButtons_data() void tst_QSpinBox::stepModifierButtons_data()
{ {
QTest::addColumn<QStyle::SubControl>("subControl"); QTest::addColumn<QStyle::SubControl>("subControl");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); QTest::addColumn<Qt::KeyboardModifiers>("modifiers");
QTest::addColumn<int>("startValue"); QTest::addColumn<int>("startValue");
QTest::addColumn<int>("expectedValue"); QTest::addColumn<int>("expectedValue");
@ -1552,8 +1624,14 @@ void tst_QSpinBox::stepModifierButtons_data()
const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown}; const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ShiftModifier,
Qt::ControlModifier, Qt::ControlModifier,
Qt::ShiftModifier}; Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
for (auto subControl : subControls) { for (auto subControl : subControls) {
@ -1570,18 +1648,27 @@ void tst_QSpinBox::stepModifierButtons_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
const int expectedValue = startValue + steps; const auto stepModifierName = modifierToName(stepModifier);
if (stepModifierName.isEmpty())
continue;
QTest::addRow("%sWith%sKeyboardModifier", const int steps = (modifier & stepModifier ? 10 : 1)
up ? "up" : "down", * (up ? 1 : -1);
modifierName.latin1())
<< subControl const int expectedValue = startValue + steps;
<< modifiers
<< startValue QTest::addRow("%s%sWith%sKeyboardModifier",
<< expectedValue; up ? "up" : "down",
stepModifierName.latin1(),
modifierName.latin1())
<< subControl
<< static_cast<int>(stepModifier)
<< modifiers
<< startValue
<< expectedValue;
}
} }
} }
} }
@ -1589,6 +1676,7 @@ void tst_QSpinBox::stepModifierButtons_data()
void tst_QSpinBox::stepModifierButtons() void tst_QSpinBox::stepModifierButtons()
{ {
QFETCH(QStyle::SubControl, subControl); QFETCH(QStyle::SubControl, subControl);
QFETCH(int, stepModifier);
QFETCH(Qt::KeyboardModifiers, modifiers); QFETCH(Qt::KeyboardModifiers, modifiers);
QFETCH(int, startValue); QFETCH(int, startValue);
QFETCH(int, expectedValue); QFETCH(int, expectedValue);
@ -1596,6 +1684,12 @@ void tst_QSpinBox::stepModifierButtons()
SpinBox spin(0); SpinBox spin(0);
spin.setRange(-20, 20); spin.setRange(-20, 20);
spin.setValue(startValue); spin.setValue(startValue);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style(
new StepModifierStyle);
style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
spin.setStyle(style.data());
spin.show(); spin.show();
QVERIFY(QTest::qWaitForWindowActive(&spin)); QVERIFY(QTest::qWaitForWindowActive(&spin));
@ -1613,14 +1707,21 @@ void tst_QSpinBox::stepModifierButtons()
void tst_QSpinBox::stepModifierPressAndHold_data() void tst_QSpinBox::stepModifierPressAndHold_data()
{ {
QTest::addColumn<QStyle::SubControl>("subControl"); QTest::addColumn<QStyle::SubControl>("subControl");
QTest::addColumn<int>("stepModifier");
QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); QTest::addColumn<Qt::KeyboardModifiers>("modifiers");
QTest::addColumn<int>("expectedStepModifier"); QTest::addColumn<int>("expectedStepModifier");
const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown}; const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown};
const auto modifierList = {Qt::NoModifier, const auto modifierList = {Qt::NoModifier,
Qt::ShiftModifier,
Qt::ControlModifier, Qt::ControlModifier,
Qt::ShiftModifier}; Qt::AltModifier,
Qt::MetaModifier};
const auto validStepModifierList = {Qt::NoModifier,
Qt::ControlModifier,
Qt::ShiftModifier};
for (auto subControl : subControls) { for (auto subControl : subControls) {
@ -1635,15 +1736,24 @@ void tst_QSpinBox::stepModifierPressAndHold_data()
if (modifierName.isEmpty()) if (modifierName.isEmpty())
continue; continue;
const int steps = (modifier & Qt::ControlModifier ? 10 : 1) for (auto stepModifier : validStepModifierList) {
* (up ? 1 : -1);
QTest::addRow("%sWith%sKeyboardModifier", const auto stepModifierName = modifierToName(stepModifier);
up ? "up" : "down", if (stepModifierName.isEmpty())
modifierName.latin1()) continue;
<< subControl
<< modifiers const int steps = (modifier & stepModifier ? 10 : 1)
<< steps; * (up ? 1 : -1);
QTest::addRow("%s%sWith%sKeyboardModifier",
up ? "up" : "down",
stepModifierName.latin1(),
modifierName.latin1())
<< subControl
<< static_cast<int>(stepModifier)
<< modifiers
<< steps;
}
} }
} }
} }
@ -1651,16 +1761,19 @@ void tst_QSpinBox::stepModifierPressAndHold_data()
void tst_QSpinBox::stepModifierPressAndHold() void tst_QSpinBox::stepModifierPressAndHold()
{ {
QFETCH(QStyle::SubControl, subControl); QFETCH(QStyle::SubControl, subControl);
QFETCH(int, stepModifier);
QFETCH(Qt::KeyboardModifiers, modifiers); QFETCH(Qt::KeyboardModifiers, modifiers);
QFETCH(int, expectedStepModifier); QFETCH(int, expectedStepModifier);
SpinBox spin(0); SpinBox spin(0);
QScopedPointer<PressAndHoldStyle, QScopedPointerDeleteLater> pressAndHoldStyle(
new PressAndHoldStyle);
spin.setStyle(pressAndHoldStyle.data());
spin.setRange(-100, 100); spin.setRange(-100, 100);
spin.setValue(0); spin.setValue(0);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> stepModifierStyle(
new StepModifierStyle(new PressAndHoldStyle));
stepModifierStyle->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier);
spin.setStyle(stepModifierStyle.data());
QSignalSpy spy(&spin, QOverload<int>::of(&SpinBox::valueChanged)); QSignalSpy spy(&spin, QOverload<int>::of(&SpinBox::valueChanged));
spin.show(); spin.show();