Add way to override when to show context menu
Add Qt::ContextMenuTrigger enum used with QStyleHints::setContextMenuTrigger() to override default platform behavior when to trigger context menu event. The default is to show context menu on mouse press on UNIX systems and on mouse release on Windows. Give developer a possibility to override platform default behavior to make cross platform application that behaves the same way on all platforms Task-number: QTBUG-93486 Change-Id: Ic832d3d8a7c355a8adb46868fff9cfd19988cf3c Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
3d59a0f7c7
commit
4585cacaa9
@ -1356,6 +1356,11 @@ namespace Qt {
|
||||
PreventContextMenu
|
||||
};
|
||||
|
||||
enum class ContextMenuTrigger {
|
||||
Press,
|
||||
Release,
|
||||
};
|
||||
|
||||
enum InputMethodQuery {
|
||||
ImEnabled = 0x1,
|
||||
ImCursorRectangle = 0x2,
|
||||
@ -1731,6 +1736,7 @@ namespace Qt {
|
||||
Q_ENUM_NS(ScrollBarPolicy)
|
||||
Q_ENUM_NS(FocusPolicy)
|
||||
Q_ENUM_NS(ContextMenuPolicy)
|
||||
Q_ENUM_NS(ContextMenuTrigger)
|
||||
Q_ENUM_NS(ArrowType)
|
||||
Q_ENUM_NS(ToolButtonStyle)
|
||||
Q_ENUM_NS(PenStyle)
|
||||
|
@ -2086,6 +2086,18 @@
|
||||
\value CustomContextMenu the widget emits the QWidget::customContextMenuRequested() signal.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum Qt::ContextMenuTrigger
|
||||
\since 6.8
|
||||
|
||||
This enum type defines the mouse event used to trigger a context menu event.
|
||||
|
||||
\value Press context menu on mouse press event, default on UNIX systems.
|
||||
\value Release context menu on mouse release event, default on Windows.
|
||||
|
||||
\sa QStyleHints::contextMenuTrigger
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum Qt::FocusPolicy
|
||||
|
||||
|
@ -3447,6 +3447,15 @@ void QGuiApplicationPrivate::updatePalette()
|
||||
}
|
||||
}
|
||||
|
||||
QEvent::Type QGuiApplicationPrivate::contextMenuEventType()
|
||||
{
|
||||
switch (QGuiApplication::styleHints()->contextMenuTrigger()) {
|
||||
case Qt::ContextMenuTrigger::Press: return QEvent::MouseButtonPress;
|
||||
case Qt::ContextMenuTrigger::Release: return QEvent::MouseButtonRelease;
|
||||
}
|
||||
return QEvent::None;
|
||||
}
|
||||
|
||||
void QGuiApplicationPrivate::clearPalette()
|
||||
{
|
||||
delete app_pal;
|
||||
|
@ -323,6 +323,8 @@ public:
|
||||
|
||||
static void updatePalette();
|
||||
|
||||
static QEvent::Type contextMenuEventType();
|
||||
|
||||
protected:
|
||||
virtual void handleThemeChanged();
|
||||
|
||||
|
@ -442,6 +442,40 @@ void QStyleHints::setShowShortcutsInContextMenus(bool s)
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QStyleHints::contextMenuTrigger
|
||||
\since 6.8
|
||||
\brief mouse event used to trigger a context menu event.
|
||||
|
||||
The default on UNIX systems is to show context menu on mouse button press event, while on
|
||||
Windows it is the mouse button release event. This property can be used to override the default
|
||||
platform behavior.
|
||||
|
||||
\note Developers must use this property with great care, as it changes the default interaction
|
||||
mode that their users will expect on the platform that they are running on.
|
||||
|
||||
\sa Qt::ContextMenuTrigger
|
||||
*/
|
||||
Qt::ContextMenuTrigger QStyleHints::contextMenuTrigger() const
|
||||
{
|
||||
Q_D(const QStyleHints);
|
||||
if (d->m_contextMenuTrigger == -1) {
|
||||
return themeableHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool()
|
||||
? Qt::ContextMenuTrigger::Release
|
||||
: Qt::ContextMenuTrigger::Press;
|
||||
}
|
||||
return Qt::ContextMenuTrigger(d->m_contextMenuTrigger);
|
||||
}
|
||||
|
||||
void QStyleHints::setContextMenuTrigger(Qt::ContextMenuTrigger contextMenuTrigger)
|
||||
{
|
||||
Q_D(QStyleHints);
|
||||
const Qt::ContextMenuTrigger currentTrigger = this->contextMenuTrigger();
|
||||
d->m_contextMenuTrigger = int(contextMenuTrigger);
|
||||
if (currentTrigger != contextMenuTrigger)
|
||||
emit contextMenuTriggerChanged(contextMenuTrigger);
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QStyleHints::passwordMaskDelay
|
||||
\brief the time, in milliseconds, a typed letter is displayed unshrouded
|
||||
|
@ -36,6 +36,8 @@ class Q_GUI_EXPORT QStyleHints : public QObject
|
||||
Q_PROPERTY(bool showIsMaximized READ showIsMaximized STORED false CONSTANT FINAL)
|
||||
Q_PROPERTY(bool showShortcutsInContextMenus READ showShortcutsInContextMenus
|
||||
WRITE setShowShortcutsInContextMenus NOTIFY showShortcutsInContextMenusChanged FINAL)
|
||||
Q_PROPERTY(Qt::ContextMenuTrigger contextMenuTrigger READ contextMenuTrigger WRITE
|
||||
setContextMenuTrigger NOTIFY contextMenuTriggerChanged FINAL)
|
||||
Q_PROPERTY(int startDragDistance READ startDragDistance NOTIFY startDragDistanceChanged FINAL)
|
||||
Q_PROPERTY(int startDragTime READ startDragTime NOTIFY startDragTimeChanged FINAL)
|
||||
Q_PROPERTY(int startDragVelocity READ startDragVelocity STORED false CONSTANT FINAL)
|
||||
@ -80,6 +82,8 @@ public:
|
||||
bool showIsMaximized() const;
|
||||
bool showShortcutsInContextMenus() const;
|
||||
void setShowShortcutsInContextMenus(bool showShortcutsInContextMenus);
|
||||
Qt::ContextMenuTrigger contextMenuTrigger() const;
|
||||
void setContextMenuTrigger(Qt::ContextMenuTrigger contextMenuTrigger);
|
||||
int passwordMaskDelay() const;
|
||||
QChar passwordMaskCharacter() const;
|
||||
qreal fontSmoothingGamma() const;
|
||||
@ -108,6 +112,7 @@ Q_SIGNALS:
|
||||
void tabFocusBehaviorChanged(Qt::TabFocusBehavior tabFocusBehavior);
|
||||
void useHoverEffectsChanged(bool useHoverEffects);
|
||||
void showShortcutsInContextMenusChanged(bool);
|
||||
void contextMenuTriggerChanged(Qt::ContextMenuTrigger contextMenuTrigger);
|
||||
void wheelScrollLinesChanged(int scrollLines);
|
||||
void mouseQuickSelectionThresholdChanged(int threshold);
|
||||
void colorSchemeChanged(Qt::ColorScheme colorScheme);
|
||||
|
@ -35,6 +35,7 @@ public:
|
||||
int m_tabFocusBehavior = -1;
|
||||
int m_uiEffects = -1;
|
||||
int m_showShortcutsInContextMenus = -1;
|
||||
int m_contextMenuTrigger = -1;
|
||||
int m_wheelScrollLines = -1;
|
||||
int m_mouseQuickSelectionThreshold = -1;
|
||||
int m_mouseDoubleClickDistance = -1;
|
||||
|
@ -2654,16 +2654,14 @@ bool QWindow::event(QEvent *ev)
|
||||
This logic could be simplified by always synthesizing events in
|
||||
QGuiApplicationPrivate, or perhaps even in each QPA plugin. See QTBUG-93486.
|
||||
*/
|
||||
static const QEvent::Type contextMenuTrigger =
|
||||
QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ?
|
||||
QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
|
||||
auto asMouseEvent = [](QEvent *ev) {
|
||||
const auto t = ev->type();
|
||||
return t == QEvent::MouseButtonPress || t == QEvent::MouseButtonRelease
|
||||
? static_cast<QMouseEvent *>(ev) : nullptr ;
|
||||
};
|
||||
if (QMouseEvent *me = asMouseEvent(ev); me &&
|
||||
ev->type() == contextMenuTrigger && me->button() == Qt::RightButton) {
|
||||
if (QMouseEvent *me = asMouseEvent(ev);
|
||||
me && ev->type() == QGuiApplicationPrivate::contextMenuEventType()
|
||||
&& me->button() == Qt::RightButton) {
|
||||
QContextMenuEvent e(QContextMenuEvent::Mouse, me->position().toPoint(),
|
||||
me->globalPosition().toPoint(), me->modifiers());
|
||||
QGuiApplication::sendEvent(this, &e);
|
||||
|
@ -505,9 +505,6 @@ void QWidgetWindow::handleNonClientAreaMouseEvent(QMouseEvent *e)
|
||||
|
||||
void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
|
||||
{
|
||||
static const QEvent::Type contextMenuTrigger =
|
||||
QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ?
|
||||
QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
|
||||
if (QApplicationPrivate::inPopupMode()) {
|
||||
QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget();
|
||||
QPointF mapped = event->position();
|
||||
@ -624,7 +621,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
|
||||
}
|
||||
qt_replay_popup_mouse_event = false;
|
||||
#ifndef QT_NO_CONTEXTMENU
|
||||
} else if (event->type() == contextMenuTrigger
|
||||
} else if (event->type() == QGuiApplicationPrivate::contextMenuEventType()
|
||||
&& event->button() == Qt::RightButton
|
||||
&& (openPopupCount == oldOpenPopupCount)) {
|
||||
QWidget *receiver = activePopupWidget;
|
||||
@ -637,7 +634,6 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
|
||||
QApplication::forwardEvent(receiver, &e, event);
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(contextMenuTrigger);
|
||||
Q_UNUSED(oldOpenPopupCount);
|
||||
}
|
||||
#endif
|
||||
@ -684,7 +680,8 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
|
||||
event->setAccepted(translated.isAccepted());
|
||||
}
|
||||
#ifndef QT_NO_CONTEXTMENU
|
||||
if (event->type() == contextMenuTrigger && event->button() == Qt::RightButton
|
||||
if (event->type() == QGuiApplicationPrivate::contextMenuEventType()
|
||||
&& event->button() == Qt::RightButton
|
||||
&& m_widget->rect().contains(event->position().toPoint())) {
|
||||
QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPosition().toPoint(), event->modifiers());
|
||||
QGuiApplication::forwardEvent(receiver, &e, event);
|
||||
|
@ -477,6 +477,10 @@ private slots:
|
||||
void reparentWindowHandles_data();
|
||||
void reparentWindowHandles();
|
||||
|
||||
#ifndef QT_NO_CONTEXTMENU
|
||||
void contextMenuTrigger();
|
||||
#endif
|
||||
|
||||
private:
|
||||
const QString m_platform;
|
||||
QSize m_testWidgetSize;
|
||||
@ -14040,5 +14044,41 @@ void tst_QWidget::reparentWindowHandles()
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef QT_NO_CONTEXTMENU
|
||||
void tst_QWidget::contextMenuTrigger()
|
||||
{
|
||||
class ContextMenuWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
int events = 0;
|
||||
|
||||
protected:
|
||||
void contextMenuEvent(QContextMenuEvent *) override { ++events; }
|
||||
};
|
||||
|
||||
const Qt::ContextMenuTrigger wasTrigger = QGuiApplication::styleHints()->contextMenuTrigger();
|
||||
auto restoreTriggerGuard = qScopeGuard([wasTrigger]{
|
||||
QGuiApplication::styleHints()->setContextMenuTrigger(wasTrigger);
|
||||
});
|
||||
|
||||
ContextMenuWidget widget;
|
||||
widget.show();
|
||||
QVERIFY(!qApp->topLevelWindows().empty());
|
||||
auto *window = qApp->topLevelWindows()[0];
|
||||
QVERIFY(window);
|
||||
QCOMPARE(widget.events, 0);
|
||||
QGuiApplication::styleHints()->setContextMenuTrigger(Qt::ContextMenuTrigger::Press);
|
||||
QTest::mousePress(window, Qt::RightButton);
|
||||
QCOMPARE(widget.events, 1);
|
||||
QTest::mouseRelease(window, Qt::RightButton);
|
||||
QCOMPARE(widget.events, 1);
|
||||
QGuiApplication::styleHints()->setContextMenuTrigger(Qt::ContextMenuTrigger::Release);
|
||||
QTest::mousePress(window, Qt::RightButton);
|
||||
QCOMPARE(widget.events, 1);
|
||||
QTest::mouseRelease(window, Qt::RightButton);
|
||||
QCOMPARE(widget.events, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
QTEST_MAIN(tst_QWidget)
|
||||
#include "tst_qwidget.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user