diff options
Diffstat (limited to 'src/widgets')
25 files changed, 184 insertions, 339 deletions
diff --git a/src/widgets/doc/images/designer-stylesheet-options.png b/src/widgets/doc/images/designer-stylesheet-options.png Binary files differdeleted file mode 100644 index a6893e770bc..00000000000 --- a/src/widgets/doc/images/designer-stylesheet-options.png +++ /dev/null diff --git a/src/widgets/doc/images/designer-stylesheet-options.webp b/src/widgets/doc/images/designer-stylesheet-options.webp Binary files differnew file mode 100644 index 00000000000..14d1ad368fc --- /dev/null +++ b/src/widgets/doc/images/designer-stylesheet-options.webp diff --git a/src/widgets/doc/images/designer-stylesheet-usage.png b/src/widgets/doc/images/designer-stylesheet-usage.png Binary files differdeleted file mode 100644 index f6875900def..00000000000 --- a/src/widgets/doc/images/designer-stylesheet-usage.png +++ /dev/null diff --git a/src/widgets/doc/images/designer-stylesheet-usage.webp b/src/widgets/doc/images/designer-stylesheet-usage.webp Binary files differnew file mode 100644 index 00000000000..79dd6803853 --- /dev/null +++ b/src/widgets/doc/images/designer-stylesheet-usage.webp diff --git a/src/widgets/doc/images/designer-validator-highlighter.png b/src/widgets/doc/images/designer-validator-highlighter.png Binary files differdeleted file mode 100644 index a6661d5c955..00000000000 --- a/src/widgets/doc/images/designer-validator-highlighter.png +++ /dev/null diff --git a/src/widgets/doc/images/designer-validator-highlighter.webp b/src/widgets/doc/images/designer-validator-highlighter.webp Binary files differnew file mode 100644 index 00000000000..7ca6cdf6eb3 --- /dev/null +++ b/src/widgets/doc/images/designer-validator-highlighter.webp diff --git a/src/widgets/doc/src/external-resources.qdoc b/src/widgets/doc/src/external-resources.qdoc index 17459b6a5bc..96117546a29 100644 --- a/src/widgets/doc/src/external-resources.qdoc +++ b/src/widgets/doc/src/external-resources.qdoc @@ -8,7 +8,7 @@ */ /*! - \externalpage http://www.nvg.ntnu.no/sinclair/computers/zxspectrum/zxspectrum.htm + \externalpage https://rk.nvg.ntnu.no/sinclair/computers/zxspectrum/zxspectrum.htm \title Sinclair Spectrum */ /*! diff --git a/src/widgets/doc/src/modelview.qdoc b/src/widgets/doc/src/modelview.qdoc index b2448a2c705..121cc30ed09 100644 --- a/src/widgets/doc/src/modelview.qdoc +++ b/src/widgets/doc/src/modelview.qdoc @@ -573,281 +573,10 @@ out of range when using ModelTest. - \section1 4. Good Sources of Additional Information - - \section2 4.1 Books - - Model/View programming is covered quite extensively in the documentation of - Qt but also in several good books. - - \list 1 - \li \b{C++ GUI Programming with Qt 4} / Jasmin Blanchette, Mark Summerfield, - \e{Prentice Hall, 2nd edition}, ISBN 0-13-235416-0. Also available in - German: \b{C++ GUI Programmierung mit Qt 4: Die offizielle Einführung}, - \e{Addison-Wesley}, ISBN 3-827327-29-6 - \li \b{The Book of Qt4, The Art of Building Qt Applications} / Daniel Molkentin, - \e{Open Source Press}, ISBN 1-59327-147-6. - Translated from \b{Qt 4, Einführung in die Applikationsentwicklung}, - \e{Open Source Press}, ISBN 3-937514-12-0. - \li \b{Foundations of Qt Development} / Johan Thelin, \e{Apress}, ISBN 1-59059-831-8. - \li \b{Advanced Qt Programming} / Mark Summerfield, \e{Prentice Hall}, ISBN 0-321-63590-6. - This book covers Model/View programming on more than 150 pages. - \endlist - - The following list provides an overview of example programs contained in the first three - books listed above. Some of them make very good templates for developing similar - applications. - - \table - \header - \li Example name - \li View class used - \li Model used - \li Aspects covered - \li - \row - \li Team Leaders - \li QListview - \li QStringListModel - \li - \li Book 1, Chapter 10, Figure 10.6 - \row - \li Color Names - \li QListView - \li QSortFilterProxyModel - applied to QStringListModel - \li - \li Book 1, Chapter 10, Figure 10.8 - \row - \li Currencies - \li QTableView - \li custom model based on - QAbstractTableModel - \li Read only - \li Book 1, Chapter 10, Figure 10.10 - \row - \li Cities - \li QTableView - \li Custom model based on - QAbstractTableModel - \li Read / write - \li Book 1, Chapter 10, Figure 10.12 - \row - \li Boolean Parser - \li QTreeView - \li Custom model based on - QAbstractItemModel - \li Read only - \li Book 1, Chapter 10, Figure 10.14 - \row - \li Track Editor - \li {2, 1} QTableWidget - \li Custom delegate providing a custom editor - \li Book 1, Chapter 10, Figure 10.15 - - \row - \li Address Book - \li QListView - QTableView - QTreeView - \li Custom model based on - QAbstractTableModel - \li Read / write - \li Book2, Chapter 8.4 - \row - \li Address Book with sorting - \li - \li QSortfilterProxyModel - \li Introducing sort and filter capabilities - \li Book2, Chapter 8.5 - \row - \li Address Book - with checkboxes - \li - \li - \li Introducing checkboxes in model/view - \li Book2, Chapter 8.6 - \row - \li Address Book with transposed grid - \li - \li Custom proxy Model based on QAbstractProxyModel - \li Introducing a custom model - \li Book2, Chapter 8.7 - \row - \li Address Book with drag and drop - \li - \li - \li Introducing drag and drop support - \li Book2, Chapter 8.8 - \row - \li Address Book with custom editor - \li - \li - \li Introducing custom delegates - \li Book2, Chapter 8.9 - \row - \li Views - \li QListView - QTableView - QTreeView - \li QStandardItemModel - \li Read only - \li Book 3, Chapter 5, figure 5-3 - \row - \li Bardelegate - \li QTableView - \li - \li Custom delegate for presentation based on QAbstractItemDelegate - \li Book 3, Chapter 5, figure 5-5 - \row - \li Editdelegate - \li QTableView - \li - \li Custom delegate for editing based on QAbstractItemDelegate - \li Book 3, Chapter 5, figure 5-6 - \row - \li Singleitemview - \li Custom view based on QAbstractItemView - \li - \li Custom view - \li Book 3, - Chapter 5, - figure 5-7 - \row - \li listmodel - \li QTableView - \li Custom Model based on QAbstractTableModel - \li Read only - \li Book 3, Chapter 5, Figure 5-8 - \row - \li treemodel - \li QTreeView - \li Custom Model based on QAbstractItemModel - \li Read only - \li Book 3, Chapter 5, Figure 5-10 - \row - \li edit integers - \li QListView - \li Custom Model based on QAbstractListModel - \li Read / write - \li Book 3, Chapter 5, Listing 5-37, Figure 5-11 - \row - \li sorting - \li QTableView - \li QSortFilterProxyModel applied to QStringListModel - \li Demonstrates sorting - \li Book 3, Chapter 5, Figure 5-12 - \endtable - - - \section2 4.2 Qt Documentation - - Qt 5.0 comes with 19 examples for model/view. - The examples can be found on the \l{Item Views Examples} page. - - \table - \header - \li Example name - \li View class used - \li Model used - \li Aspects covered - \row - \li Address Book - \li QTableView - \li QAbstractTableModel - QSortFilterProxyModel - \li Usage of QSortFilterProxyModel to generate different - subsets from one data pool - \row - \li Basic Sort/Filter Model - \li QTreeView - \li QStandardItemModel - QSortFilterProxyModel - \li - \row - \li Chart - \li Custom view - \li QStandardItemModel - \li Designing custom views that cooperate with selection models - \row - \li Color Editor Factory - \li {2, 1} QTableWidget - \li Enhancing the standard delegate with a new custom editor to choose colours - \row - \li Combo Widget Mapper - \li QDataWidgetMapper to map QLineEdit, QTextEdit and QComboBox - \li QStandardItemModel - \li Shows how a QComboBox can serve as a view class - \row - \li Custom Sort/Filter Model - \li QTreeView - \li QStandardItemModel - QSortFilterProxyModel - \li Subclass QSortFilterProxyModel for advanced sorting and filtering - \row - \li Dir View - \li QTreeView - \li QFileSystemModel - \li Very small example to demonstrate how to assign a model to a view - \row - \li Editable Tree Model - \li QTreeView - \li Custom tree model - \li Comprehensive example for working with trees, demonstrates - editing cells and tree structure with an underlying custom - model - \row - \li Fetch More - \li QListView - \li Custom list model - \li Dynamically changing model - \row - \li Frozen Column - \li QTableView - \li QStandardItemModel - \li - \row - \li Interview - \li Multiple - \li Custom item model - \li Multiple views - \row - \li Pixelator - \li QTableView - \li Custom table model - \li Implementation of a custom delegate - \row - \li Puzzle - \li QListView - \li Custom list model - \li Model/view with drag and drop - \row - \li Simple DOM Model - \li QTreeView - \li Custom tree model - \li Read only example for a custom tree model - \row - \li Simple Tree Model - \li QTreeView - \li Custom tree model - \li Read only example for a custom tree model - \row - \li Simple Widget Mapper - \li QDataWidgetMapper to map QLineEdit, QTextEdit and QSpinBox - \li QStandardItemModel - \li Basic QDataWidgetMapper usage - \row - \li Spreadsheet - \li {2, 1} QTableView - \li Custom delegates - \row - \li Star Delegate - \li {2, 1} QTableWidget - \li Comprehensive custom delegate example. - \endtable + \section1 Examples - A \l{Model/View Programming}{reference document} for model/view technology - is also available. + Qt comes with multiple examples for model/view. You can find them on the + \l{Item Views Examples} page. */ /*! diff --git a/src/widgets/doc/src/qtwidgets-examples.qdoc b/src/widgets/doc/src/qtwidgets-examples.qdoc index 45677c471ba..364c985b310 100644 --- a/src/widgets/doc/src/qtwidgets-examples.qdoc +++ b/src/widgets/doc/src/qtwidgets-examples.qdoc @@ -164,3 +164,15 @@ regular expressions for the Widget-based applications. */ +/*! + \group examples-user-input + \ingroup all-examples + \title User Input Examples + \brief Using user input in Qt Widgets applications. + + \image imagegestures-example.png {Application handling touch gestures} + + Qt provides the functionality for handling user input and drag-and-drop in + widget-based applications. + +*/ diff --git a/src/widgets/doc/src/qtwidgets-toc.qdoc b/src/widgets/doc/src/qtwidgets-toc.qdoc index bc447b8bd58..beddf853a22 100644 --- a/src/widgets/doc/src/qtwidgets-toc.qdoc +++ b/src/widgets/doc/src/qtwidgets-toc.qdoc @@ -53,6 +53,7 @@ \li \l{Rich Text Examples} \li \l{Graphics View Examples} \li \l{Widget Tools Examples} + \li \l{User Input Examples} \endlist \endlist diff --git a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc index 841948b671f..84226fdb5b5 100644 --- a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc +++ b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc @@ -536,21 +536,20 @@ to preview style sheets. You can right-click on any widget in Designer and select \uicontrol{Change styleSheet...} to set the style sheet. - \image designer-stylesheet-options.png + \image designer-stylesheet-options.webp {Editing a form in Qt Widgets Designer} - In Qt 4.2 and later, \QD also includes a - style sheet syntax highlighter and validator. The validator indicates - if the syntax is valid or invalid, at the bottom left of the \uicontrol{Edit - Style Sheet} dialog. + \QD also includes a style sheet syntax highlighter and validator. The + validator indicates if the syntax is valid or invalid, at the bottom left + of the \uicontrol{Edit Style Sheet} dialog. - \image designer-validator-highlighter.png + \image designer-validator-highlighter.webp {Editing and validating a stylesheet} When you click \uicontrol{OK} or \uicontrol{Apply}, \QD will automatically display the widget with its new stylesheet. - \image designer-stylesheet-usage.png + \image designer-stylesheet-usage.webp {Preview of a form with the new stylesheet} */ diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index e4159ad2cf0..6288aae096a 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -3108,7 +3108,8 @@ void QAbstractItemView::keyboardSearch(const QString &search) QModelIndex startMatch; QModelIndexList previous; do { - match = d->model->match(current, Qt::DisplayRole, d->keyboardInput); + match = d->model->match(current, Qt::DisplayRole, d->keyboardInput, 1, + d->keyboardSearchFlags); if (match == previous) break; firstMatch = match.value(0); @@ -3251,6 +3252,30 @@ void QAbstractItemView::setUpdateThreshold(int threshold) } /*! + \property QAbstractItemView::keyboardSearchFlags + \since 6.11 + This property determines how the default implementation of + keyboardSearch() matches the given string against the model's data. + + The default value is \c{Qt::MatchStartsWith|Qt::MatchWrap}. + + \sa keyboardSearch() + \sa QAbstractItemModel::match() +*/ + +Qt::MatchFlags QAbstractItemView::keyboardSearchFlags() const +{ + Q_D(const QAbstractItemView); + return d->keyboardSearchFlags; +} + +void QAbstractItemView::setKeyboardSearchFlags(Qt::MatchFlags searchFlags) +{ + Q_D(QAbstractItemView); + d->keyboardSearchFlags = searchFlags; +} + +/*! Opens a persistent editor on the item at the given \a index. If no editor exists, the delegate will create a new editor. @@ -3298,7 +3323,8 @@ void QAbstractItemView::closePersistentEditor(const QModelIndex &index) bool QAbstractItemView::isPersistentEditorOpen(const QModelIndex &index) const { Q_D(const QAbstractItemView); - return d->editorForIndex(index).widget; + QWidget *editor = d->editorForIndex(index).widget; + return editor && d->persistent.contains(editor); } /*! diff --git a/src/widgets/itemviews/qabstractitemview.h b/src/widgets/itemviews/qabstractitemview.h index 63adac8d6f2..ce509dc9e98 100644 --- a/src/widgets/itemviews/qabstractitemview.h +++ b/src/widgets/itemviews/qabstractitemview.h @@ -48,6 +48,8 @@ class Q_WIDGETS_EXPORT QAbstractItemView : public QAbstractScrollArea Q_PROPERTY(ScrollMode horizontalScrollMode READ horizontalScrollMode WRITE setHorizontalScrollMode RESET resetHorizontalScrollMode) Q_PROPERTY(int updateThreshold READ updateThreshold WRITE setUpdateThreshold) + Q_PROPERTY(Qt::MatchFlags keyboardSearchFlags READ keyboardSearchFlags + WRITE setKeyboardSearchFlags) public: enum SelectionMode { @@ -182,6 +184,9 @@ public: int updateThreshold() const; void setUpdateThreshold(int threshold); + Qt::MatchFlags keyboardSearchFlags() const; + void setKeyboardSearchFlags(Qt::MatchFlags searchFlags); + void openPersistentEditor(const QModelIndex &index); void closePersistentEditor(const QModelIndex &index); bool isPersistentEditorOpen(const QModelIndex &index) const; @@ -204,7 +209,7 @@ public: virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const override; - using QAbstractScrollArea::update; + using QWidget::update; public Q_SLOTS: virtual void reset(); diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h index b24b2d21c33..60799fb8a50 100644 --- a/src/widgets/itemviews/qabstractitemview_p.h +++ b/src/widgets/itemviews/qabstractitemview_p.h @@ -383,6 +383,7 @@ public: QString keyboardInput; QElapsedTimer keyboardInputTime; + Qt::MatchFlags keyboardSearchFlags = Qt::MatchStartsWith | Qt::MatchWrap; bool autoScroll; QBasicTimer autoScrollTimer; diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index da1fbbd60df..84ff04c9f34 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -1030,7 +1030,8 @@ void QTreeView::keyboardSearch(const QString &search) searchFrom = searchFrom.sibling(searchFrom.row(), start.column()); if (searchFrom.parent() == start.parent()) searchFrom = start; - QModelIndexList match = d->model->match(searchFrom, Qt::DisplayRole, searchString); + QModelIndexList match = d->model->match(searchFrom, Qt::DisplayRole, searchString, 1, + keyboardSearchFlags()); if (match.size()) { int hitIndex = d->viewIndex(match.at(0)); if (hitIndex >= 0 && hitIndex < startIndex) diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 6fcfcf1b1ef..fa95a1d2538 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -1432,8 +1432,8 @@ void QApplicationPrivate::notifyWindowIconChanged() // in case there are any plain QWindows in this QApplication-using // application, also send the notification to them - for (int i = 0; i < windowList.size(); ++i) - QCoreApplication::sendEvent(windowList.at(i), &ev); + for (QWindow *w : std::as_const(windowList)) + QCoreApplication::sendEvent(w, &ev); } /*! @@ -1508,11 +1508,15 @@ void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) return; } - if (focus && (reason == Qt::BacktabFocusReason || reason == Qt::TabFocusReason) - && qt_in_tab_key_event) - focus->window()->setAttribute(Qt::WA_KeyboardFocusChange); - else if (focus && reason == Qt::ShortcutFocusReason) { - focus->window()->setAttribute(Qt::WA_KeyboardFocusChange); + if (focus) { + if ((reason == Qt::BacktabFocusReason || reason == Qt::TabFocusReason) + && qt_in_tab_key_event) + focus->window()->setAttribute(Qt::WA_KeyboardFocusChange); + else if (reason == Qt::ShortcutFocusReason) { + focus->window()->setAttribute(Qt::WA_KeyboardFocusChange); + } else { + focus->window()->setAttribute(Qt::WA_KeyboardFocusChange, false); + } } QWidget *prev = focus_widget; focus_widget = focus; @@ -1774,9 +1778,9 @@ void QApplicationPrivate::notifyLayoutDirectionChange() // in case there are any plain QWindows in this QApplication-using // application, also send the notification to them - for (int i = 0; i < windowList.size(); ++i) { + for (QWindow *w: std::as_const(windowList)) { QEvent ev(QEvent::ApplicationLayoutDirectionChange); - QCoreApplication::sendEvent(windowList.at(i), &ev); + QCoreApplication::sendEvent(w, &ev); } } @@ -1863,14 +1867,12 @@ void QApplicationPrivate::setActiveWindow(QWidget* act) QEvent windowActivate(QEvent::WindowActivate); QEvent windowDeactivate(QEvent::WindowDeactivate); - for (int i = 0; i < toBeActivated.size(); ++i) { - QWidget *w = toBeActivated.at(i); + for (QWidget *w : std::as_const(toBeActivated)) { QApplication::sendSpontaneousEvent(w, &windowActivate); QApplication::sendSpontaneousEvent(w, &activationChange); } - for(int i = 0; i < toBeDeactivated.size(); ++i) { - QWidget *w = toBeDeactivated.at(i); + for (QWidget *w : std::as_const(toBeDeactivated)) { QApplication::sendSpontaneousEvent(w, &windowDeactivate); QApplication::sendSpontaneousEvent(w, &activationChange); } @@ -2082,8 +2084,7 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, con } QEvent leaveEvent(QEvent::Leave); - for (int i = 0; i < leaveList.size(); ++i) { - auto *w = leaveList.at(i); + for (QWidget *w : std::as_const(leaveList)) { if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, nullptr)) { QCoreApplication::sendEvent(w, &leaveEvent); if (w->testAttribute(Qt::WA_Hover) && @@ -2125,8 +2126,7 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, con // Whenever we leave an alien widget on X11/QPA, we need to reset its nativeParentWidget()'s cursor. // This is not required on Windows as the cursor is reset on every single mouse move. QWidget *parentOfLeavingCursor = nullptr; - for (int i = 0; i < leaveList.size(); ++i) { - auto *w = leaveList.at(i); + for (QWidget *w : std::as_const(leaveList)) { if (!isAlien(w)) break; if (w->testAttribute(Qt::WA_SetCursor)) { @@ -3085,7 +3085,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) const QPoint offset = w->pos(); w = w->parentWidget(); QMutableTouchEvent::setTarget(touchEvent, w); - for (int i = 0; i < touchEvent->pointCount(); ++i) { + for (qsizetype cnt = touchEvent->pointCount(), i = 0; i < cnt; ++i) { auto &pt = touchEvent->point(i); QMutableEventPoint::setPosition(pt, pt.position() + offset); } @@ -3164,8 +3164,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) res = d->notify_helper(w, &ge); gestureEvent->m_spont = false; eventAccepted = ge.isAccepted(); - for (int i = 0; i < gestures.size(); ++i) { - QGesture *g = gestures.at(i); + for (QGesture *g : std::as_const(gestures)) { // Ignore res [event return value] because handling of multiple gestures // packed into a single QEvent depends on not consuming the event if (eventAccepted || ge.isAccepted(g)) { @@ -3708,7 +3707,7 @@ bool QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEven { bool containsPress = false; - for (int i = 0; i < touchEvent->pointCount(); ++i) { + for (qsizetype cnt = touchEvent->pointCount(), i = 0; i < cnt; ++i) { auto &pt = touchEvent->point(i); QMutableEventPoint::setPosition(pt, widget->mapFromGlobal(pt.globalPosition())); @@ -3768,7 +3767,7 @@ void QApplicationPrivate::activateImplicitTouchGrab(QWidget *widget, QTouchEvent // If the widget dispatched the event further (see QGraphicsProxyWidget), then // there might already be an implicit grabber. Don't override that. A widget that // has partially recognized a gesture needs to grab all points. - for (int i = 0; i < touchEvent->pointCount(); ++i) { + for (qsizetype cnt = touchEvent->pointCount(), i = 0; i < cnt; ++i) { auto &ep = touchEvent->point(i); if (!QMutableEventPoint::target(ep) && (ep.isAccepted() || grabMode == GrabAllPoints)) QMutableEventPoint::setTarget(ep, widget); diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp index 9e6aaf4b95f..d989feb7f91 100644 --- a/src/widgets/kernel/qtooltip.cpp +++ b/src/widgets/kernel/qtooltip.cpp @@ -20,6 +20,8 @@ #if QT_CONFIG(style_stylesheet) #include <private/qstylesheetstyle_p.h> #endif +#include <qpa/qplatformwindow.h> +#include <qpa/qplatformwindow_p.h> #include <qlabel.h> #include <QtWidgets/private/qlabel_p.h> @@ -386,6 +388,17 @@ void QTipLabel::placeTip(const QPoint &pos, QWidget *w) p += offset; +#if QT_CONFIG(wayland) + create(); + if (auto waylandWindow = dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(windowHandle()->handle())) { + // based on the existing code below, by default position at 'p' stored at the bottom right of our rect + // then flip to the other arbitrary 4x24 space if constrained + const QRect controlGeometry(QRect(p.x() - 4, p.y() - 24, 4, 24)); + waylandWindow->setParentControlGeometry(controlGeometry); + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::ToolTip); + } +#endif + QRect screenRect = screen->geometry(); if (p.x() + this->width() > screenRect.x() + screenRect.width()) p.rx() -= 4 + this->width(); diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 36446c3e5c4..9499c88af12 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -13144,11 +13144,22 @@ int QWidget::metric(PaintDeviceMetric m) const void QWidget::initPainter(QPainter *painter) const { const QPalette &pal = palette(); - painter->d_func()->state->pen = QPen(pal.brush(foregroundRole()), 1); - painter->d_func()->state->bgBrush = pal.brush(backgroundRole()); + QPainterPrivate *painterPrivate = QPainterPrivate::get(painter); + + painterPrivate->state->pen = QPen(pal.brush(foregroundRole()), 1); + painterPrivate->state->bgBrush = pal.brush(backgroundRole()); QFont f(font(), this); - painter->d_func()->state->deviceFont = f; - painter->d_func()->state->font = f; + painterPrivate->state->deviceFont = f; + painterPrivate->state->font = f; + + painterPrivate->setEngineDirtyFlags({ + QPaintEngine::DirtyPen, + QPaintEngine::DirtyBrush, + QPaintEngine::DirtyFont, + }); + + if (painterPrivate->extended) + painterPrivate->extended->penChanged(); } /*! diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 737ccb0e807..622f1548756 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -591,6 +591,10 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) } } + // Event delivery above might have destroyed this object. See QTBUG-138419. + if (self.isNull()) + return; + if (QApplication::activePopupWidget() != activePopupWidget && QApplicationPrivate::replayMousePress && QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::ReplayMousePressOutsidePopup).toBool()) { diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 82d16cb1252..b2cfb27e814 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -3419,29 +3419,28 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC } QRect gr = subControlRect(cc, opt, SC_SliderGroove, w); - if (slider->subControls & SC_SliderGroove) { + if (slider->subControls & SC_SliderGroove) grooveSubRule.drawRule(p, gr); - } if (slider->subControls & SC_SliderHandle) { QRect hr = subControlRect(cc, opt, SC_SliderHandle, w); - QRenderRule subRule1 = renderRule(w, opt, PseudoElement_SliderSubPage); - if (subRule1.hasDrawable()) { - QRect r(gr.topLeft(), - slider->orientation == Qt::Horizontal - ? QPoint(hr.x()+hr.width()/2, gr.y()+gr.height() - 1) - : QPoint(gr.x()+gr.width() - 1, hr.y()+hr.height()/2)); - subRule1.drawRule(p, r); - } - - QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SliderAddPage); - if (subRule2.hasDrawable()) { - QRect r(slider->orientation == Qt::Horizontal - ? QPoint(hr.x()+hr.width()/2+1, gr.y()) - : QPoint(gr.x(), hr.y()+hr.height()/2+1), - gr.bottomRight()); - subRule2.drawRule(p, r); + if (slider->subControls & SC_SliderGroove) { + const bool isHor = slider->orientation == Qt::Horizontal; + QRenderRule subRule1 = renderRule(w, opt, PseudoElement_SliderSubPage); + if (subRule1.hasDrawable()) { + QRect r(gr.topLeft(), + isHor ? QPoint(hr.x() + hr.width() / 2, gr.y() + gr.height() - 1) + : QPoint(gr.x() + gr.width() - 1, hr.y() + hr.height() / 2)); + subRule1.drawRule(p, r); + } + QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SliderAddPage); + if (subRule2.hasDrawable()) { + QRect r(isHor ? QPoint(hr.x() + hr.width() / 2 + 1, gr.y()) + : QPoint(gr.x(), hr.y() + hr.height() / 2 + 1), + gr.bottomRight()); + subRule2.drawRule(p, r); + } } handleSubRule.drawRule(p, handleSubRule.boxRect(hr, Margin)); diff --git a/src/widgets/util/qcompleter.cpp b/src/widgets/util/qcompleter.cpp index 220f600ea41..735b574d293 100644 --- a/src/widgets/util/qcompleter.cpp +++ b/src/widgets/util/qcompleter.cpp @@ -122,6 +122,8 @@ #include "QtGui/qevent.h" #include <private/qapplication_p.h> #include <private/qwidget_p.h> +#include <qpa/qplatformwindow.h> +#include <qpa/qplatformwindow_p.h> #if QT_CONFIG(lineedit) #include "QtWidgets/qlineedit.h" #endif @@ -925,10 +927,15 @@ void QCompleterPrivate::showPopup(const QRect& rect) popup->setGeometry(pos.x(), pos.y(), w, h); if (!popup->isVisible()) { - // Make sure popup has a transient parent set, Wayland needs it. QTBUG-130474 - popup->winId(); // force creation of windowHandle - popup->windowHandle()->setTransientParent(widget->window()->windowHandle()); - +#if QT_CONFIG(wayland) + popup->createWinId(); + if (auto waylandWindow = dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(popup->windowHandle()->handle())) { + popup->windowHandle()->setTransientParent(widget->window()->windowHandle()); + const QRect controlGeometry = QRect(widget->mapTo(widget->topLevelWidget(), QPoint(0,0)), widget->size()); + waylandWindow->setParentControlGeometry(controlGeometry); + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::ComboBox); + } +#endif popup->show(); } } diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index 6f25b8bde67..2f51b83a49d 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -7,6 +7,9 @@ #include <qstylepainter.h> #include <qpa/qplatformtheme.h> #include <qpa/qplatformmenu.h> +#include <qpa/qplatformwindow.h> +#include <qpa/qplatformwindow_p.h> + #include <qlineedit.h> #include <qapplication.h> #include <qlistview.h> @@ -2868,6 +2871,17 @@ void QComboBox::showPopup() container->hide(); } } + +#if QT_CONFIG(wayland) + if (auto waylandWindow = dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(container->windowHandle()->handle())) { + const QRect popup(style->subControlRect(QStyle::CC_ComboBox, &opt, + QStyle::SC_ComboBoxListBoxPopup, this)); + const QRect controlGeometry = QRect(mapTo(window(), popup.topLeft()), popup.size()); + waylandWindow->setParentControlGeometry(controlGeometry); + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::ComboBox); + } +#endif + container->show(); if (!neededHorizontalScrollBar && needHorizontalScrollBar()) { listRect.adjust(0, 0, 0, sb->height()); diff --git a/src/widgets/widgets/qmdisubwindow.cpp b/src/widgets/widgets/qmdisubwindow.cpp index 1ca6b8a47a1..7aff0da3327 100644 --- a/src/widgets/widgets/qmdisubwindow.cpp +++ b/src/widgets/widgets/qmdisubwindow.cpp @@ -2220,7 +2220,7 @@ QMdiSubWindow::QMdiSubWindow(QWidget *parent, Qt::WindowFlags flags) d->titleBarPalette = d->desktopPalette(); d->font = QApplication::font("QMdiSubWindowTitleBar"); // We don't want the menu icon by default on mac. -#ifndef Q_OS_MAC +#ifndef Q_OS_DARWIN if (windowIcon().isNull()) d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, nullptr, this); else @@ -2847,8 +2847,11 @@ bool QMdiSubWindow::event(QEvent *event) break; case QEvent::WindowIconChange: d->menuIcon = windowIcon(); + // We don't want the default menu icon on mac. +#ifndef Q_OS_DARWIN if (d->menuIcon.isNull()) d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, nullptr, this); +#endif if (d->controlContainer) d->controlContainer->updateWindowIcon(d->menuIcon); if (!maximizedSystemMenuIconWidget()) diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 5cda8f33f4c..92ff14dd44f 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -40,6 +40,8 @@ #include <private/qaction_p.h> #include <private/qguiapplication_p.h> #include <qpa/qplatformtheme.h> +#include <qpa/qplatformwindow.h> +#include <qpa/qplatformwindow_p.h> #include <private/qstyle_p.h> QT_BEGIN_NAMESPACE @@ -769,7 +771,8 @@ void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason #endif hideMenu(hideActiveMenu); } else if (!currentAction || !currentAction->menu()) { - sloppyState.startTimerIfNotRunning(); + if (reason != SelectionReason::SelectedFromAPI) + sloppyState.startTimerIfNotRunning(); } } } @@ -2170,7 +2173,7 @@ void QMenu::hideTearOffMenu() void QMenu::setActiveAction(QAction *act) { Q_D(QMenu); - d->setCurrentAction(act, 0); + d->setCurrentAction(act, 0, QMenuPrivate::SelectionReason::SelectedFromAPI); if (d->scroll && act) d->scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollCenter); } @@ -2535,6 +2538,23 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po } popupScreen = QGuiApplication::screenAt(pos); q->setGeometry(QRect(pos, size)); + +#if QT_CONFIG(wayland) + q->create(); + if (auto waylandWindow = dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(q->windowHandle()->handle())) { + if (causedButton) { + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::Menu); + waylandWindow->setParentControlGeometry(causedButton->geometry()); + } else if (caused) { + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::SubMenu); + waylandWindow->setParentControlGeometry(caused->d_func()->actionRect(caused->d_func()->currentAction)); + } else if (auto menubar = qobject_cast<QMenuBar*>(causedPopup.widget)) { + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::Menu); + waylandWindow->setParentControlGeometry(menubar->actionGeometry(causedPopup.action)); + } + } +#endif + #if QT_CONFIG(effects) int hGuess = q->isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll; int vGuess = QEffects::DownScroll; @@ -2952,7 +2972,7 @@ void QMenu::mouseReleaseEvent(QMouseEvent *e) #endif d->activateAction(action, QAction::Trigger); } - } else if (!action || action->isEnabled()) { + } else if (!action || (action->isEnabled() && !action->isSeparator())) { d->hideUpToMenuBar(); } } diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h index dd1f058a288..d9dcd7d0362 100644 --- a/src/widgets/widgets/qmenu_p.h +++ b/src/widgets/widgets/qmenu_p.h @@ -362,7 +362,8 @@ public: } delayState; enum SelectionReason { SelectedFromKeyboard, - SelectedFromElsewhere + SelectedFromAPI, + SelectedFromElsewhere, }; enum class SelectionDirection { Up, |
