diff options
Diffstat (limited to 'src/gui')
77 files changed, 1425 insertions, 622 deletions
diff --git a/src/gui/animation/qguivariantanimation.cpp b/src/gui/animation/qguivariantanimation.cpp index 0ae79b6..1e9c166 100644 --- a/src/gui/animation/qguivariantanimation.cpp +++ b/src/gui/animation/qguivariantanimation.cpp @@ -54,10 +54,10 @@ QT_BEGIN_NAMESPACE template<> Q_INLINE_TEMPLATE QColor _q_interpolate(const QColor &f,const QColor &t, qreal progress) { - return QColor(_q_interpolate(f.red(), t.red(), progress), - _q_interpolate(f.green(), t.green(), progress), - _q_interpolate(f.blue(), t.blue(), progress), - _q_interpolate(f.alpha(), t.alpha(), progress)); + return QColor(qBound(0,_q_interpolate(f.red(), t.red(), progress),255), + qBound(0,_q_interpolate(f.green(), t.green(), progress),255), + qBound(0,_q_interpolate(f.blue(), t.blue(), progress),255), + qBound(0,_q_interpolate(f.alpha(), t.alpha(), progress),255)); } template<> Q_INLINE_TEMPLATE QQuaternion _q_interpolate(const QQuaternion &f,const QQuaternion &t, qreal progress) diff --git a/src/gui/dialogs/qfiledialog_mac.mm b/src/gui/dialogs/qfiledialog_mac.mm index 8e4c461..d9bec27 100644 --- a/src/gui/dialogs/qfiledialog_mac.mm +++ b/src/gui/dialogs/qfiledialog_mac.mm @@ -280,6 +280,10 @@ QT_USE_NAMESPACE - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename { Q_UNUSED(sender); + + if ([filename length] == 0) + return NO; + QString qtFileName = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)(filename); QFileInfo info(qtFileName.normalized(QT_PREPEND_NAMESPACE(QString::NormalizationForm_C))); QString path = info.absolutePath(); diff --git a/src/gui/dialogs/qwizard.cpp b/src/gui/dialogs/qwizard.cpp index 0102e25..db1c9e9 100644 --- a/src/gui/dialogs/qwizard.cpp +++ b/src/gui/dialogs/qwizard.cpp @@ -1537,7 +1537,9 @@ void QWizardPrivate::handleAeroStyleChange() vistaHelper->backButton()->show(); } else { q->setMouseTracking(true); // ### original value possibly different +#ifndef QT_NO_CURSOR q->unsetCursor(); // ### ditto +#endif antiFlickerWidget->move(0, 0); vistaHelper->hideBackButton(); vistaHelper->setTitleBarIconAndCaptionVisible(true); diff --git a/src/gui/dialogs/qwizard_win.cpp b/src/gui/dialogs/qwizard_win.cpp index aa38ddc..f3f3a4e 100644 --- a/src/gui/dialogs/qwizard_win.cpp +++ b/src/gui/dialogs/qwizard_win.cpp @@ -387,10 +387,12 @@ bool QVistaHelper::winEvent(MSG* msg, long* result) void QVistaHelper::setMouseCursor(QPoint pos) { +#ifndef QT_NO_CURSOR if (rtTop.contains(pos)) wizard->setCursor(Qt::SizeVerCursor); else wizard->setCursor(Qt::ArrowCursor); +#endif } void QVistaHelper::mouseEvent(QEvent *event) diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index e25b40b..f20480b 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -350,8 +350,10 @@ void QGraphicsEffect::setEnabled(bool enable) return; d->isEnabled = enable; - if (d->source) + if (d->source) { d->source->d_func()->effectBoundingRectChanged(); + d->source->d_func()->invalidateCache(); + } emit enabledChanged(enable); } @@ -405,8 +407,10 @@ QGraphicsEffectSource *QGraphicsEffect::source() const void QGraphicsEffect::updateBoundingRect() { Q_D(QGraphicsEffect); - if (d->source) + if (d->source) { d->source->d_func()->effectBoundingRectChanged(); + d->source->d_func()->invalidateCache(); + } } /*! diff --git a/src/gui/effects/qgraphicseffect_p.h b/src/gui/effects/qgraphicseffect_p.h index 87abbbc..24d8696 100644 --- a/src/gui/effects/qgraphicseffect_p.h +++ b/src/gui/effects/qgraphicseffect_p.h @@ -102,8 +102,8 @@ public: QGraphicsEffect::ChangeFlags flags; if (source) { flags |= QGraphicsEffect::SourceDetached; - source->d_func()->detach(); source->d_func()->invalidateCache(); + source->d_func()->detach(); delete source; } source = newSource; diff --git a/src/gui/embedded/qdecorationdefault_qws.cpp b/src/gui/embedded/qdecorationdefault_qws.cpp index 5bc8826..70389d3 100644 --- a/src/gui/embedded/qdecorationdefault_qws.cpp +++ b/src/gui/embedded/qdecorationdefault_qws.cpp @@ -394,7 +394,7 @@ QPixmap QDecorationDefault::pixmapFor(const QWidget *widget, */ int QDecorationDefault::titleBarHeight(const QWidget *) { - return qMax(20, QApplication::fontMetrics().lineSpacing() + BORDER_WIDTH); + return qMax(20, QApplication::fontMetrics().height() + BORDER_WIDTH); } /*! diff --git a/src/gui/embedded/qdecorationwindows_qws.cpp b/src/gui/embedded/qdecorationwindows_qws.cpp index 77393cf..7764ca5 100644 --- a/src/gui/embedded/qdecorationwindows_qws.cpp +++ b/src/gui/embedded/qdecorationwindows_qws.cpp @@ -216,7 +216,7 @@ QRegion QDecorationWindows::region(const QWidget *widget, const QRect &rect, int bool hasMinimize = flags & Qt::WindowMinimizeButtonHint; bool hasMaximize = flags & Qt::WindowMaximizeButtonHint; const QFontMetrics fontMetrics = QApplication::fontMetrics(); - int titleHeight = hasTitle ? qMax(20, fontMetrics.lineSpacing()) : 0; + int titleHeight = hasTitle ? qMax(20, fontMetrics.height()) : 0; int state = widget->windowState(); bool isMinimized = state & Qt::WindowMinimized; bool isMaximized = state & Qt::WindowMaximized; diff --git a/src/gui/graphicsview/qgraphicsanchorlayout.cpp b/src/gui/graphicsview/qgraphicsanchorlayout.cpp index c39e8a6..e21cd99 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout.cpp @@ -48,36 +48,60 @@ \ingroup geomanagement \ingroup graphicsview-api - The anchor layout is a layout where one can specify how widgets should be placed relative to - each other. The specification is called an anchor, and it is set up by calling anchor(). + The anchor layout allows developers to specify how widgets should be placed relative to + each other, and to the layout itself. The specification is made by adding anchors to the + layout by calling addAnchor(), addAnchors() or addCornerAnchors(). + + Existing anchors in the layout can be accessed with the anchor() function. + Items that are anchored are automatically added to the layout, and if items + are removed, all their anchors will be automatically removed. + + \beginfloatleft + \inlineimage simpleanchorlayout-example.png Using an anchor layout to align simple colored widgets. + \endfloat + Anchors are always set up between edges of an item, where the "center" is also considered to - be an edge. Considering this example: - \code - QGraphicsAnchorLayout *l = new QGraphicsAnchorLayout; - QGraphicsWidget *a = new QGraphicsWidget; - QGraphicsWidget *b = new QGraphicsWidget; - l->anchor(a, Qt::AnchorRight, b, Qt::AnchorLeft); - \endcode - - Here is the right edge of item A anchored to the left edge of item B, with the result that - item B will be placed to the right of item A, with a spacing between A and B. If the - spacing is negative, the items will overlap to some extent. Items that are anchored are - automatically added to the layout, and if items are removed, all their anchors will be - automatically removed - - \section1 Size Hints and Size Policies in QGraphicsAnchorLayout + be an edge. Consider the following example: + + \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding anchors + + Here, the right edge of item \c a is anchored to the left edge of item \c b and the bottom + edge of item \c a is anchored to the top edge of item \c b, with the result that + item \c b will be placed diagonally to the right and below item \c b. + + The addCornerAnchors() function provides a simpler way of anchoring the corners + of two widgets than the two individual calls to addAnchor() shown in the code + above. Here, we see how a widget can be anchored to the top-left corner of the enclosing + layout: + + \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding a corner anchor + + In cases where anchors are used to match the widths or heights of widgets, it is + convenient to use the addAnchors() function. As with the other functions for specifying + anchors, it can also be used to anchor a widget to a layout. + + \clearfloat + \section1 Size Hints and Size Policies in an Anchor Layout QGraphicsAnchorLayout respects each item's size hints and size policies. However it does - not respect stretch factors currently. This might change in the future, so please refrain - from using stretch factors in anchor layout to avoid any future regressions. + not currently respect their stretch factors. This might change in the future, so avoid + using stretch factors in anchor layouts if you want to avoid any future regressions in + behavior. + + \section1 Spacing within an Anchor Layout + + The layout may distribute some space between the items. If the spacing has not been + explicitly specified, the actual amount of space will usually be 0. - \section1 Spacing within QGraphicsAnchorLayout + However, if the first edge is the \e opposite of the second edge (e.g., the right edge + of the first widget is anchored to the left edge of the second widget), the size of the + anchor will be queried from the style through a pixel metric: + \l{QStyle::}{PM_LayoutHorizontalSpacing} for horizontal anchors and + \l{QStyle::}{PM_LayoutVerticalSpacing} for vertical anchors. - Between the items, the layout can distribute some space. If the spacing has not been - explicitly specified, the actual amount of space will usually be 0, but if the first edge - is the "opposite" of the second edge (i.e. Right is anchored to Left or vice-versa), the - size of the anchor will be queried from the style through the pixelMetric - PM_LayoutHorizontalSpacing (or PM_LayoutVerticalSpacing for vertical anchors). + If the spacing is negative, the items will overlap to some extent. + + \sa QGraphicsLinearLayout, QGraphicsGridLayout, QGraphicsLayout */ /*! @@ -118,16 +142,26 @@ QGraphicsAnchor::~QGraphicsAnchor() } /*! - Sets the size policy of the anchor to \a policy. + \property QGraphicsAnchor::sizePolicy + \brief the size policy for the QGraphicsAnchor. + + By setting the size policy on an anchor you can configure how the item can resize itself + from its preferred spacing. For instance, if the anchor has the size policy + QSizePolicy::Minimum, the spacing is the minimum size of the anchor. However, its size + can grow up to the anchors maximum size. If the default size policy is QSizePolicy::Fixed, + the anchor can neither grow or shrink, which means that the only size the anchor can have + is the spacing. QSizePolicy::Fixed is the default size policy. + QGraphicsAnchor always has a minimum spacing of 0 and a very large maximum spacing. + + \sa QGraphicsAnchor::spacing */ + void QGraphicsAnchor::setSizePolicy(QSizePolicy::Policy policy) { Q_D(QGraphicsAnchor); d->setSizePolicy(policy); } -/*! - Returns the size policy of the anchor. The default size policy is QSizePolicy::Fixed -*/ + QSizePolicy::Policy QGraphicsAnchor::sizePolicy() const { Q_D(const QGraphicsAnchor); @@ -136,12 +170,12 @@ QSizePolicy::Policy QGraphicsAnchor::sizePolicy() const /*! \property QGraphicsAnchor::spacing - \brief the space between items in the QGraphicsAnchorLayout. + \brief the preferred space between items in the QGraphicsAnchorLayout. Depending on the anchor type, the default spacing is either 0 or a value returned from the style. - \sa QGraphicsAnchorLayout::anchor() + \sa QGraphicsAnchorLayout::addAnchor() */ void QGraphicsAnchor::setSpacing(qreal spacing) { @@ -205,7 +239,7 @@ QGraphicsAnchorLayout::~QGraphicsAnchorLayout() If there is already an anchor between the edges, the the new anchor will replace the old one. \a firstItem and \a secondItem are automatically added to the layout if they are not part - of the layout. This means that count() can increase with up to 2. + of the layout. This means that count() can increase by up to 2. The spacing an anchor will get depends on the type of anchor. For instance, anchors from the Right edge of one item to the Left edge of another (or vice versa) will use the default @@ -215,7 +249,10 @@ QGraphicsAnchorLayout::~QGraphicsAnchorLayout() The spacing can also be set manually by using QGraphicsAnchor::setSpacing() method. - \sa addCornerAnchors(), addAnchors() + Calling this function where \a firstItem or \a secondItem are ancestors of the layout have + undefined behaviour. + + \sa addAnchors(), addCornerAnchors() */ QGraphicsAnchor * QGraphicsAnchorLayout::addAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge, @@ -240,29 +277,26 @@ QGraphicsAnchorLayout::anchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint fi } /*! - Creates two anchors between \a firstItem and \a secondItem, where one is for the horizontal - edge and another one for the vertical edge that the corners \a firstCorner and \a - secondCorner specifies. - The magnitude of the anchors is picked up from the style. + Creates two anchors between \a firstItem and \a secondItem specified by the corners, + \a firstCorner and \a secondCorner, where one is for the horizontal edge and another + one for the vertical edge. + + This is a convenience function, since anchoring corners can be expressed as anchoring + two edges. For instance: - This is a convenience function, since anchoring corners can be expressed as anchoring two edges. - For instance, - \code - layout->addAnchor(layout, Qt::AnchorTop, b, Qt::AnchorTop); - layout->addAnchor(layout, Qt::AnchorLeft, b, Qt::AnchorLeft); - \endcode + \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding a corner anchor in two steps - has the same effect as + This can also be achieved with the following line of code: - \code - layout->addCornerAnchors(layout, Qt::TopLeft, b, Qt::TopLeft); - \endcode + \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding a corner anchor If there is already an anchor between the edge pairs, it will be replaced by the anchors that this function specifies. \a firstItem and \a secondItem are automatically added to the layout if they are not part of the - layout. This means that count() can increase with up to 2. + layout. This means that count() can increase by up to 2. + + \sa addAnchor(), addAnchors() */ void QGraphicsAnchorLayout::addCornerAnchors(QGraphicsLayoutItem *firstItem, Qt::Corner firstCorner, @@ -289,17 +323,16 @@ void QGraphicsAnchorLayout::addCornerAnchors(QGraphicsLayoutItem *firstItem, edges of \a secondItem, so that \a firstItem has the same size as \a secondItem in the dimensions specified by \a orientations. - Calling this convenience function with the following arguments - \code - l->addAnchors(firstItem, secondItem, Qt::Horizontal) - \endcode + For example, the following example anchors the left and right edges of two items + to match their widths: + + \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding anchors to match sizes in two steps + + This can also be achieved using the following line of code: - is the same as + \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding anchors to match sizes - \code - l->addAnchor(firstItem, Qt::AnchorLeft, secondItem, Qt::AnchorLeft); - l->addAnchor(firstItem, Qt::AnchorRight, secondItem, Qt::AnchorRight); - \endcode + \sa addAnchor(), addCornerAnchors() */ void QGraphicsAnchorLayout::addAnchors(QGraphicsLayoutItem *firstItem, QGraphicsLayoutItem *secondItem, diff --git a/src/gui/graphicsview/qgraphicsanchorlayout.h b/src/gui/graphicsview/qgraphicsanchorlayout.h index f09ac43..01c3a86 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout.h @@ -62,12 +62,13 @@ class Q_GUI_EXPORT QGraphicsAnchor : public QObject { Q_OBJECT Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing RESET unsetSpacing) + Q_PROPERTY(QSizePolicy::Policy sizePolicy READ sizePolicy WRITE setSizePolicy) public: void setSpacing(qreal spacing); void unsetSpacing(); + qreal spacing() const; void setSizePolicy(QSizePolicy::Policy policy); QSizePolicy::Policy sizePolicy() const; - qreal spacing() const; ~QGraphicsAnchor(); private: QGraphicsAnchor(QGraphicsAnchorLayout *parent); diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 5153783..f892bb4 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1228,7 +1228,7 @@ void QGraphicsItemCache::purge() } /*! - Constructs a QGraphicsItem with the given \a parent. + Constructs a QGraphicsItem, passing \a item to QGraphicsItem's constructor. It does not modify \fn QObject::parent(). If \a parent is 0, you can add the item to a scene by calling QGraphicsScene::addItem(). The item will then become a top-level item. @@ -1511,6 +1511,8 @@ const QGraphicsObject *QGraphicsItem::toGraphicsObject() const the parent. You should not \l{QGraphicsScene::addItem()}{add} the item to the scene yourself. + Calling this function on an item that is an ancestor of \a parent have undefined behaviour. + \sa parentItem(), childItems() */ void QGraphicsItem::setParentItem(QGraphicsItem *parent) @@ -4737,7 +4739,7 @@ bool QGraphicsItem::isObscuredBy(const QGraphicsItem *item) const { if (!item) return false; - return QGraphicsSceneBspTreeIndexPrivate::closestItemFirst_withoutCache(item, this) + return qt_closestItemFirst(item, this) && qt_QGraphicsItem_isObscured(this, item, boundingRect()); } @@ -7316,7 +7318,7 @@ void QGraphicsObject::grabGesture(Qt::GestureType gesture, Qt::GestureContext co /*! \property QGraphicsObject::parent - \brief the parent of the item + \brief the parent of the item. It is independent from \fn QObject::parent. \sa QGraphicsItem::setParentItem(), QGraphicsItem::parentObject() */ @@ -10755,6 +10757,23 @@ QDebug operator<<(QDebug debug, QGraphicsItem *item) return debug; } +QDebug operator<<(QDebug debug, QGraphicsObject *item) +{ + if (!item) { + debug << "QGraphicsObject(0)"; + return debug; + } + + debug.nospace() << item->metaObject()->className() << '(' << (void*)item; + if (!item->objectName().isEmpty()) + debug << ", name = " << item->objectName(); + debug.nospace() << ", parent = " << ((void*)item->parentItem()) + << ", pos = " << item->pos() + << ", z = " << item->zValue() << ", flags = " + << item->flags() << ')'; + return debug.space(); +} + QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemChange change) { const char *str = "UnknownChange"; diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 2665235..f3fe99c 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -555,7 +555,7 @@ public: using QObject::children; #endif - void grabGesture(Qt::GestureType type, Qt::GestureContext context = Qt::WidgetWithChildrenGesture); + void grabGesture(Qt::GestureType type, Qt::GestureContext context = Qt::ItemWithChildrenGesture); Q_SIGNALS: void parentChanged(); @@ -1120,6 +1120,7 @@ template <class T> inline T qgraphicsitem_cast(const QGraphicsItem *item) #ifndef QT_NO_DEBUG_STREAM Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem *item); +Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsObject *item); Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemChange change); Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag); Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlags flags); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 8fd1a75..7c3c4f0 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -630,6 +630,71 @@ public: /*! + Returns true if \a item1 is on top of \a item2. + The items dont need to be siblings. + + \internal +*/ +inline bool qt_closestItemFirst(const QGraphicsItem *item1, const QGraphicsItem *item2) +{ + // Siblings? Just check their z-values. + const QGraphicsItemPrivate *d1 = item1->d_ptr.data(); + const QGraphicsItemPrivate *d2 = item2->d_ptr.data(); + if (d1->parent == d2->parent) + return qt_closestLeaf(item1, item2); + + // Find common ancestor, and each item's ancestor closest to the common + // ancestor. + int item1Depth = d1->depth(); + int item2Depth = d2->depth(); + const QGraphicsItem *p = item1; + const QGraphicsItem *t1 = item1; + while (item1Depth > item2Depth && (p = p->d_ptr->parent)) { + if (p == item2) { + // item2 is one of item1's ancestors; item1 is on top + return !(t1->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent); + } + t1 = p; + --item1Depth; + } + p = item2; + const QGraphicsItem *t2 = item2; + while (item2Depth > item1Depth && (p = p->d_ptr->parent)) { + if (p == item1) { + // item1 is one of item2's ancestors; item1 is not on top + return (t2->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent); + } + t2 = p; + --item2Depth; + } + + // item1Ancestor is now at the same level as item2Ancestor, but not the same. + const QGraphicsItem *p1 = t1; + const QGraphicsItem *p2 = t2; + while (t1 && t1 != t2) { + p1 = t1; + p2 = t2; + t1 = t1->d_ptr->parent; + t2 = t2->d_ptr->parent; + } + + // in case we have a common ancestor, we compare the immediate children in the ancestor's path. + // otherwise we compare the respective items' topLevelItems directly. + return qt_closestLeaf(p1, p2); +} + +/*! + Returns true if \a item2 is on top of \a item1. + The items dont need to be siblings. + + \internal +*/ +inline bool qt_closestItemLast(const QGraphicsItem *item1, const QGraphicsItem *item2) +{ + return qt_closestItemFirst(item2, item1); +} + +/*! \internal */ inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2) @@ -649,7 +714,7 @@ inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item /*! \internal */ -static inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2) +inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2) { return qt_closestLeaf(item2, item1); } /* diff --git a/src/gui/graphicsview/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp index b7a3962..64c51ad 100644 --- a/src/gui/graphicsview/qgraphicsproxywidget.cpp +++ b/src/gui/graphicsview/qgraphicsproxywidget.cpp @@ -57,6 +57,9 @@ #include <QtGui/qpainter.h> #include <QtGui/qstyleoption.h> #include <QtGui/qgraphicsview.h> +#include <QtGui/qlistview.h> +#include <QtGui/qlineedit.h> +#include <QtGui/qtextedit.h> QT_BEGIN_NAMESPACE @@ -86,7 +89,9 @@ QT_BEGIN_NAMESPACE of embedded widgets through creating a child proxy for each popup. This means that when an embedded QComboBox shows its popup list, a new QGraphicsProxyWidget is created automatically, embedding the popup, and - positioning it correctly. + positioning it correctly. This only works if the popup is child of the + embedded widget (for example QToolButton::setMenu() requires the QMenu instance + to be child of the QToolButton). \section1 Embedding a Widget with QGraphicsProxyWidget @@ -184,6 +189,7 @@ QT_BEGIN_NAMESPACE */ extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); +extern bool qt_tab_all_widgets; /*! \internal @@ -369,6 +375,7 @@ QVariant QGraphicsProxyWidgetPrivate::inputMethodQueryHelper(Qt::InputMethodQuer /*! \internal + Some of the logic is shared with QApplicationPrivate::focusNextPrevChild_helper */ QWidget *QGraphicsProxyWidgetPrivate::findFocusChild(QWidget *child, bool next) const { @@ -382,14 +389,16 @@ QWidget *QGraphicsProxyWidgetPrivate::findFocusChild(QWidget *child, bool next) child = next ? child->d_func()->focus_next : child->d_func()->focus_prev; if ((next && child == widget) || (!next && child == widget->d_func()->focus_prev)) { return 0; - } + } } QWidget *oldChild = child; + uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus; do { if (child->isEnabled() && child->isVisibleTo(widget) - && (child->focusPolicy() & Qt::TabFocus)) { + && (child->focusPolicy() & focus_flag == focus_flag) + && !(child->d_func()->extra && child->d_func()->extra->focus_proxy)) { return child; } child = next ? child->d_func()->focus_next : child->d_func()->focus_prev; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index fc8ce8a..c459d21 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -242,7 +242,6 @@ #include <QtGui/qstyleoption.h> #include <QtGui/qtooltip.h> #include <QtGui/qtransform.h> -#include <QtGui/qgesture.h> #include <QtGui/qinputcontext.h> #include <QtGui/qgraphicseffect.h> #include <private/qapplication_p.h> @@ -251,6 +250,14 @@ #include <private/qt_x11_p.h> #endif #include <private/qgraphicseffect_p.h> +#include <private/qgesturemanager_p.h> + +// #define GESTURE_DEBUG +#ifndef GESTURE_DEBUG +# define DEBUG if (0) qDebug +#else +# define DEBUG qDebug +#endif QT_BEGIN_NAMESPACE @@ -1052,6 +1059,14 @@ bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event) */ bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event) { + if (QGraphicsObject *object = item->toGraphicsObject()) { + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); + if (qAppPriv->gestureManager) { + if (qAppPriv->gestureManager->filterEvent(object, event)) + return true; + } + } + if (filterEvent(item, event)) return false; if (filterDescendantEvent(item, event)) @@ -3365,6 +3380,10 @@ bool QGraphicsScene::event(QEvent *event) case QEvent::TouchEnd: d->touchEventHandler(static_cast<QTouchEvent *>(event)); break; + case QEvent::Gesture: + case QEvent::GestureOverride: + d->gestureEventHandler(static_cast<QGestureEvent *>(event)); + break; default: return QObject::event(event); } @@ -5704,6 +5723,238 @@ void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel) dispatchHoverEvent(&hoverEvent); } +void QGraphicsScenePrivate::getGestureTargets(const QSet<QGesture *> &gestures, + QWidget *viewport, + QMap<Qt::GestureType, QGesture *> *conflictedGestures, + QList<QList<QGraphicsObject *> > *conflictedItems, + QHash<QGesture *, QGraphicsObject *> *normalGestures) +{ + foreach (QGesture *gesture, gestures) { + Qt::GestureType gestureType = gesture->gestureType(); + if (gesture->hasHotSpot()) { + QPoint screenPos = gesture->hotSpot().toPoint(); + QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport); + QList<QGraphicsObject *> result; + for (int j = 0; j < items.size(); ++j) { + QGraphicsObject *item = items.at(j)->toGraphicsObject(); + if (!item) + continue; + QGraphicsItemPrivate *d = item->QGraphicsItem::d_func(); + if (d->gestureContext.contains(gestureType)) { + result.append(item); + } + } + DEBUG() << "QGraphicsScenePrivate::getGestureTargets:" + << gesture << result; + if (result.size() == 1) { + normalGestures->insert(gesture, result.first()); + } else if (!result.isEmpty()) { + conflictedGestures->insert(gestureType, gesture); + conflictedItems->append(result); + } + } + } +} + +void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event) +{ + QWidget *viewport = event->widget(); + if (!viewport) + return; + QList<QGesture *> allGestures = event->allGestures(); + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" + << "Delivering gestures:" << allGestures; + + typedef QHash<QGraphicsObject *, QList<QGesture *> > GesturesPerItem; + GesturesPerItem gesturesPerItem; + + QSet<QGesture *> startedGestures; + foreach (QGesture *gesture, allGestures) { + QGraphicsObject *target = gestureTargets.value(gesture, 0); + if (!target) { + // when we are not in started mode but don't have a target + // then the only one interested in gesture is the view/scene + if (gesture->state() == Qt::GestureStarted) + startedGestures.insert(gesture); + } else { + gesturesPerItem[target].append(gesture); + } + } + + QMap<Qt::GestureType, QGesture *> conflictedGestures; + QList<QList<QGraphicsObject *> > conflictedItems; + QHash<QGesture *, QGraphicsObject *> normalGestures; + getGestureTargets(startedGestures, viewport, &conflictedGestures, &conflictedItems, + &normalGestures); + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" + << "Conflicting gestures:" << conflictedGestures.values() << conflictedItems; + Q_ASSERT((conflictedGestures.isEmpty() && conflictedItems.isEmpty()) || + (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty())); + + // gestures that were sent as override events, but no one accepted them + QHash<QGesture *, QGraphicsObject *> ignoredConflictedGestures; + + // deliver conflicted gestures as override events first + while (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()) { + // get the topmost item to deliver the override event + Q_ASSERT(!conflictedItems.isEmpty()); + Q_ASSERT(!conflictedItems.first().isEmpty()); + QGraphicsObject *topmost = conflictedItems.first().first(); + for (int i = 1; i < conflictedItems.size(); ++i) { + QGraphicsObject *item = conflictedItems.at(i).first(); + if (qt_closestItemFirst(item, topmost)) { + topmost = item; + } + } + // get a list of gestures to send to the item + QList<Qt::GestureType> grabbedGestures = + topmost->QGraphicsItem::d_func()->gestureContext.keys(); + QList<QGesture *> gestures; + for (int i = 0; i < grabbedGestures.size(); ++i) { + if (QGesture *g = conflictedGestures.value(grabbedGestures.at(i), 0)) { + gestures.append(g); + if (!ignoredConflictedGestures.contains(g)) + ignoredConflictedGestures.insert(g, topmost); + } + } + + // send gesture override to the topmost item + QGestureEvent ev(gestures); + ev.t = QEvent::GestureOverride; + ev.setWidget(event->widget()); + // mark event and individual gestures as ignored + ev.ignore(); + foreach(QGesture *g, gestures) + ev.setAccepted(g, false); + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" + << "delivering override to" + << topmost << gestures; + sendEvent(topmost, &ev); + // mark all accepted gestures to deliver them as normal gesture events + foreach (QGesture *g, gestures) { + if (ev.isAccepted() || ev.isAccepted(g)) { + conflictedGestures.remove(g->gestureType()); + gestureTargets.remove(g); + // add the gesture to the list of normal delivered gestures + normalGestures.insert(g, topmost); + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" + << "override was accepted:" + << g << topmost; + ignoredConflictedGestures.remove(g); + } + } + // remove the item that we've already delivered from the list + for (int i = 0; i < conflictedItems.size(); ) { + QList<QGraphicsObject *> &items = conflictedItems[i]; + if (items.first() == topmost) { + items.removeFirst(); + if (items.isEmpty()) { + conflictedItems.removeAt(i); + continue; + } + } + ++i; + } + } + + // put back those started gestures that are not in the conflicted state + // and remember their targets + QHash<QGesture *, QGraphicsObject *>::const_iterator it = normalGestures.begin(), + e = normalGestures.end(); + for (; it != e; ++it) { + QGesture *g = it.key(); + QGraphicsObject *receiver = it.value(); + Q_ASSERT(!gestureTargets.contains(g)); + gestureTargets.insert(g, receiver); + gesturesPerItem[receiver].append(g); + } + it = ignoredConflictedGestures.begin(); + e = ignoredConflictedGestures.end(); + for (; it != e; ++it) { + QGesture *g = it.key(); + QGraphicsObject *receiver = it.value(); + Q_ASSERT(!gestureTargets.contains(g)); + gestureTargets.insert(g, receiver); + gesturesPerItem[receiver].append(g); + } + + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" + << "Started gestures:" << normalGestures.keys() + << "All gestures:" << gesturesPerItem.values(); + + // deliver all events + QList<QGesture *> alreadyIgnoredGestures; + QHash<QGraphicsObject *, QSet<QGesture *> > itemIgnoredGestures; + QList<QGraphicsObject *> targetItems = gesturesPerItem.keys(); + qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst); + for (int i = 0; i < targetItems.size(); ++i) { + QGraphicsObject *item = targetItems.at(i); + QList<QGesture *> gestures = gesturesPerItem.value(item); + // remove gestures that were already delivered once and were ignored + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" + << "already ignored gestures for item" + << item << ":" << itemIgnoredGestures.value(item); + + if (itemIgnoredGestures.contains(item)) // don't deliver twice to the same item + continue; + + QGraphicsItemPrivate *gid = item->QGraphicsItem::d_func(); + foreach(QGesture *g, alreadyIgnoredGestures) { + if (gid->gestureContext.contains(g->gestureType())) + gestures += g; + } + if (gestures.isEmpty()) + continue; + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" + << "delivering to" + << item << gestures; + QGestureEvent ev(gestures); + ev.setWidget(event->widget()); + sendEvent(item, &ev); + QSet<QGesture *> ignoredGestures; + foreach (QGesture *g, gestures) { + if (!ev.isAccepted() && !ev.isAccepted(g)) + ignoredGestures.insert(g); + } + if (!ignoredGestures.isEmpty()) { + // get a list of items under the (current) hotspot of each ignored + // gesture and start delivery again from the beginning + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" + << "item has ignored the event, will propagate." + << item << ignoredGestures; + itemIgnoredGestures[item] += ignoredGestures; + QMap<Qt::GestureType, QGesture *> conflictedGestures; + QList<QList<QGraphicsObject *> > itemsForConflictedGestures; + QHash<QGesture *, QGraphicsObject *> normalGestures; + getGestureTargets(ignoredGestures, viewport, + &conflictedGestures, &itemsForConflictedGestures, + &normalGestures); + QSet<QGraphicsObject *> itemsSet = targetItems.toSet(); + for (int k = 0; k < itemsForConflictedGestures.size(); ++k) + itemsSet += itemsForConflictedGestures.at(k).toSet(); + targetItems = itemsSet.toList(); + qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst); + alreadyIgnoredGestures = conflictedGestures.values(); + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" + << "new targets:" << targetItems; + i = -1; // start delivery again + continue; + } + } + + // forget about targets for gestures that have ended + foreach (QGesture *g, allGestures) { + switch (g->state()) { + case Qt::GestureFinished: + case Qt::GestureCanceled: + gestureTargets.remove(g); + break; + default: + break; + } + } +} + QT_END_NAMESPACE #include "moc_qgraphicsscene.cpp" diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 8073695..cd20fd0 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -282,6 +282,13 @@ public: bool allItemsIgnoreTouchEvents; void enableTouchEventsOnViews(); + QHash<QGesture *, QGraphicsObject *> gestureTargets; + void gestureEventHandler(QGestureEvent *event); + void getGestureTargets(const QSet<QGesture *> &gestures, QWidget *viewport, + QMap<Qt::GestureType, QGesture *> *conflictedGestures, + QList<QList<QGraphicsObject *> > *conflictedItems, + QHash<QGesture *, QGraphicsObject *> *normalGestures); + void updateInputMethodSensitivityInViews(); QList<QGraphicsItem *> modalPanels; diff --git a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp index e21183a..47ae3f1 100644 --- a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp +++ b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp @@ -405,70 +405,6 @@ QList<QGraphicsItem *> QGraphicsSceneBspTreeIndexPrivate::estimateItems(const QR } /*! - Returns true if \a item1 is on top of \a item2. - - \internal -*/ -bool QGraphicsSceneBspTreeIndexPrivate::closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2) -{ - // Siblings? Just check their z-values. - const QGraphicsItemPrivate *d1 = item1->d_ptr.data(); - const QGraphicsItemPrivate *d2 = item2->d_ptr.data(); - if (d1->parent == d2->parent) - return qt_closestLeaf(item1, item2); - - // Find common ancestor, and each item's ancestor closest to the common - // ancestor. - int item1Depth = d1->depth(); - int item2Depth = d2->depth(); - const QGraphicsItem *p = item1; - const QGraphicsItem *t1 = item1; - while (item1Depth > item2Depth && (p = p->d_ptr->parent)) { - if (p == item2) { - // item2 is one of item1's ancestors; item1 is on top - return !(t1->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent); - } - t1 = p; - --item1Depth; - } - p = item2; - const QGraphicsItem *t2 = item2; - while (item2Depth > item1Depth && (p = p->d_ptr->parent)) { - if (p == item1) { - // item1 is one of item2's ancestors; item1 is not on top - return (t2->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent); - } - t2 = p; - --item2Depth; - } - - // item1Ancestor is now at the same level as item2Ancestor, but not the same. - const QGraphicsItem *a1 = t1; - const QGraphicsItem *a2 = t2; - while (a1) { - const QGraphicsItem *p1 = a1; - const QGraphicsItem *p2 = a2; - a1 = a1->parentItem(); - a2 = a2->parentItem(); - if (a1 && a1 == a2) - return qt_closestLeaf(p1, p2); - } - - // No common ancestor? Then just compare the items' toplevels directly. - return qt_closestLeaf(t1->topLevelItem(), t2->topLevelItem()); -} - -/*! - Returns true if \a item2 is on top of \a item1. - - \internal -*/ -bool QGraphicsSceneBspTreeIndexPrivate::closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2) -{ - return closestItemFirst_withoutCache(item2, item1); -} - -/*! Sort a list of \a itemList in a specific \a order and use the cache if requested. \internal @@ -495,9 +431,9 @@ void QGraphicsSceneBspTreeIndexPrivate::sortItems(QList<QGraphicsItem *> *itemLi } } else { if (order == Qt::DescendingOrder) { - qSort(itemList->begin(), itemList->end(), closestItemFirst_withoutCache); + qSort(itemList->begin(), itemList->end(), qt_closestItemFirst); } else if (order == Qt::AscendingOrder) { - qSort(itemList->begin(), itemList->end(), closestItemLast_withoutCache); + qSort(itemList->begin(), itemList->end(), qt_closestItemLast); } } } diff --git a/src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h b/src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h index 0a86bb7..c130190 100644 --- a/src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h +++ b/src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h @@ -145,8 +145,6 @@ public: QList<QGraphicsItem *> estimateItems(const QRectF &, Qt::SortOrder, bool b = false); static void climbTree(QGraphicsItem *item, int *stackingOrder); - static bool closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2); - static bool closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2); static inline bool closestItemFirst_withCache(const QGraphicsItem *item1, const QGraphicsItem *item2) { diff --git a/src/gui/graphicsview/qgraphicstransform.cpp b/src/gui/graphicsview/qgraphicstransform.cpp index ec1a2f5..93dc196 100644 --- a/src/gui/graphicsview/qgraphicstransform.cpp +++ b/src/gui/graphicsview/qgraphicstransform.cpp @@ -547,7 +547,7 @@ void QGraphicsRotation::applyTo(QMatrix4x4 *matrix) const return; matrix->translate(d->origin); - matrix->rotate(d->angle, d->axis.x(), d->axis.y(), d->axis.z()); + matrix->projectedRotate(d->angle, d->axis.x(), d->axis.y(), d->axis.z()); matrix->translate(-d->origin); } diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 32747cc..710c745 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -2701,6 +2701,19 @@ bool QGraphicsView::viewportEvent(QEvent *event) return true; } + case QEvent::Gesture: + case QEvent::GestureOverride: + { + if (!isEnabled()) + return false; + + if (d->scene && d->sceneInteractionAllowed) { + QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(event); + gestureEvent->setWidget(viewport()); + (void) QApplication::sendEvent(d->scene, gestureEvent); + } + return true; + } default: break; } diff --git a/src/gui/itemviews/qheaderview.cpp b/src/gui/itemviews/qheaderview.cpp index fc9820f..3bd9a19 100644 --- a/src/gui/itemviews/qheaderview.cpp +++ b/src/gui/itemviews/qheaderview.cpp @@ -1419,7 +1419,7 @@ int QHeaderView::minimumSectionSize() const int margin = style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this); if (d->orientation == Qt::Horizontal) return qMax(strut.width(), (fontMetrics().maxWidth() + margin)); - return qMax(strut.height(), (fontMetrics().lineSpacing() + margin)); + return qMax(strut.height(), (fontMetrics().height() + margin)); } return d->minimumSectionSize; } diff --git a/src/gui/itemviews/qlistview.cpp b/src/gui/itemviews/qlistview.cpp index 1d9b6e0..f58f458 100644 --- a/src/gui/itemviews/qlistview.cpp +++ b/src/gui/itemviews/qlistview.cpp @@ -1900,7 +1900,7 @@ void QListModeViewBase::updateVerticalScrollBar(const QSize &step) if (verticalScrollMode() == QAbstractItemView::ScrollPerItem && ((flow() == QListView::TopToBottom && !isWrapping()) || (flow() == QListView::LeftToRight && isWrapping()))) { - const int steps = (flow() == QListView::TopToBottom ? flowPositions : segmentPositions).count() - 1; + const int steps = (flow() == QListView::TopToBottom ? scrollValueMap : segmentPositions).count() - 1; if (steps > 0) { const int pageSteps = perItemScrollingPageSteps(viewport()->height(), contentsSize.height(), isWrapping()); verticalScrollBar()->setSingleStep(1); @@ -1921,7 +1921,7 @@ void QListModeViewBase::updateHorizontalScrollBar(const QSize &step) if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem && ((flow() == QListView::TopToBottom && isWrapping()) || (flow() == QListView::LeftToRight && !isWrapping()))) { - int steps = (flow() == QListView::TopToBottom ? segmentPositions : flowPositions).count() - 1; + int steps = (flow() == QListView::TopToBottom ? segmentPositions : scrollValueMap).count() - 1; if (steps > 0) { const int pageSteps = perItemScrollingPageSteps(viewport()->width(), contentsSize.width(), isWrapping()); horizontalScrollBar()->setSingleStep(1); @@ -1939,7 +1939,11 @@ int QListModeViewBase::verticalScrollToValue(int index, QListView::ScrollHint hi bool above, bool below, const QRect &area, const QRect &rect) const { if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) { - int value = qBound(0, verticalScrollBar()->value(), flowPositions.count() - 1); + int value; + if (scrollValueMap.isEmpty()) + value = 0; + else + value = qBound(0, scrollValueMap.at(verticalScrollBar()->value()), flowPositions.count() - 1); if (above) hint = QListView::PositionAtTop; else if (below) @@ -1966,8 +1970,8 @@ int QListModeViewBase::horizontalOffset() const return (isRightToLeft() ? maximum - position : position); } } else if (flow() == QListView::LeftToRight && !flowPositions.isEmpty()) { - int position = flowPositions.at(horizontalScrollBar()->value()); - int maximum = flowPositions.at(horizontalScrollBar()->maximum()); + int position = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->value())); + int maximum = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->maximum())); return (isRightToLeft() ? maximum - position : position); } } @@ -1986,9 +1990,9 @@ int QListModeViewBase::verticalOffset() const } } else if (flow() == QListView::TopToBottom && !flowPositions.isEmpty()) { int value = verticalScrollBar()->value(); - if (value > flowPositions.count()) + if (value > scrollValueMap.count()) return 0; - return flowPositions.at(value) - spacing(); + return flowPositions.at(scrollValueMap.at(value)) - spacing(); } } return QCommonListViewBase::verticalOffset(); @@ -2000,7 +2004,11 @@ int QListModeViewBase::horizontalScrollToValue(int index, QListView::ScrollHint if (horizontalScrollMode() != QAbstractItemView::ScrollPerItem) return QCommonListViewBase::horizontalScrollToValue(index, hint, leftOf, rightOf, area, rect); - int value = qBound(0, horizontalScrollBar()->value(), flowPositions.count() - 1); + int value; + if (scrollValueMap.isEmpty()) + value = 0; + else + value = qBound(0, scrollValueMap.at(horizontalScrollBar()->value()), flowPositions.count() - 1); if (leftOf) hint = QListView::PositionAtTop; else if (rightOf) @@ -2043,14 +2051,14 @@ void QListModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand) if (vertical && flow() == QListView::TopToBottom && dy != 0) { int currentValue = qBound(0, verticalValue, max); int previousValue = qBound(0, currentValue + dy, max); - int currentCoordinate = flowPositions.at(currentValue); - int previousCoordinate = flowPositions.at(previousValue); + int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue)); + int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue)); dy = previousCoordinate - currentCoordinate; } else if (horizontal && flow() == QListView::LeftToRight && dx != 0) { int currentValue = qBound(0, horizontalValue, max); int previousValue = qBound(0, currentValue + dx, max); - int currentCoordinate = flowPositions.at(currentValue); - int previousCoordinate = flowPositions.at(previousValue); + int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue)); + int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue)); dx = previousCoordinate - currentCoordinate; } } @@ -2113,6 +2121,7 @@ QPoint QListModeViewBase::initStaticLayout(const QListViewLayoutInfo &info) segmentPositions.clear(); segmentStartRows.clear(); segmentExtents.clear(); + scrollValueMap.clear(); x = info.bounds.left() + info.spacing; y = info.bounds.top() + info.spacing; segmentPositions.append(info.flow == QListView::LeftToRight ? y : x); @@ -2204,6 +2213,7 @@ void QListModeViewBase::doStaticLayout(const QListViewLayoutInfo &info) deltaSegPosition = 0; } // save the flow position of this item + scrollValueMap.append(flowPositions.count()); flowPositions.append(flowPosition); // prepare for the next item deltaSegPosition = qMax(deltaSegHint, deltaSegPosition); @@ -2229,6 +2239,7 @@ void QListModeViewBase::doStaticLayout(const QListViewLayoutInfo &info) // if it is the last batch, save the end of the segments if (info.last == info.max) { segmentExtents.append(flowPosition); + scrollValueMap.append(flowPositions.count()); flowPositions.append(flowPosition); segmentPositions.append(info.wrap ? segPosition + deltaSegPosition : INT_MAX); } @@ -2306,7 +2317,14 @@ QRect QListModeViewBase::mapToViewport(const QRect &rect) const int QListModeViewBase::perItemScrollingPageSteps(int length, int bounds, bool wrap) const { - const QVector<int> positions = (wrap ? segmentPositions : flowPositions); + QVector<int> positions; + if (wrap) + positions = segmentPositions; + else if (!flowPositions.isEmpty()) { + positions.reserve(scrollValueMap.size()); + foreach (int itemShown, scrollValueMap) + positions.append(flowPositions.at(itemShown)); + } if (positions.isEmpty() || bounds <= length) return positions.count(); if (uniformItemSizes()) { diff --git a/src/gui/itemviews/qlistview_p.h b/src/gui/itemviews/qlistview_p.h index b6785da..de4c7f3 100644 --- a/src/gui/itemviews/qlistview_p.h +++ b/src/gui/itemviews/qlistview_p.h @@ -205,6 +205,7 @@ public: QVector<int> segmentPositions; QVector<int> segmentStartRows; QVector<int> segmentExtents; + QVector<int> scrollValueMap; // used when laying out in batches int batchSavedPosition; diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index 210534e..f37d8c7 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -2908,6 +2908,8 @@ void QTreeViewPrivate::expand(int item, bool emitSignal) layout(item); q->setState(oldState); + if (model->canFetchMore(index)) + model->fetchMore(index); if (emitSignal) { emit q->expanded(index); #ifndef QT_NO_ANIMATION @@ -2915,8 +2917,6 @@ void QTreeViewPrivate::expand(int item, bool emitSignal) beginAnimatedOperation(); #endif //QT_NO_ANIMATION } - if (model->canFetchMore(index)) - model->fetchMore(index); } void QTreeViewPrivate::collapse(int item, bool emitSignal) @@ -3005,10 +3005,12 @@ void QTreeViewPrivate::beginAnimatedOperation() animatedOperation.setEndValue(animatedOperation.top() + h); } - animatedOperation.after = renderTreeToPixmapForAnimation(rect); + if (!rect.isEmpty()) { + animatedOperation.after = renderTreeToPixmapForAnimation(rect); - q->setState(QAbstractItemView::AnimatingState); - animatedOperation.start(); //let's start the animation + q->setState(QAbstractItemView::AnimatingState); + animatedOperation.start(); //let's start the animation + } } void QTreeViewPrivate::drawAnimatedOperation(QPainter *painter) const diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 53c2611..8859358 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -84,6 +84,7 @@ SOURCES += \ kernel/qgesturerecognizer.cpp \ kernel/qgesturemanager.cpp \ kernel/qsoftkeymanager.cpp \ + kernel/qdesktopwidget.cpp \ kernel/qguiplatformplugin.cpp win32 { diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index f48c551..7c38d4b 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -2495,6 +2495,7 @@ void QApplication::setActiveWindow(QWidget* act) /*!internal * Helper function that returns the new focus widget, but does not set the focus reason. * Returns 0 if a new focus widget could not be found. + * Shared with QGraphicsProxyWidgetPrivate::findFocusChild() */ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool next) { @@ -3638,8 +3639,13 @@ bool QApplication::notify(QObject *receiver, QEvent *e) // walk through parents and check for gestures if (d->gestureManager) { - if (d->gestureManager->filterEvent(receiver, e)) - return true; + if (receiver->isWidgetType()) { + if (d->gestureManager->filterEvent(static_cast<QWidget *>(receiver), e)) + return true; + } else if (QGesture *gesture = qobject_cast<QGesture *>(receiver)) { + if (d->gestureManager->filterEvent(gesture, e)) + return true; + } } @@ -4164,40 +4170,41 @@ bool QApplication::notify(QObject *receiver, QEvent *e) if (wd->gestureContext.contains(type)) { allGestures.removeAt(i); gestures.append(g); - gestureEvent->setAccepted(g, false); } else { ++i; } } - if (!gestures.isEmpty()) { + if (!gestures.isEmpty()) { // we have gestures for this w QGestureEvent ge(gestures); ge.t = gestureEvent->t; ge.spont = gestureEvent->spont; ge.m_accept = wasAccepted; + ge.d_func()->accepted = gestureEvent->d_func()->accepted; res = d->notify_helper(w, &ge); gestureEvent->spont = false; eventAccepted = ge.isAccepted(); - if (res && eventAccepted) - break; - if (!eventAccepted) { - // ### two ways to ignore the event/gesture - - // if the whole event wasn't accepted, put back those - // gestures that were not accepted. - for (int i = 0; i < gestures.size(); ++i) { - QGesture *g = gestures.at(i); - if (!ge.isAccepted(g)) - allGestures.append(g); + for (int i = 0; i < gestures.size(); ++i) { + QGesture *g = gestures.at(i); + if ((res && eventAccepted) || (!eventAccepted && ge.isAccepted(g))) { + // if the gesture was accepted, mark the target widget for it + gestureEvent->d_func()->targetWidgets[g->gestureType()] = w; + gestureEvent->setAccepted(g, true); + } else if (!eventAccepted && !ge.isAccepted(g)) { + // if the gesture was explicitly ignored by the application, + // put it back so a parent can get it + allGestures.append(g); } } } - if (allGestures.isEmpty()) + if (allGestures.isEmpty()) // everything delivered break; if (w->isWindow()) break; w = w->parentWidget(); } - gestureEvent->m_accept = eventAccepted; + foreach (QGesture *g, allGestures) + gestureEvent->setAccepted(g, false); + gestureEvent->m_accept = false; // to make sure we check individual gestures } else { res = d->notify_helper(receiver, e); } diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 5bb25fa..e84985e 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -615,6 +615,8 @@ static void qt_set_windows_font_resources() if (qt_wince_is_mobile()) { smallerFont.setPointSize(systemFont.pointSize()-1); QApplication::setFont(smallerFont, "QTabBar"); + smallerFont.setBold(true); + QApplication::setFont(smallerFont, "QAbstractButton"); } #endif// Q_WS_WINCE } diff --git a/src/gui/kernel/qdesktopwidget.cpp b/src/gui/kernel/qdesktopwidget.cpp new file mode 100644 index 0000000..b1e1008 --- /dev/null +++ b/src/gui/kernel/qdesktopwidget.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglobal.h" + +QT_BEGIN_NAMESPACE + +#include "qdesktopwidget.h" +#include "qwidget_p.h" + +const QRect QDesktopWidget::screenGeometry(const QWidget *widget) const +{ + QRect rect = QWidgetPrivate::screenGeometry(widget); + if (rect.isNull()) + return screenGeometry(screenNumber(widget)); + else return rect; +} + +const QRect QDesktopWidget::availableGeometry(const QWidget *widget) const +{ + QRect rect = QWidgetPrivate::screenGeometry(widget); + if (rect.isNull()) + return availableGeometry(screenNumber(widget)); + else + return rect; +} + +QT_END_NAMESPACE + diff --git a/src/gui/kernel/qdesktopwidget.h b/src/gui/kernel/qdesktopwidget.h index 85f479e..6e3447c 100644 --- a/src/gui/kernel/qdesktopwidget.h +++ b/src/gui/kernel/qdesktopwidget.h @@ -75,14 +75,12 @@ public: QWidget *screen(int screen = -1); const QRect screenGeometry(int screen = -1) const; - const QRect screenGeometry(const QWidget *widget) const - { return screenGeometry(screenNumber(widget)); } + const QRect screenGeometry(const QWidget *widget) const; const QRect screenGeometry(const QPoint &point) const { return screenGeometry(screenNumber(point)); } const QRect availableGeometry(int screen = -1) const; - const QRect availableGeometry(const QWidget *widget) const - { return availableGeometry(screenNumber(widget)); } + const QRect availableGeometry(const QWidget *widget) const; const QRect availableGeometry(const QPoint &point) const { return availableGeometry(screenNumber(point)); } diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 2ff6d65..065bd09 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -45,6 +45,7 @@ #include "private/qapplication_p.h" #include "private/qkeysequence_p.h" #include "qwidget.h" +#include "qgraphicsview.h" #include "qdebug.h" #include "qmime.h" #include "qdnd_p.h" @@ -4223,8 +4224,17 @@ QTouchEvent::TouchPoint &QTouchEvent::TouchPoint::operator=(const QTouchEvent::T Creates new QGestureEvent containing a list of \a gestures. */ QGestureEvent::QGestureEvent(const QList<QGesture *> &gestures) - : QEvent(QEvent::Gesture), gestures_(gestures) + : QEvent(QEvent::Gesture) { + d = reinterpret_cast<QEventPrivate *>(new QGestureEventPrivate(gestures)); +} + +/*! + Destroys QGestureEvent. +*/ +QGestureEvent::~QGestureEvent() +{ + delete reinterpret_cast<QGestureEventPrivate *>(d); } /*! @@ -4232,7 +4242,7 @@ QGestureEvent::QGestureEvent(const QList<QGesture *> &gestures) */ QList<QGesture *> QGestureEvent::allGestures() const { - return gestures_; + return d_func()->gestures; } /*! @@ -4240,9 +4250,10 @@ QList<QGesture *> QGestureEvent::allGestures() const */ QGesture *QGestureEvent::gesture(Qt::GestureType type) const { - for(int i = 0; i < gestures_.size(); ++i) - if (gestures_.at(i)->gestureType() == type) - return gestures_.at(i); + const QGestureEventPrivate *d = d_func(); + for(int i = 0; i < d->gestures.size(); ++i) + if (d->gestures.at(i)->gestureType() == type) + return d->gestures.at(i); return 0; } @@ -4251,7 +4262,7 @@ QGesture *QGestureEvent::gesture(Qt::GestureType type) const */ QList<QGesture *> QGestureEvent::activeGestures() const { - return gestures_; + return d_func()->gestures; } /*! @@ -4259,7 +4270,7 @@ QList<QGesture *> QGestureEvent::activeGestures() const */ QList<QGesture *> QGestureEvent::canceledGestures() const { - return gestures_; + return d_func()->gestures; } /*! @@ -4279,7 +4290,7 @@ void QGestureEvent::setAccepted(QGesture *gesture, bool value) { setAccepted(false); if (gesture) - gesture->d_func()->accept = value; + d_func()->accepted[gesture->gestureType()] = value; } /*! @@ -4315,7 +4326,56 @@ void QGestureEvent::ignore(QGesture *gesture) */ bool QGestureEvent::isAccepted(QGesture *gesture) const { - return gesture ? gesture->d_func()->accept : false; + return gesture ? d_func()->accepted.value(gesture->gestureType(), true) : false; +} + +/*! + Sets the widget for this event. +*/ +void QGestureEvent::setWidget(QWidget *widget) +{ + d_func()->widget = widget; +} + +/*! + Returns the widget on which the event occurred. +*/ +QWidget *QGestureEvent::widget() const +{ + return d_func()->widget; +} + +/*! + Returns the scene-local coordinates if the \a gesturePoint is inside a graphics view. + + \sa QPointF::isNull(). +*/ +QPointF QGestureEvent::mapToScene(const QPointF &gesturePoint) const +{ + QWidget *w = widget(); + if (w) // we get the viewport as widget, not the graphics view + w = w->parentWidget(); + QGraphicsView *view = qobject_cast<QGraphicsView*>(w); + if (view) { + return view->mapToScene(view->mapFromGlobal(gesturePoint.toPoint())); + } + return QPointF(); +} + +/*! + \internal +*/ +QGestureEventPrivate *QGestureEvent::d_func() +{ + return reinterpret_cast<QGestureEventPrivate *>(d); +} + +/*! + \internal +*/ +const QGestureEventPrivate *QGestureEvent::d_func() const +{ + return reinterpret_cast<const QGestureEventPrivate *>(d); } #ifdef Q_NO_USING_KEYWORD diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 3516222..b7370fd 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -820,10 +820,12 @@ protected: }; class QGesture; +class QGestureEventPrivate; class Q_GUI_EXPORT QGestureEvent : public QEvent { public: QGestureEvent(const QList<QGesture *> &gestures); + ~QGestureEvent(); QList<QGesture *> allGestures() const; QGesture *gesture(Qt::GestureType type) const; @@ -849,8 +851,17 @@ public: void ignore(QGesture *); bool isAccepted(QGesture *) const; + void setWidget(QWidget *widget); + QWidget *widget() const; + + QPointF mapToScene(const QPointF &gesturePoint) const; + private: - QList<QGesture *> gestures_; + QGestureEventPrivate *d_func(); + const QGestureEventPrivate *d_func() const; + + friend class QApplication; + friend class QGestureManager; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h index c7a4975..6e6ab01 100644 --- a/src/gui/kernel/qevent_p.h +++ b/src/gui/kernel/qevent_p.h @@ -150,6 +150,20 @@ public: #endif }; +class QGestureEventPrivate +{ +public: + inline QGestureEventPrivate(const QList<QGesture *> &list) + : gestures(list), widget(0) + { + } + + QList<QGesture *> gestures; + QWidget *widget; + QMap<Qt::GestureType, bool> accepted; + QMap<Qt::GestureType, QWidget *> targetWidgets; +}; + QT_END_NAMESPACE #endif // QEVENT_P_H diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp index fc8df49..ecdd661 100644 --- a/src/gui/kernel/qgesture.cpp +++ b/src/gui/kernel/qgesture.cpp @@ -129,6 +129,10 @@ QGesture::~QGesture() \brief The point that is used to find the receiver for the gesture event. + The hot-spot is a point in the global coordinate system, use + QWidget::mapFromGlobal() or QGestureEvent::mapToScene() to get a + local hot-spot. + If the hot-spot is not set, the targetObject is used as the receiver of the gesture event. */ @@ -154,16 +158,6 @@ Qt::GestureState QGesture::state() const return d_func()->state; } -QObject *QGesture::targetObject() const -{ - return d_func()->targetObject; -} - -void QGesture::setTargetObject(QObject *value) -{ - d_func()->targetObject = value; -} - QPointF QGesture::hotSpot() const { return d_func()->hotSpot; @@ -241,17 +235,17 @@ QPanGesture::QPanGesture(QObject *parent) d_func()->gestureType = Qt::PanGesture; } -QSizeF QPanGesture::totalOffset() const +QPointF QPanGesture::totalOffset() const { return d_func()->totalOffset; } -QSizeF QPanGesture::lastOffset() const +QPointF QPanGesture::lastOffset() const { return d_func()->lastOffset; } -QSizeF QPanGesture::offset() const +QPointF QPanGesture::offset() const { return d_func()->offset; } @@ -262,17 +256,17 @@ qreal QPanGesture::acceleration() const } -void QPanGesture::setTotalOffset(const QSizeF &value) +void QPanGesture::setTotalOffset(const QPointF &value) { d_func()->totalOffset = value; } -void QPanGesture::setLastOffset(const QSizeF &value) +void QPanGesture::setLastOffset(const QPointF &value) { d_func()->lastOffset = value; } -void QPanGesture::setOffset(const QSizeF &value) +void QPanGesture::setOffset(const QPointF &value) { d_func()->offset = value; } diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h index 02eb526..6469959 100644 --- a/src/gui/kernel/qgesture.h +++ b/src/gui/kernel/qgesture.h @@ -67,7 +67,6 @@ class Q_GUI_EXPORT QGesture : public QObject Q_PROPERTY(Qt::GestureType gestureType READ gestureType) Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot RESET unsetHotSpot) Q_PROPERTY(bool hasHotSpot READ hasHotSpot) - Q_PROPERTY(QObject* targetObject READ targetObject WRITE setTargetObject) public: explicit QGesture(QObject *parent = 0); @@ -77,9 +76,6 @@ public: Qt::GestureState state() const; - QObject *targetObject() const; - void setTargetObject(QObject *value); - QPointF hotSpot() const; void setHotSpot(const QPointF &value); bool hasHotSpot() const; @@ -100,22 +96,22 @@ class Q_GUI_EXPORT QPanGesture : public QGesture Q_OBJECT Q_DECLARE_PRIVATE(QPanGesture) - Q_PROPERTY(QSizeF totalOffset READ totalOffset WRITE setTotalOffset) - Q_PROPERTY(QSizeF lastOffset READ lastOffset WRITE setLastOffset) - Q_PROPERTY(QSizeF offset READ offset WRITE setOffset) + Q_PROPERTY(QPointF totalOffset READ totalOffset WRITE setTotalOffset) + Q_PROPERTY(QPointF lastOffset READ lastOffset WRITE setLastOffset) + Q_PROPERTY(QPointF offset READ offset WRITE setOffset) Q_PROPERTY(qreal acceleration READ acceleration WRITE setAcceleration) public: QPanGesture(QObject *parent = 0); - QSizeF totalOffset() const; - QSizeF lastOffset() const; - QSizeF offset() const; + QPointF totalOffset() const; + QPointF lastOffset() const; + QPointF offset() const; qreal acceleration() const; - void setTotalOffset(const QSizeF &value); - void setLastOffset(const QSizeF &value); - void setOffset(const QSizeF &value); + void setTotalOffset(const QPointF &value); + void setLastOffset(const QPointF &value); + void setOffset(const QPointF &value); void setAcceleration(qreal value); friend class QPanGestureRecognizer; diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h index 7f69a4e..975c0c9 100644 --- a/src/gui/kernel/qgesture_p.h +++ b/src/gui/kernel/qgesture_p.h @@ -68,7 +68,7 @@ class QGesturePrivate : public QObjectPrivate public: QGesturePrivate() : gestureType(Qt::CustomGesture), state(Qt::NoGesture), isHotSpotSet(false), - targetObject(0), accept(true) + targetObject(0) { } @@ -77,7 +77,6 @@ public: QPointF hotSpot; bool isHotSpotSet; QObject *targetObject; - bool accept; }; class QPanGesturePrivate : public QGesturePrivate @@ -90,9 +89,9 @@ public: { } - QSizeF totalOffset; - QSizeF lastOffset; - QSizeF offset; + QPointF totalOffset; + QPointF lastOffset; + QPointF offset; QPoint lastPosition; qreal acceleration; }; diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index 0f0aef2..ed8e744 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -44,6 +44,7 @@ #include "private/qwidget_p.h" #include "private/qgesture_p.h" #include "private/qgraphicsitem_p.h" +#include "private/qevent_p.h" #include "qgesture.h" #include "qevent.h" #include "qgraphicsitem.h" @@ -88,7 +89,8 @@ Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *r { QGesture *dummy = recognizer->createGesture(0); if (!dummy) { - qWarning("QGestureManager::registerGestureRecognizer: the recognizer doesn't provide gesture object"); + qWarning("QGestureManager::registerGestureRecognizer: " + "the recognizer fails to create a gesture object, skipping registration."); return Qt::GestureType(0); } Qt::GestureType type = dummy->gestureType(); @@ -107,7 +109,7 @@ void QGestureManager::unregisterGestureRecognizer(Qt::GestureType) } -QGesture* QGestureManager::getState(QObject *object, Qt::GestureType type) +QGesture *QGestureManager::getState(QObject *object, Qt::GestureType type) { // if the widget is being deleted we should be carefull and not to // create a new state, as it will create QWeakPointer which doesnt work @@ -115,28 +117,39 @@ QGesture* QGestureManager::getState(QObject *object, Qt::GestureType type) if (object->isWidgetType()) { if (static_cast<QWidget *>(object)->d_func()->data.in_destructor) return 0; + } else if (QGesture *g = qobject_cast<QGesture *>(object)) { + return g; + } else { + Q_ASSERT(qobject_cast<QGraphicsObject *>(object)); } - QWeakPointer<QGesture> state = objectGestures.value(QGestureManager::ObjectGesture(object, type)); + QGesture *state = + objectGestures.value(QGestureManager::ObjectGesture(object, type)); if (!state) { QGestureRecognizer *recognizer = recognizers.value(type); if (recognizer) { state = recognizer->createGesture(object); if (!state) return 0; - if (state.data()->gestureType() == Qt::CustomGesture) { + if (state->gestureType() == Qt::CustomGesture) { // if the recognizer didn't fill in the gesture type, then this // is a custom gesture with autogenerated it and we fill it. - state.data()->d_func()->gestureType = type; + state->d_func()->gestureType = type; +#if defined(GESTURE_DEBUG) + state->setObjectName(QString::number((int)type)); +#endif } objectGestures.insert(QGestureManager::ObjectGesture(object, type), state); - gestureToRecognizer[state.data()] = recognizer; + gestureToRecognizer[state] = recognizer; + gestureOwners[state] = object; } } - return state.data(); + return state; } -bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) +bool QGestureManager::filterEventThroughContexts(const QMap<QObject *, + Qt::GestureType> &contexts, + QEvent *event) { QSet<QGesture *> triggeredGestures; QSet<QGesture *> finishedGestures; @@ -144,93 +157,23 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) QSet<QGesture *> canceledGestures; QSet<QGesture *> notGestures; - QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(receiver); - if (receiver->isWidgetType() || graphicsObject) { - QMap<QObject *, Qt::GestureType> contexts; - if (receiver->isWidgetType()) { - QWidget *w = static_cast<QWidget *>(receiver); - if (!w->d_func()->gestureContext.isEmpty()) { - typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; - for(ContextIterator it = w->d_func()->gestureContext.begin(), - e = w->d_func()->gestureContext.end(); it != e; ++it) { - contexts.insertMulti(w, it.key()); - } - } - // find all gesture contexts for the widget tree - w = w->parentWidget(); - while (w) - { - typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; - for (ContextIterator it = w->d_func()->gestureContext.begin(), - e = w->d_func()->gestureContext.end(); it != e; ++it) { - if (it.value() == Qt::WidgetWithChildrenGesture) - contexts.insertMulti(w, it.key()); - } - w = w->parentWidget(); - } - } else { - QGraphicsObject *item = graphicsObject; - if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) { - typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; - for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), - e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { - contexts.insertMulti(item, it.key()); - } - } - // find all gesture contexts for the widget tree - item = item->parentObject(); - while (item) - { - typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; - for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), - e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { - if (it.value() == Qt::WidgetWithChildrenGesture) - contexts.insertMulti(item, it.key()); - } - item = item->parentObject(); - } - } - // filter the event through recognizers - typedef QMap<QObject *, Qt::GestureType>::const_iterator ContextIterator; - for (ContextIterator cit = contexts.begin(), ce = contexts.end(); cit != ce; ++cit) { - Qt::GestureType gestureType = cit.value(); - QMap<Qt::GestureType, QGestureRecognizer *>::const_iterator - rit = recognizers.lowerBound(gestureType), - re = recognizers.upperBound(gestureType); - for (; rit != re; ++rit) { - QGestureRecognizer *recognizer = rit.value(); - QObject *target = cit.key(); - QGesture *state = getState(target, gestureType); - if (!state) - continue; - QGestureRecognizer::Result result = recognizer->filterEvent(state, target, event); - QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask; - if (type == QGestureRecognizer::GestureTriggered) { - DEBUG() << "QGestureManager: gesture triggered: " << state; - triggeredGestures << state; - } else if (type == QGestureRecognizer::GestureFinished) { - DEBUG() << "QGestureManager: gesture finished: " << state; - finishedGestures << state; - } else if (type == QGestureRecognizer::MaybeGesture) { - DEBUG() << "QGestureManager: maybe gesture: " << state; - newMaybeGestures << state; - } else if (type == QGestureRecognizer::NotGesture) { - DEBUG() << "QGestureManager: not gesture: " << state; - notGestures << state; - } else if (type == QGestureRecognizer::Ignore) { - DEBUG() << "QGestureManager: gesture ignored the event: " << state; - } else { - DEBUG() << "QGestureManager: hm, lets assume the recognizer ignored the event: " << state; - } - if (result & QGestureRecognizer::ConsumeEventHint) { - DEBUG() << "QGestureManager: we were asked to consume the event: " << state; - //TODO: consume events if asked - } - } - } - } else if (QGesture *state = qobject_cast<QGesture*>(receiver)) { - if (QGestureRecognizer *recognizer = gestureToRecognizer.value(state)) { - QGestureRecognizer::Result result = recognizer->filterEvent(state, state, event); + // TODO: sort contexts by the gesture type and check if one of the contexts + // is already active. + + // filter the event through recognizers + typedef QMap<QObject *, Qt::GestureType>::const_iterator ContextIterator; + for (ContextIterator cit = contexts.begin(), ce = contexts.end(); cit != ce; ++cit) { + Qt::GestureType gestureType = cit.value(); + QMap<Qt::GestureType, QGestureRecognizer *>::const_iterator + rit = recognizers.lowerBound(gestureType), + re = recognizers.upperBound(gestureType); + for (; rit != re; ++rit) { + QGestureRecognizer *recognizer = rit.value(); + QObject *target = cit.key(); + QGesture *state = getState(target, gestureType); + if (!state) + continue; + QGestureRecognizer::Result result = recognizer->filterEvent(state, target, event); QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask; if (type == QGestureRecognizer::GestureTriggered) { DEBUG() << "QGestureManager: gesture triggered: " << state; @@ -247,11 +190,15 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) } else if (type == QGestureRecognizer::Ignore) { DEBUG() << "QGestureManager: gesture ignored the event: " << state; } else { - DEBUG() << "QGestureManager: hm, lets assume the recognizer ignored the event: " << state; + DEBUG() << "QGestureManager: hm, lets assume the recognizer" + << "ignored the event: " << state; + } + if (result & QGestureRecognizer::ConsumeEventHint) { + DEBUG() << "QGestureManager: we were asked to consume the event: " + << state; + //TODO: consume events if asked } } - } else { - return false; } QSet<QGesture *> startedGestures = triggeredGestures - activeGestures; @@ -260,7 +207,8 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) // check if a running gesture switched back to maybe state QSet<QGesture *> activeToMaybeGestures = activeGestures & newMaybeGestures; - // check if a running gesture switched back to not gesture state, i.e. were canceled + // check if a running gesture switched back to not gesture state, + // i.e. were canceled QSet<QGesture *> activeToCancelGestures = activeGestures & notGestures; canceledGestures += activeToCancelGestures; @@ -271,7 +219,9 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) timer.start(3000, this); } // kill timers for gestures that were in maybe state - QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures | finishedGestures | canceledGestures | notGestures); + QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures + | finishedGestures | canceledGestures + | notGestures); foreach(QGesture *gesture, notMaybeGestures) { QMap<QGesture *, QBasicTimer>::iterator it = maybeGestures.find(gesture); @@ -294,7 +244,9 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) // probably those are "singleshot" gestures so we'll fake the started state. foreach (QGesture *gesture, notStarted) gesture->d_func()->state = Qt::GestureStarted; - deliverEvents(notStarted, receiver); + QSet<QGesture *> undeliveredGestures; + deliverEvents(notStarted, &undeliveredGestures); + finishedGestures -= undeliveredGestures; } activeGestures += startedGestures; @@ -328,10 +280,15 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) << "\n\tcanceled:" << canceledGestures; } - deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures, receiver); + QSet<QGesture *> undeliveredGestures; + deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures, + &undeliveredGestures); + + activeGestures -= undeliveredGestures; // reset gestures that ended - QSet<QGesture *> endedGestures = finishedGestures + canceledGestures; + QSet<QGesture *> endedGestures = + finishedGestures + canceledGestures + undeliveredGestures; foreach (QGesture *gesture, endedGestures) { if (QGestureRecognizer *recognizer = gestureToRecognizer.value(gesture, 0)) { recognizer->reset(gesture); @@ -341,100 +298,218 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) return false; } -void QGestureManager::deliverEvents(const QSet<QGesture*> &gestures, QObject *lastReceiver) +bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) +{ + QSet<Qt::GestureType> types; + QMap<QObject *, Qt::GestureType> contexts; + QWidget *w = receiver; + typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; + if (!w->d_func()->gestureContext.isEmpty()) { + for(ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + types.insert(it.key()); + contexts.insertMulti(w, it.key()); + } + } + // find all gesture contexts for the widget tree + w = w->isWindow() ? 0 : w->parentWidget(); + while (w) + { + for (ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + if (it.value() == Qt::WidgetWithChildrenGesture) { + if (!types.contains(it.key())) { + types.insert(it.key()); + contexts.insertMulti(w, it.key()); + } + } + } + if (w->isWindow()) + break; + w = w->parentWidget(); + } + return filterEventThroughContexts(contexts, event); +} + +bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event) +{ + QSet<Qt::GestureType> types; + QMap<QObject *, Qt::GestureType> contexts; + QGraphicsObject *item = receiver; + if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) { + typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; + for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + types.insert(it.key()); + contexts.insertMulti(item, it.key()); + } + } + // find all gesture contexts for the graphics object tree + item = item->parentObject(); + while (item) + { + typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; + for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + if (it.value() == Qt::ItemWithChildrenGesture) { + if (!types.contains(it.key())) + contexts.insertMulti(item, it.key()); + } + } + item = item->parentObject(); + } + return filterEventThroughContexts(contexts, event); +} + +bool QGestureManager::filterEvent(QGesture *state, QEvent *event) +{ + QMap<QObject *, Qt::GestureType> contexts; + contexts.insert(state, state->gestureType()); + return filterEventThroughContexts(contexts, event); +} + +void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures, + QMap<QWidget *, QList<QGesture *> > *conflicts, + QMap<QWidget *, QList<QGesture *> > *normal) +{ + typedef QHash<Qt::GestureType, QHash<QWidget *, QGesture *> > GestureByTypes; + GestureByTypes gestureByTypes; + + // sort gestures by types + foreach (QGesture *gesture, gestures) { + QWidget *receiver = gestureTargets.value(gesture, 0); + Q_ASSERT(receiver); + gestureByTypes[gesture->gestureType()].insert(receiver, gesture); + } + + // for each gesture type + foreach (Qt::GestureType type, gestureByTypes.keys()) { + QHash<QWidget *, QGesture *> gestures = gestureByTypes.value(type); + foreach (QWidget *widget, gestures.keys()) { + QWidget *w = widget->parentWidget(); + while (w) { + QMap<Qt::GestureType, Qt::GestureContext>::const_iterator it + = w->d_func()->gestureContext.find(type); + if (it != w->d_func()->gestureContext.end()) { + // i.e. 'w' listens to gesture 'type' + Qt::GestureContext context = it.value(); + if (context == Qt::WidgetWithChildrenGesture && w != widget) { + // conflicting gesture! + (*conflicts)[widget].append(gestures[widget]); + break; + } + } + if (w->isWindow()) { + w = 0; + break; + } + w = w->parentWidget(); + } + if (!w) + (*normal)[widget].append(gestures[widget]); + } + } +} + +void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures, + QSet<QGesture *> *undeliveredGestures) { if (gestures.isEmpty()) return; - // group gestures by widgets - typedef QMap<QObject *, QList<QGesture *> > GesturesPerReceiver; - GesturesPerReceiver groupedGestures; - // for conflicted gestures the key is always the innermost widget (i.e. the child) - GesturesPerReceiver conflictedGestures; - QMultiHash<QObject *, QGesture *> objectGestures; + typedef QMap<QWidget *, QList<QGesture *> > GesturesPerWidget; + GesturesPerWidget conflictedGestures; + GesturesPerWidget normalStartedGestures; - foreach (QGesture *gesture, gestures) { - QObject *target = gestureTargets.value(gesture, 0); + QSet<QGesture *> startedGestures; + // first figure out the initial receivers of gestures + for (QSet<QGesture *>::const_iterator it = gestures.begin(), + e = gestures.end(); it != e; ++it) { + QGesture *gesture = *it; + QWidget *target = gestureTargets.value(gesture, 0); if (!target) { + // the gesture has just started and doesn't have a target yet. Q_ASSERT(gesture->state() == Qt::GestureStarted); if (gesture->hasHotSpot()) { - // guess the target using the hotspot of the gesture + // guess the target widget using the hotspot of the gesture QPoint pt = gesture->hotSpot().toPoint(); - if (!pt.isNull()) { - if (QWidget *w = qApp->topLevelAt(pt)) - target = w->childAt(w->mapFromGlobal(pt)); + if (QWidget *w = qApp->topLevelAt(pt)) { + target = w->childAt(w->mapFromGlobal(pt)); } + } else { + // or use the context of the gesture + QObject *context = gestureOwners.value(gesture, 0); + if (context->isWidgetType()) + target = static_cast<QWidget *>(context); } - if (!target) { - target = gesture->targetObject(); - if (!target) - target = lastReceiver; - } + if (target) + gestureTargets.insert(gesture, target); } + + Qt::GestureType gestureType = gesture->gestureType(); + Q_ASSERT(gestureType != Qt::CustomGesture); + if (target) { - gestureTargets.insert(gesture, target); - if (target->isWidgetType()) - objectGestures.insert(target, gesture); - groupedGestures[target].append(gesture); + if (gesture->state() == Qt::GestureStarted) { + startedGestures.insert(gesture); + } else { + normalStartedGestures[target].append(gesture); + } } else { - qWarning() << "QGestureManager::deliverEvent: could not find the target for gesture" + DEBUG() << "QGestureManager::deliverEvent: could not find the target for gesture" << gesture->gestureType(); + qWarning("QGestureManager::deliverEvent: could not find the target for gesture"); + undeliveredGestures->insert(gesture); } } - typedef QMultiHash<QObject *, QGesture *>::const_iterator ObjectGesturesIterator; - for (ObjectGesturesIterator it = objectGestures.begin(), e = objectGestures.end(); it != e; ++it) { - QObject *object1 = it.key(); - QWidget *widget1 = qobject_cast<QWidget *>(object1); - QGraphicsObject *item1 = qobject_cast<QGraphicsObject *>(object1); - QGesture *gesture1 = it.value(); - ObjectGesturesIterator cit = it; - for (++cit; cit != e; ++cit) { - QObject *object2 = cit.key(); - QWidget *widget2 = qobject_cast<QWidget *>(object2); - QGraphicsObject *item2 = qobject_cast<QGraphicsObject *>(object2); - QGesture *gesture2 = cit.value(); - // TODO: ugly, rewrite this. - if ((widget1 && widget2 && widget2->isAncestorOf(widget1)) || - (item1 && item2 && item2->isAncestorOf(item1))) { - groupedGestures[object2].removeOne(gesture2); - groupedGestures[object1].removeOne(gesture1); - conflictedGestures[object1].append(gesture1); - } else if ((widget1 && widget2 && widget1->isAncestorOf(widget2)) || - (item1 && item2 && item1->isAncestorOf(item2))) { - groupedGestures[object2].removeOne(gesture2); - groupedGestures[object1].removeOne(gesture1); - conflictedGestures[object2].append(gesture2); - } - } - } - - DEBUG() << "deliverEvents: conflicted =" << conflictedGestures.values() - << " grouped =" << groupedGestures.values(); + getGestureTargets(startedGestures, &conflictedGestures, &normalStartedGestures); + DEBUG() << "QGestureManager::deliverEvents:" + << "\nstarted: " << startedGestures + << "\nconflicted: " << conflictedGestures + << "\nnormal: " << normalStartedGestures + << "\n"; // if there are conflicting gestures, send the GestureOverride event - for (GesturesPerReceiver::const_iterator it = conflictedGestures.begin(), + for (GesturesPerWidget::const_iterator it = conflictedGestures.begin(), e = conflictedGestures.end(); it != e; ++it) { + QWidget *receiver = it.key(); + QList<QGesture *> gestures = it.value(); DEBUG() << "QGestureManager::deliverEvents: sending GestureOverride to" - << it.key() - << " gestures:" << it.value(); - QGestureEvent event(it.value()); + << receiver + << "gestures:" << gestures; + QGestureEvent event(gestures); event.t = QEvent::GestureOverride; + // mark event and individual gestures as ignored event.ignore(); - QApplication::sendEvent(it.key(), &event); - if (!event.isAccepted()) { - // nobody accepted the GestureOverride, put it back to deliver to - // the closest context (i.e. to the inner-most widget). - DEBUG() <<" override was not accepted"; - groupedGestures[it.key()].append(it.value()); + foreach(QGesture *g, gestures) + event.setAccepted(g, false); + + QApplication::sendEvent(receiver, &event); + bool eventAccepted = event.isAccepted(); + foreach(QGesture *gesture, event.allGestures()) { + if (eventAccepted || event.isAccepted(gesture)) { + QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0); + Q_ASSERT(w); + DEBUG() << "override event: gesture was accepted:" << gesture << w; + QList<QGesture *> &gestures = normalStartedGestures[w]; + gestures.append(gesture); + // override the target + gestureTargets[gesture] = w; + } else { + DEBUG() << "override event: gesture wasn't accepted. putting back:" << gesture; + QList<QGesture *> &gestures = normalStartedGestures[receiver]; + gestures.append(gesture); + } } } - for (GesturesPerReceiver::const_iterator it = groupedGestures.begin(), - e = groupedGestures.end(); it != e; ++it) { + // delivering gestures that are not in conflicted state + for (GesturesPerWidget::const_iterator it = normalStartedGestures.begin(), + e = normalStartedGestures.end(); it != e; ++it) { if (!it.value().isEmpty()) { DEBUG() << "QGestureManager::deliverEvents: sending to" << it.key() - << " gestures:" << it.value(); + << "gestures:" << it.value(); QGestureEvent event(it.value()); QApplication::sendEvent(it.key(), &event); } @@ -452,7 +527,8 @@ void QGestureManager::timerEvent(QTimerEvent *event) timer.stop(); QGesture *gesture = it.key(); it = maybeGestures.erase(it); - DEBUG() << "QGestureManager::timerEvent: gesture stopped due to timeout:" << gesture; + DEBUG() << "QGestureManager::timerEvent: gesture stopped due to timeout:" + << gesture; QGestureRecognizer *recognizer = gestureToRecognizer.value(gesture, 0); if (recognizer) recognizer->reset(gesture); diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h index c61819f..f0e7225 100644 --- a/src/gui/kernel/qgesturemanager_p.h +++ b/src/gui/kernel/qgesturemanager_p.h @@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE class QBasicTimer; +class QGraphicsObject; class QGestureManager : public QObject { Q_OBJECT @@ -71,13 +72,17 @@ public: Qt::GestureType registerGestureRecognizer(QGestureRecognizer *recognizer); void unregisterGestureRecognizer(Qt::GestureType type); - bool filterEvent(QObject *receiver, QEvent *event); + bool filterEvent(QWidget *receiver, QEvent *event); + bool filterEvent(QGesture *receiver, QEvent *event); + bool filterEvent(QGraphicsObject *receiver, QEvent *event); // declared in qapplication.cpp static QGestureManager* instance(); protected: void timerEvent(QTimerEvent *event); + bool filterEventThroughContexts(const QMap<QObject *, Qt::GestureType> &contexts, + QEvent *event); private: QMultiMap<Qt::GestureType, QGestureRecognizer *> recognizers; @@ -109,15 +114,20 @@ private: } }; - QMap<ObjectGesture, QWeakPointer<QGesture> > objectGestures; + QMap<ObjectGesture, QGesture *> objectGestures; QMap<QGesture *, QGestureRecognizer *> gestureToRecognizer; + QHash<QGesture *, QObject *> gestureOwners; - QHash<QGesture *, QObject *> gestureTargets; + QHash<QGesture *, QWidget *> gestureTargets; int lastCustomGestureId; QGesture *getState(QObject *widget, Qt::GestureType gesture); - void deliverEvents(const QSet<QGesture *> &gestures, QObject *lastReceiver); + void deliverEvents(const QSet<QGesture *> &gestures, + QSet<QGesture *> *undeliveredGestures); + void getGestureTargets(const QSet<QGesture*> &gestures, + QMap<QWidget *, QList<QGesture *> > *conflicts, + QMap<QWidget *, QList<QGesture *> > *normal); }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesturerecognizer.cpp b/src/gui/kernel/qgesturerecognizer.cpp index 9de3bcc..ba3a750 100644 --- a/src/gui/kernel/qgesturerecognizer.cpp +++ b/src/gui/kernel/qgesturerecognizer.cpp @@ -186,7 +186,7 @@ void QGestureRecognizer::reset(QGesture *gesture) \fn QGestureRecognizer::filterEvent(QGesture *gesture, QObject *watched, QEvent *event) Handles the given \a event for the \a watched object, updating the state of the \a gesture - object as required, and returns a suitable Result for the current recognition step. + object as required, and returns a suitable result for the current recognition step. This function is called by the framework to allow the recognizer to filter input events dispatched to QWidget or QGraphicsObject instances that it is monitoring. diff --git a/src/gui/kernel/qmacgesturerecognizer_mac.mm b/src/gui/kernel/qmacgesturerecognizer_mac.mm index 7b19a54..7019580 100644 --- a/src/gui/kernel/qmacgesturerecognizer_mac.mm +++ b/src/gui/kernel/qmacgesturerecognizer_mac.mm @@ -218,7 +218,7 @@ QMacPanGestureRecognizer::filterEvent(QGesture *gesture, QObject *target, QEvent const QPointF p = QCursor::pos(); const QPointF posOffset = p - _lastPos; g->setLastOffset(g->offset()); - g->setOffset(QSizeF(posOffset.x(), posOffset.y())); + g->setOffset(QPointF(posOffset.x(), posOffset.y())); g->setTotalOffset(g->lastOffset() + g->offset()); _lastPos = p; return QGestureRecognizer::GestureTriggered; @@ -256,9 +256,9 @@ void QMacPanGestureRecognizer::reset(QGesture *gesture) _startPos = QPointF(); _lastPos = QPointF(); _panCanceled = true; - g->setOffset(QSizeF(0, 0)); - g->setLastOffset(QSizeF(0, 0)); - g->setTotalOffset(QSizeF(0, 0)); + g->setOffset(QPointF(0, 0)); + g->setLastOffset(QPointF(0, 0)); + g->setTotalOffset(QPointF(0, 0)); g->setAcceleration(qreal(1)); QGestureRecognizer::reset(gesture); } diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp index dfc3499..a136379 100644 --- a/src/gui/kernel/qstandardgestures.cpp +++ b/src/gui/kernel/qstandardgestures.cpp @@ -73,7 +73,7 @@ QGestureRecognizer::Result QPanGestureRecognizer::filterEvent(QGesture *state, Q result = QGestureRecognizer::MaybeGesture; QTouchEvent::TouchPoint p = ev->touchPoints().at(0); d->lastPosition = p.pos().toPoint(); - d->lastOffset = d->totalOffset = d->offset = QSize(); + d->lastOffset = d->totalOffset = d->offset = QPointF(); break; } case QEvent::TouchEnd: { @@ -83,7 +83,7 @@ QGestureRecognizer::Result QPanGestureRecognizer::filterEvent(QGesture *state, Q QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); d->lastOffset = d->offset; d->offset = - QSize(p1.pos().x() - p1.lastPos().x() + p2.pos().x() - p2.lastPos().x(), + QPointF(p1.pos().x() - p1.lastPos().x() + p2.pos().x() - p2.lastPos().x(), p1.pos().y() - p1.lastPos().y() + p2.pos().y() - p2.lastPos().y()) / 2; d->totalOffset += d->offset; } @@ -99,11 +99,11 @@ QGestureRecognizer::Result QPanGestureRecognizer::filterEvent(QGesture *state, Q QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); d->lastOffset = d->offset; d->offset = - QSize(p1.pos().x() - p1.lastPos().x() + p2.pos().x() - p2.lastPos().x(), + QPointF(p1.pos().x() - p1.lastPos().x() + p2.pos().x() - p2.lastPos().x(), p1.pos().y() - p1.lastPos().y() + p2.pos().y() - p2.lastPos().y()) / 2; d->totalOffset += d->offset; - if (d->totalOffset.width() > 10 || d->totalOffset.height() > 10 || - d->totalOffset.width() < -10 || d->totalOffset.height() < -10) { + if (d->totalOffset.x() > 10 || d->totalOffset.y() > 10 || + d->totalOffset.x() < -10 || d->totalOffset.y() < -10) { result = QGestureRecognizer::GestureTriggered; } else { result = QGestureRecognizer::MaybeGesture; @@ -128,7 +128,7 @@ void QPanGestureRecognizer::reset(QGesture *state) QPanGesture *pan = static_cast<QPanGesture*>(state); QPanGesturePrivate *d = pan->d_func(); - d->totalOffset = d->lastOffset = d->offset = QSizeF(); + d->totalOffset = d->lastOffset = d->offset = QPointF(); d->lastPosition = QPoint(); d->acceleration = 0; diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 088197e..5fa9a92 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -150,24 +150,6 @@ static inline bool hasBackingStoreSupport() #endif } -/*! - \internal - - Returns true if \a p or any of its parents enable the - Qt::BypassGraphicsProxyWidget window flag. Used in QWidget::show() and - QWidget::setParent() to determine whether it's necessary to embed the - widget into a QGraphicsProxyWidget or not. -*/ -static inline bool bypassGraphicsProxyWidget(QWidget *p) -{ - while (p) { - if (p->windowFlags() & Qt::BypassGraphicsProxyWidget) - return true; - p = p->parentWidget(); - } - return false; -} - #ifdef Q_WS_MAC # define QT_NO_PAINT_DEBUG #endif @@ -5509,6 +5491,7 @@ QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint * return pixmap; } +#ifndef QT_NO_GRAPHICSVIEW /*! \internal @@ -5517,7 +5500,7 @@ QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint * If successful, the function returns the proxy that embeds the widget, or 0 if no embedded widget was found. */ -QGraphicsProxyWidget * QWidgetPrivate::nearestGraphicsProxyWidget(QWidget *origin) +QGraphicsProxyWidget * QWidgetPrivate::nearestGraphicsProxyWidget(const QWidget *origin) { if (origin) { QWExtra *extra = origin->d_func()->extra; @@ -5527,6 +5510,7 @@ QGraphicsProxyWidget * QWidgetPrivate::nearestGraphicsProxyWidget(QWidget *origi } return 0; } +#endif /*! \property QWidget::locale @@ -7336,7 +7320,7 @@ void QWidget::setVisible(bool visible) break; parent = parent->parentWidget(); } - if (parent && !d->getOpaqueRegion().isEmpty()) + if (parent) parent->d_func()->setDirtyOpaqueRegion(); } @@ -7761,6 +7745,10 @@ void QWidget::adjustSize() Q_D(QWidget); ensurePolished(); QSize s = d->adjustedSize(); + + if (d->layout) + d->layout->activate(); + if (s.isValid()) resize(s); } diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 05c6a5b..d08f8a9 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -3048,6 +3048,7 @@ void QWidget::grabMouse() } } +#ifndef QT_NO_CURSOR void QWidget::grabMouse(const QCursor &) { if(isVisible() && !qt_nograb()) { @@ -3056,6 +3057,7 @@ void QWidget::grabMouse(const QCursor &) mac_mouse_grabber=this; } } +#endif void QWidget::releaseMouse() { diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index a109f32..159a3f2 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -63,7 +63,9 @@ #include "QtGui/qstyle.h" #include "QtGui/qapplication.h" #include <private/qgraphicseffect_p.h> - +#include "QtGui/qgraphicsproxywidget.h" +#include "QtGui/qgraphicsscene.h" +#include "QtGui/qgraphicsview.h" #include <private/qgesture_p.h> #ifdef Q_WS_WIN @@ -180,7 +182,9 @@ struct QWExtra { // Regular pointers (keep them together to avoid gaps on 64 bits architectures). void *glContext; // if the widget is hijacked by QGLWindowSurface QTLWExtra *topextra; // only useful for TLWs +#ifndef QT_NO_GRAPHICSVIEW QGraphicsProxyWidget *proxyWidget; // if the widget is embedded +#endif #ifndef QT_NO_CURSOR QCursor *curs; #endif @@ -235,6 +239,24 @@ struct QWExtra { #endif }; +/*! + \internal + + Returns true if \a p or any of its parents enable the + Qt::BypassGraphicsProxyWidget window flag. Used in QWidget::show() and + QWidget::setParent() to determine whether it's necessary to embed the + widget into a QGraphicsProxyWidget or not. +*/ +static inline bool bypassGraphicsProxyWidget(const QWidget *p) +{ + while (p) { + if (p->windowFlags() & Qt::BypassGraphicsProxyWidget) + return true; + p = p->parentWidget(); + } + return false; +} + class Q_GUI_EXPORT QWidgetPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QWidget) @@ -345,7 +367,9 @@ public: QPainter *beginSharedPainter(); bool endSharedPainter(); - static QGraphicsProxyWidget * nearestGraphicsProxyWidget(QWidget *origin); +#ifndef QT_NO_GRAPHICSVIEW + static QGraphicsProxyWidget * nearestGraphicsProxyWidget(const QWidget *origin); +#endif QWindowSurface *createDefaultWindowSurface(); QWindowSurface *createDefaultWindowSurface_sys(); void repaint_sys(const QRegion &rgn); @@ -443,6 +467,31 @@ public: void setModal_sys(); + // This is an helper function that return the available geometry for + // a widget and takes care is this one is in QGraphicsView. + // If the widget is not embed in a scene then the geometry available is + // null, we let QDesktopWidget decide for us. + static QRect screenGeometry(const QWidget *widget) + { + QRect screen; +#ifndef QT_NO_GRAPHICSVIEW + QGraphicsProxyWidget *ancestorProxy = widget->d_func()->nearestGraphicsProxyWidget(widget); + //It's embedded if it has an ancestor + if (ancestorProxy) { + if (!bypassGraphicsProxyWidget(widget)) { + // One view, let be smart and return the viewport rect then the popup is aligned + if (ancestorProxy->scene()->views().size() == 1) { + QGraphicsView *view = ancestorProxy->scene()->views().at(0); + screen = view->mapToScene(view->viewport()->rect()).boundingRect().toRect(); + } else { + screen = ancestorProxy->scene()->sceneRect().toRect(); + } + } + } +#endif + return screen; + } + inline void setRedirected(QPaintDevice *replacement, const QPoint &offset) { Q_ASSERT(q_func()->testAttribute(Qt::WA_WState_InPaintEvent)); diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index 2b11bec..fa12b0d 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -851,10 +851,13 @@ void QWidget::grabMouse() Q_ASSERT(testAttribute(Qt::WA_WState_Created)); SetCapture(effectiveWinId()); mouseGrb = this; +#ifndef QT_NO_CURSOR mouseGrbCur = new QCursor(mouseGrb->cursor()); +#endif } } +#ifndef QT_NO_CURSOR void QWidget::grabMouse(const QCursor &cursor) { if (!qt_nograb()) { @@ -868,6 +871,7 @@ void QWidget::grabMouse(const QCursor &cursor) mouseGrb = this; } } +#endif void QWidget::releaseMouse() { diff --git a/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp b/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp index 4619594..12d3058 100644 --- a/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp +++ b/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp @@ -97,11 +97,11 @@ QGestureRecognizer::Result QWinNativePanGestureRecognizer::filterEvent(QGesture return QGestureRecognizer::Ignore; } if (q->state() == Qt::NoGesture) { - d->lastOffset = d->totalOffset = d->offset = QSize(); + d->lastOffset = d->totalOffset = d->offset = QPointF(); } else { d->lastOffset = d->offset; - d->offset = QSize(ev->position.x() - d->lastPosition.x(), - ev->position.y() - d->lastPosition.y()); + d->offset = QPointF(ev->position.x() - d->lastPosition.x(), + ev->position.y() - d->lastPosition.y()); d->totalOffset += d->offset; } d->lastPosition = ev->position; @@ -114,7 +114,7 @@ void QWinNativePanGestureRecognizer::reset(QGesture *state) QPanGesture *pan = static_cast<QPanGesture*>(state); QPanGesturePrivate *d = pan->d_func(); - d->totalOffset = d->lastOffset = d->offset = QSizeF(); + d->totalOffset = d->lastOffset = d->offset = QPointF(); d->lastPosition = QPoint(); d->acceleration = 0; diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp index ed1b13d..5d624d8 100644 --- a/src/gui/math3d/qmatrix4x4.cpp +++ b/src/gui/math3d/qmatrix4x4.cpp @@ -58,6 +58,8 @@ QT_BEGIN_NAMESPACE \sa QVector3D, QGenericMatrix */ +static const qreal inv_dist_to_plane = 1. / 1024.; + /*! \fn QMatrix4x4::QMatrix4x4() @@ -1103,7 +1105,111 @@ QMatrix4x4& QMatrix4x4::rotate(qreal angle, qreal x, qreal y, qreal z) return *this; } -#ifndef QT_NO_VECTOR4D +/*! + \internal +*/ +QMatrix4x4& QMatrix4x4::projectedRotate(qreal angle, qreal x, qreal y, qreal z) +{ + // Used by QGraphicsRotation::applyTo() to perform a rotation + // and projection back to 2D in a single step. + if (angle == 0.0f) + return *this; + QMatrix4x4 m(1); // The "1" says to not load the identity. + qreal c, s, ic; + if (angle == 90.0f || angle == -270.0f) { + s = 1.0f; + c = 0.0f; + } else if (angle == -90.0f || angle == 270.0f) { + s = -1.0f; + c = 0.0f; + } else if (angle == 180.0f || angle == -180.0f) { + s = 0.0f; + c = -1.0f; + } else { + qreal a = angle * M_PI / 180.0f; + c = qCos(a); + s = qSin(a); + } + bool quick = false; + if (x == 0.0f) { + if (y == 0.0f) { + if (z != 0.0f) { + // Rotate around the Z axis. + m.setIdentity(); + m.m[0][0] = c; + m.m[1][1] = c; + if (z < 0.0f) { + m.m[1][0] = s; + m.m[0][1] = -s; + } else { + m.m[1][0] = -s; + m.m[0][1] = s; + } + m.flagBits = General; + quick = true; + } + } else if (z == 0.0f) { + // Rotate around the Y axis. + m.setIdentity(); + m.m[0][0] = c; + m.m[2][2] = 1.0f; + if (y < 0.0f) { + m.m[0][3] = -s * inv_dist_to_plane; + } else { + m.m[0][3] = s * inv_dist_to_plane; + } + m.flagBits = General; + quick = true; + } + } else if (y == 0.0f && z == 0.0f) { + // Rotate around the X axis. + m.setIdentity(); + m.m[1][1] = c; + m.m[2][2] = 1.0f; + if (x < 0.0f) { + m.m[1][3] = s * inv_dist_to_plane; + } else { + m.m[1][3] = -s * inv_dist_to_plane; + } + m.flagBits = General; + quick = true; + } + if (!quick) { + qreal len = x * x + y * y + z * z; + if (!qFuzzyIsNull(len - 1.0f) && !qFuzzyIsNull(len)) { + len = qSqrt(len); + x /= len; + y /= len; + z /= len; + } + ic = 1.0f - c; + m.m[0][0] = x * x * ic + c; + m.m[1][0] = x * y * ic - z * s; + m.m[2][0] = 0.0f; + m.m[3][0] = 0.0f; + m.m[0][1] = y * x * ic + z * s; + m.m[1][1] = y * y * ic + c; + m.m[2][1] = 0.0f; + m.m[3][1] = 0.0f; + m.m[0][2] = 0.0f; + m.m[1][2] = 0.0f; + m.m[2][2] = 1.0f; + m.m[3][2] = 0.0f; + m.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane; + m.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane; + m.m[2][3] = 0.0f; + m.m[3][3] = 1.0f; + } + int flags = flagBits; + *this *= m; + if (flags != Identity) + flagBits = flags | Rotation; + else + flagBits = Rotation; + return *this; +} + +#ifndef QT_NO_QUATERNION /*! Multiples this matrix by another that rotates coordinates according @@ -1430,15 +1536,31 @@ QMatrix QMatrix4x4::toAffine() const m[3][0], m[3][1]); } -static const qreal inv_dist_to_plane = 1. / 1024.; +/*! + Returns the conventional Qt 2D transformation matrix that + corresponds to this matrix. + + The returned QTransform is formed by simply dropping the + third row and third column of the QMatrix4x4. This is suitable + for implementing orthographic projections where the z co-ordinate + should be dropped rather than projected. + + \sa toAffine() +*/ +QTransform QMatrix4x4::toTransform() const +{ + return QTransform(m[0][0], m[0][1], m[0][3], + m[1][0], m[1][1], m[1][3], + m[3][0], m[3][1], m[3][3]); +} /*! Returns the conventional Qt 2D transformation matrix that corresponds to this matrix. If \a distanceToPlane is non-zero, it indicates a projection - factor to use to adjust for the z co-ordinate. The default - value of 1024 corresponds to the projection factor used + factor to use to adjust for the z co-ordinate. The value of + 1024 corresponds to the projection factor used by QTransform::rotate() for the x and y axes. If \a distanceToPlane is zero, then the returned QTransform diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h index b32e00a..ba74b89 100644 --- a/src/gui/math3d/qmatrix4x4.h +++ b/src/gui/math3d/qmatrix4x4.h @@ -159,7 +159,8 @@ public: void toValueArray(qreal *values) const; QMatrix toAffine() const; - QTransform toTransform(qreal distanceToPlane = 1024.0f) const; + QTransform toTransform() const; + QTransform toTransform(qreal distanceToPlane) const; QPoint map(const QPoint& point) const; QPointF map(const QPointF& point) const; @@ -206,6 +207,10 @@ private: QMatrix4x4(int) { flagBits = General; } QMatrix4x4 orthonormalInverse() const; + + QMatrix4x4& projectedRotate(qreal angle, qreal x, qreal y, qreal z); + + friend class QGraphicsRotation; }; inline QMatrix4x4::QMatrix4x4 diff --git a/src/gui/styles/qcleanlooksstyle.cpp b/src/gui/styles/qcleanlooksstyle.cpp index fabd7ca..fc12cfe 100644 --- a/src/gui/styles/qcleanlooksstyle.cpp +++ b/src/gui/styles/qcleanlooksstyle.cpp @@ -3866,7 +3866,7 @@ QSize QCleanlooksStyle::sizeFromContents(ContentsType type, const QStyleOption * if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) { if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) { if (!menuItem->text.isEmpty()) { - newSize.setHeight(menuItem->fontMetrics.lineSpacing()); + newSize.setHeight(menuItem->fontMetrics.height()); } } #ifndef QT_NO_COMBOBOX diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index 5886512..70d130a 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -4396,13 +4396,13 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWid case PM_TitleBarHeight: { if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) { if ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool) { - ret = qMax(widget ? widget->fontMetrics().lineSpacing() : opt->fontMetrics.lineSpacing(), 16); + ret = qMax(widget ? widget->fontMetrics().height() : opt->fontMetrics.height(), 16); #ifndef QT_NO_DOCKWIDGET } else if (qobject_cast<const QDockWidget*>(widget)) { - ret = qMax(widget->fontMetrics().lineSpacing(), int(QStyleHelper::dpiScaled(13))); + ret = qMax(widget->fontMetrics().height(), int(QStyleHelper::dpiScaled(13))); #endif } else { - ret = qMax(widget ? widget->fontMetrics().lineSpacing() : opt->fontMetrics.lineSpacing(), 18); + ret = qMax(widget ? widget->fontMetrics().height() : opt->fontMetrics.height(), 18); } } else { ret = int(QStyleHelper::dpiScaled(18.)); diff --git a/src/gui/styles/qmotifstyle.cpp b/src/gui/styles/qmotifstyle.cpp index e6c60cf..b65d45c 100644 --- a/src/gui/styles/qmotifstyle.cpp +++ b/src/gui/styles/qmotifstyle.cpp @@ -1154,7 +1154,7 @@ void QMotifStyle::drawControl(ControlElement element, const QStyleOption *opt, Q menuitem->palette, menuitem->state & State_Enabled, menuitem->text, QPalette::Text); textWidth = menuitem->fontMetrics.width(menuitem->text) + 10; - y += menuitem->fontMetrics.lineSpacing() / 2; + y += menuitem->fontMetrics.height() / 2; p->setFont(oldFont); } p->setPen(opt->palette.dark().color()); @@ -2056,7 +2056,7 @@ QMotifStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, if (mi->menuItemType == QStyleOptionMenuItem::Separator) { w = 10; - h = (mi->text.isEmpty()) ? motifSepHeight : mi->fontMetrics.lineSpacing(); + h = (mi->text.isEmpty()) ? motifSepHeight : mi->fontMetrics.height(); } // a little bit of border can never harm diff --git a/src/gui/styles/qplastiquestyle.cpp b/src/gui/styles/qplastiquestyle.cpp index ce2109a..09f5d36 100644 --- a/src/gui/styles/qplastiquestyle.cpp +++ b/src/gui/styles/qplastiquestyle.cpp @@ -5027,7 +5027,7 @@ QSize QPlastiqueStyle::sizeFromContents(ContentsType type, const QStyleOption *o case CT_MenuItem: if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) { if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) - newSize.setHeight(menuItem->text.isEmpty() ? 2 : menuItem->fontMetrics.lineSpacing()); + newSize.setHeight(menuItem->text.isEmpty() ? 2 : menuItem->fontMetrics.height()); } break; case CT_MenuBarItem: @@ -5607,11 +5607,11 @@ int QPlastiqueStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, #ifdef QT3_SUPPORT if (widget && widget->inherits("Q3DockWindowTitleBar")) { // Q3DockWindow has smaller title bars than QDockWidget - ret = qMax(widget->fontMetrics().lineSpacing(), 20); + ret = qMax(widget->fontMetrics().height(), 20); } else #endif - ret = qMax(widget ? widget->fontMetrics().lineSpacing() : - (option ? option->fontMetrics.lineSpacing() : 0), 30); + ret = qMax(widget ? widget->fontMetrics().height() : + (option ? option->fontMetrics.height() : 0), 30); break; case PM_MaximumDragDistance: return -1; diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index 707b05e..2d90aa1 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -4722,7 +4722,7 @@ int QStyleSheetStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const return subRule.size().height(); else if (subRule.hasBox() || subRule.hasBorder()) { QFontMetrics fm = opt ? opt->fontMetrics : w->fontMetrics(); - return subRule.size(QSize(0, fm.lineSpacing())).height(); + return subRule.size(QSize(0, fm.height())).height(); } break; } diff --git a/src/gui/styles/qwindowsmobilestyle.cpp b/src/gui/styles/qwindowsmobilestyle.cpp index 5fa6251..7ed187f 100644 --- a/src/gui/styles/qwindowsmobilestyle.cpp +++ b/src/gui/styles/qwindowsmobilestyle.cpp @@ -5347,10 +5347,8 @@ void QWindowsMobileStyle::drawPrimitive(PrimitiveElement element, const QStyleOp painter->drawLines(a); break; } case PE_Frame: - if (d->doubleControls) - qDrawPlainRect(painter, option->rect, option->palette.shadow().color(),2,&option->palette.light()); - else - qDrawPlainRect(painter, option->rect, option->palette.shadow().color(),1,&option->palette.light()); + qDrawPlainRect(painter, option->rect, option->palette.shadow().color(), + d->doubleControls ? 2 : 1, &option->palette.background()); break; case PE_FrameLineEdit: case PE_FrameMenu: @@ -6840,34 +6838,11 @@ void QWindowsMobileStyle::polish(QWidget *widget) { else #endif //QT_NO_TOOLBAR -#ifndef QT_NO_PROPERTIES - if (QAbstractButton *pushButton = qobject_cast<QAbstractButton*>(widget)) { - QVariant oldFont = widget->property("_q_styleWindowsMobileFont"); - if (!oldFont.isValid()) { - QFont f = pushButton->font(); - widget->setProperty("_q_styleWindowsMobileFont", f); - f.setBold(true); - int p = f.pointSize(); - if (p > 2) - f.setPointSize(p-1); - pushButton->setFont(f); - } - } -#endif - QWindowsStyle::polish(widget); + QWindowsStyle::polish(widget); } void QWindowsMobileStyle::unpolish(QWidget *widget) { -#ifndef QT_NO_PROPERTIES - if (QAbstractButton *pushButton = qobject_cast<QAbstractButton*>(widget)) { - QVariant oldFont = widget->property("_q_styleWindowsMobileFont"); - if (oldFont.isValid()) { - widget->setFont(qVariantValue<QFont>(oldFont)); - widget->setProperty("_q_styleWindowsMobileFont", QVariant()); - } - } -#endif QWindowsStyle::unpolish(widget); } diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 1285935..1b4c380 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -2632,7 +2632,7 @@ QFontCache::~QFontCache() while (it != end) { if (--it.value().data->cache_count == 0) { if (it.value().data->ref == 0) { - FC_DEBUG("QFontCache::~QFontCache: deleting engine %p key=(%d / %g %d %d %d %d)", + FC_DEBUG("QFontCache::~QFontCache: deleting engine %p key=(%d / %g %g %d %d %d)", it.value().data, it.key().script, it.key().def.pointSize, it.key().def.pixelSize, it.key().def.weight, it.key().def.style, it.key().def.fixedPitch); diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h index d74f0b4..144a82d 100644 --- a/src/gui/text/qfont_p.h +++ b/src/gui/text/qfont_p.h @@ -86,7 +86,7 @@ struct QFontDef #endif // Q_WS_X11 qreal pointSize; - int pixelSize; + qreal pixelSize; uint styleStrategy : 16; uint styleHint : 8; diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 738e36a..fb8444e 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -1331,7 +1331,7 @@ static void match(int script, const QFontDef &request, " family: %s [%s], script: %d\n" " weight: %d, style: %d\n" " stretch: %d\n" - " pixelSize: %d\n" + " pixelSize: %g\n" " pitch: %c", family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(), foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(), diff --git a/src/gui/text/qfontdatabase_win.cpp b/src/gui/text/qfontdatabase_win.cpp index ae26dab..6cde9ed 100644 --- a/src/gui/text/qfontdatabase_win.cpp +++ b/src/gui/text/qfontdatabase_win.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qt_windows.h" +#include <qmath.h> #include <private/qapplication_p.h> #include "qfont_p.h" #include "qfontengine_p.h" @@ -670,7 +671,7 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ break; } - lf.lfHeight = -request.pixelSize; + lf.lfHeight = -qRound(request.pixelSize); lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; @@ -899,7 +900,6 @@ static QFontEngine *loadWin(const QFontPrivate *d, int script, const QFontDef &r return fe; } - void QFontDatabase::load(const QFontPrivate *d, int script) { // sanity checks @@ -910,8 +910,9 @@ void QFontDatabase::load(const QFontPrivate *d, int script) // normalize the request to get better caching QFontDef req = d->request; if (req.pixelSize <= 0) - req.pixelSize = qMax(1, qRound(req.pointSize * d->dpi / 72.)); - req.pointSize = 0; + req.pixelSize = qreal((req.pointSize * d->dpi) / 72.); + if (req.pixelSize < 1) + req.pixelSize = 1; if (req.weight == 0) req.weight = QFont::Normal; if (req.stretch == 0) @@ -928,7 +929,8 @@ void QFontDatabase::load(const QFontPrivate *d, int script) QFontEngine *fe = QFontCache::instance()->findEngine(key); // set it to the actual pointsize, so QFontInfo will do the right thing - req.pointSize = req.pixelSize*72./d->dpi; + if (req.pointSize < 0) + req.pointSize = req.pixelSize*72./d->dpi; if (!fe) { if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) { diff --git a/src/gui/text/qfontdatabase_x11.cpp b/src/gui/text/qfontdatabase_x11.cpp index 27ff003..f184811 100644 --- a/src/gui/text/qfontdatabase_x11.cpp +++ b/src/gui/text/qfontdatabase_x11.cpp @@ -51,6 +51,7 @@ #include <qfile.h> #include <qtemporaryfile.h> #include <qabstractfileengine.h> +#include <qmath.h> #include <ctype.h> #include <stdlib.h> @@ -757,7 +758,7 @@ QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &request) double size; if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch) - fontDef.pixelSize = qRound(size); + fontDef.pixelSize = size; else fontDef.pixelSize = 12; @@ -1455,7 +1456,7 @@ void qt_addPatternProps(FcPattern *pattern, int screen, int script, const QFontD slant_value = FC_SLANT_OBLIQUE; FcPatternAddInteger(pattern, FC_SLANT, slant_value); - double size_value = qMax(1, request.pixelSize); + double size_value = qMax(qreal(1.), request.pixelSize); FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size_value); int stretch = request.stretch; @@ -1893,8 +1894,9 @@ void QFontDatabase::load(const QFontPrivate *d, int script) // normalize the request to get better caching QFontDef req = d->request; if (req.pixelSize <= 0) - req.pixelSize = qRound(qt_pixelSize(req.pointSize, d->dpi)); - req.pointSize = 0; + req.pixelSize = floor(qt_pixelSize(req.pointSize, d->dpi) * 100 + 0.5) / 100; + if (req.pixelSize < 1) + req.pixelSize = 1; if (req.weight == 0) req.weight = QFont::Normal; if (req.stretch == 0) @@ -1909,7 +1911,9 @@ void QFontDatabase::load(const QFontPrivate *d, int script) return; // set it to the actual pointsize, so QFontInfo will do the right thing - req.pointSize = qt_pointSize(req.pixelSize, d->dpi); + if (req.pointSize < 0) + req.pointSize = qt_pointSize(req.pixelSize, d->dpi); + QFontEngine *fe = QFontCache::instance()->findEngine(key); diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 3da1593..4041717 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -327,7 +327,7 @@ void QFreetypeFace::release(const QFontEngine::FaceId &face_id) void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing) { - *ysize = fontDef.pixelSize << 6; + *ysize = qRound(fontDef.pixelSize * 64); *xsize = *ysize * fontDef.stretch / 100; *outline_drawing = false; @@ -387,7 +387,9 @@ QFontEngine::Properties QFreetypeFace::properties() const p.descent = QFixed::fromFixed(-face->size->metrics.descender); p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender); p.emSquare = face->size->metrics.y_ppem; - p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.); +// p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.); + p.boundingBox = QRectF(0, -p.ascent.toReal(), + face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() ); } p.italicAngle = 0; p.capHeight = p.ascent; @@ -709,6 +711,7 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format) hbFace = freetype->hbFace; metrics = face->size->metrics; + #if defined(Q_WS_QWS) /* TrueType fonts with embedded bitmaps may have a bitmap font specific @@ -1219,7 +1222,8 @@ QFixed QFontEngineFT::ascent() const QFixed QFontEngineFT::descent() const { - return QFixed::fromFixed(-metrics.descender); + // subtract a pixel to work around QFontMetrics's built-in + 1 + return QFixed::fromFixed(-metrics.descender - 64); } QFixed QFontEngineFT::leading() const diff --git a/src/gui/text/qfontengine_qpf.cpp b/src/gui/text/qfontengine_qpf.cpp index ef3f2ae..6ff0fbd 100644 --- a/src/gui/text/qfontengine_qpf.cpp +++ b/src/gui/text/qfontengine_qpf.cpp @@ -819,7 +819,7 @@ FT_Face QFontEngineQPF::lockFace() const FT_Face face = freetype->face; // ### not perfect - const int ysize = fontDef.pixelSize << 6; + const int ysize = int(fontDef.pixelSize) << 6; const int xsize = ysize; if (freetype->xsize != xsize || freetype->ysize != ysize) { diff --git a/src/gui/text/qfontengine_win.cpp b/src/gui/text/qfontengine_win.cpp index cc555a3..fd34d0f 100644 --- a/src/gui/text/qfontengine_win.cpp +++ b/src/gui/text/qfontengine_win.cpp @@ -125,6 +125,7 @@ HDC shared_dc() } #endif +#ifndef Q_WS_WINCE typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT); static PtrGetCharWidthI ptrGetCharWidthI = 0; static bool resolvedGetCharWidthI = false; @@ -136,6 +137,7 @@ static void resolveGetCharWidthI() resolvedGetCharWidthI = true; ptrGetCharWidthI = (PtrGetCharWidthI)QLibrary::resolve(QLatin1String("gdi32"), "GetCharWidthI"); } +#endif // !defined(Q_WS_WINCE) // defined in qtextengine_win.cpp typedef void *SCRIPT_CACHE; @@ -340,8 +342,10 @@ QFontEngineWin::QFontEngineWin(const QString &name, HFONT _hfont, bool stockFont designAdvances = 0; designAdvancesSize = 0; +#ifndef Q_WS_WINCE if (!resolvedGetCharWidthI) resolveGetCharWidthI(); +#endif } QFontEngineWin::~QFontEngineWin() @@ -381,80 +385,18 @@ bool QFontEngineWin::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph if (flags & QTextEngine::GlyphIndicesOnly) return true; -#if defined(Q_WS_WINCE) - HDC hdc = shared_dc(); - if (flags & QTextEngine::DesignMetrics) { - HGDIOBJ oldFont = 0; - int glyph_pos = 0; - for(register int i = 0; i < len; i++) { - bool surrogate = (str[i].unicode() >= 0xd800 && str[i].unicode() < 0xdc00 && i < len-1 - && str[i+1].unicode() >= 0xdc00 && str[i+1].unicode() < 0xe000); - unsigned int glyph = glyphs->glyphs[glyph_pos]; - if(int(glyph) >= designAdvancesSize) { - int newSize = (glyph + 256) >> 8 << 8; - designAdvances = q_check_ptr((QFixed *)realloc(designAdvances, newSize*sizeof(QFixed))); - for(int i = designAdvancesSize; i < newSize; ++i) - designAdvances[i] = -1000000; - designAdvancesSize = newSize; - } - if(designAdvances[glyph] < -999999) { - if(!oldFont) - oldFont = selectDesignFont(); - SIZE size = {0, 0}; - GetTextExtentPoint32(hdc, (wchar_t *)(str+i), surrogate ? 2 : 1, &size); - designAdvances[glyph] = QFixed((int)size.cx)/designToDevice; - } - glyphs->advances_x[glyph_pos] = designAdvances[glyph]; - glyphs->advances_y[glyph_pos] = 0; - if (surrogate) - ++i; - ++glyph_pos; - } - if(oldFont) - DeleteObject(SelectObject(hdc, oldFont)); - } else { - int glyph_pos = 0; - HGDIOBJ oldFont = 0; - - for(register int i = 0; i < len; i++) { - bool surrogate = (str[i].unicode() >= 0xd800 && str[i].unicode() < 0xdc00 && i < len-1 - && str[i+1].unicode() >= 0xdc00 && str[i+1].unicode() < 0xe000); - unsigned int glyph = glyphs->glyphs[glyph_pos]; - - glyphs->advances_y[glyph_pos] = 0; - - if (glyph >= widthCacheSize) { - int newSize = (glyph + 256) >> 8 << 8; - widthCache = q_check_ptr((unsigned char *)realloc(widthCache, - newSize*sizeof(QFixed))); - memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize); - widthCacheSize = newSize; - } - glyphs->advances_x[glyph_pos] = widthCache[glyph]; - // font-width cache failed - if (glyphs->advances_x[glyph_pos] == 0) { - SIZE size = {0, 0}; - if (!oldFont) - oldFont = SelectObject(hdc, hfont); - GetTextExtentPoint32(hdc, (wchar_t *)str + i, surrogate ? 2 : 1, &size); - glyphs->advances_x[glyph_pos] = size.cx; - // if glyph's within cache range, store it for later - if (size.cx > 0 && size.cx < 0x100) - widthCache[glyph] = size.cx; - } - - if (surrogate) - ++i; - ++glyph_pos; - } + recalcAdvances(glyphs, flags); + return true; +} - if (oldFont) - SelectObject(hdc, oldFont); - } +inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width) +{ +#if defined(Q_WS_WINCE) + GetCharWidth32(hdc, glyph, glyph, &width); #else - recalcAdvances(glyphs, flags); + if (ptrGetCharWidthI) + ptrGetCharWidthI(hdc, glyph, 1, 0, &width); #endif - return true; } void QFontEngineWin::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const @@ -477,8 +419,7 @@ void QFontEngineWin::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFla oldFont = selectDesignFont(); int width = 0; - if (ptrGetCharWidthI) - ptrGetCharWidthI(hdc, glyph, 1, 0, &width); + calculateTTFGlyphWidth(hdc, glyph, width); designAdvances[glyph] = QFixed(width) / designToDevice; } glyphs->advances_x[i] = designAdvances[glyph]; @@ -517,8 +458,8 @@ void QFontEngineWin::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFla SIZE size = {0, 0}; GetTextExtentPoint32(hdc, (wchar_t *)ch, chrLen, &size); width = size.cx; - } else if (ptrGetCharWidthI) { - ptrGetCharWidthI(hdc, glyph, 1, 0, &width); + } else { + calculateTTFGlyphWidth(hdc, glyph, width); } glyphs->advances_x[i] = width; // if glyph's within cache range, store it for later @@ -636,7 +577,9 @@ QFixed QFontEngineWin::ascent() const QFixed QFontEngineWin::descent() const { - return tm.tmDescent; + // ### we substract 1 to even out the historical +1 in QFontMetrics's + // ### height=asc+desc+1 equation. Fix in Qt5. + return tm.tmDescent - 1; } QFixed QFontEngineWin::leading() const diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index de83d39..73434b1 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -1437,7 +1437,9 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p option.setTextDirection(dir); layout.setTextOption(option); layout.beginLayout(); - layout.createLine(); + QTextLine line = layout.createLine(); + if (line.isValid()) + line.setLeadingIncluded(true); layout.endLayout(); layout.draw(painter, QPointF(r.left(), pos.y())); break; @@ -2579,6 +2581,7 @@ void QTextDocumentLayoutPrivate::layoutBlock(const QTextBlock &bl, int blockPosi QTextLine line = tl->createLine(); if (!line.isValid()) break; + line.setLeadingIncluded(true); QFixed left, right; floatMargins(layoutStruct->y, layoutStruct, &left, &right); diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 81c9142..a91408f 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1042,7 +1042,7 @@ void QTextEngine::shapeTextWithCE(int item) const QScriptItem &si = layoutData->items[item]; si.glyph_data_offset = layoutData->used; - QFontEngine *fe = fontEngine(si, &si.ascent, &si.descent); + QFontEngine *fe = fontEngine(si, &si.ascent, &si.descent, &si.leading); QTextEngine::ShaperFlags flags; if (si.analysis.bidiLevel % 2) @@ -1119,7 +1119,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const si.glyph_data_offset = layoutData->used; - QFontEngine *font = fontEngine(si, &si.ascent, &si.descent); + QFontEngine *font = fontEngine(si, &si.ascent, &si.descent, &si.leading); bool kerningEnabled = this->font(si).d->kerning; @@ -1350,8 +1350,11 @@ void QTextEngine::shape(int item) const layoutData->items[item].position + block.position(), format); } } else if (layoutData->items[item].analysis.flags == QScriptAnalysis::Tab) { - // set up at least the ascent/descent of the script item for the tab - fontEngine(layoutData->items[item], &layoutData->items[item].ascent, &layoutData->items[item].descent); + // set up at least the ascent/descent/leading of the script item for the tab + fontEngine(layoutData->items[item], + &layoutData->items[item].ascent, + &layoutData->items[item].descent, + &layoutData->items[item].leading); } else { shapeText(item); } @@ -1737,7 +1740,7 @@ QFont QTextEngine::font(const QScriptItem &si) const return font; } -QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFixed *descent) const +QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFixed *descent, QFixed *leading) const { QFontEngine *engine = 0; QFontEngine *scaledEngine = 0; @@ -1777,6 +1780,7 @@ QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFix if (ascent) { *ascent = engine->ascent(); *descent = engine->descent(); + *leading = engine->leading(); } if (scaledEngine) @@ -2009,8 +2013,12 @@ void QScriptLine::setDefaultHeight(QTextEngine *eng) e = eng->fnt.d->engineForScript(QUnicodeTables::Common); } - ascent = qMax(ascent, e->ascent()); - descent = qMax(descent, e->descent()); + QFixed other_ascent = e->ascent(); + QFixed other_descent = e->descent(); + QFixed other_leading = e->leading(); + leading = qMax(leading + ascent, other_leading + other_ascent) - qMax(ascent, other_ascent); + ascent = qMax(ascent, other_ascent); + descent = qMax(descent, other_descent); } QTextEngine::LayoutData::LayoutData() diff --git a/src/gui/text/qtextengine_mac.cpp b/src/gui/text/qtextengine_mac.cpp index e101830..eeccc72 100644 --- a/src/gui/text/qtextengine_mac.cpp +++ b/src/gui/text/qtextengine_mac.cpp @@ -557,7 +557,7 @@ void QTextEngine::shapeTextMac(int item) const si.glyph_data_offset = layoutData->used; - QFontEngine *font = fontEngine(si, &si.ascent, &si.descent); + QFontEngine *font = fontEngine(si, &si.ascent, &si.descent, &si.leading); if (font->type() != QFontEngine::Multi) { shapeTextWithHarfbuzz(item); return; diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 85c6928..a1d363b 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -345,11 +345,11 @@ struct Q_AUTOTEST_EXPORT QScriptItem { inline QScriptItem() : position(0), - num_glyphs(0), descent(-1), ascent(-1), width(-1), + num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1), glyph_data_offset(0) {} inline QScriptItem(int p, const QScriptAnalysis &a) : position(p), analysis(a), - num_glyphs(0), descent(-1), ascent(-1), width(-1), + num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1), glyph_data_offset(0) {} int position; @@ -357,6 +357,7 @@ struct Q_AUTOTEST_EXPORT QScriptItem unsigned short num_glyphs; QFixed descent; QFixed ascent; + QFixed leading; QFixed width; int glyph_data_offset; QFixed height() const { return ascent + descent + 1; } @@ -373,9 +374,10 @@ struct Q_AUTOTEST_EXPORT QScriptLine QScriptLine() : from(0), length(0), justified(0), gridfitted(0), - hasTrailingSpaces(0) {} + hasTrailingSpaces(0), leadingIncluded(0) {} QFixed descent; QFixed ascent; + QFixed leading; QFixed x; QFixed y; QFixed width; @@ -385,7 +387,11 @@ struct Q_AUTOTEST_EXPORT QScriptLine mutable uint justified : 1; mutable uint gridfitted : 1; uint hasTrailingSpaces : 1; - QFixed height() const { return ascent + descent + 1; } + uint leadingIncluded : 1; + QFixed height() const { return ascent + descent + 1 + + (leadingIncluded? qMax(QFixed(),leading) : QFixed()); } + QFixed base() const { return ascent + + (leadingIncluded ? qMax(QFixed(),leading) : QFixed()); } void setDefaultHeight(QTextEngine *eng); void operator+=(const QScriptLine &other); }; @@ -394,6 +400,7 @@ Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE); inline void QScriptLine::operator+=(const QScriptLine &other) { + leading= qMax(leading + ascent, other.leading + other.ascent) - qMax(ascent, other.ascent); descent = qMax(descent, other.descent); ascent = qMax(ascent, other.ascent); textWidth += other.textWidth; @@ -476,7 +483,7 @@ public: return end - si->position; } - QFontEngine *fontEngine(const QScriptItem &si, QFixed *ascent = 0, QFixed *descent = 0) const; + QFontEngine *fontEngine(const QScriptItem &si, QFixed *ascent = 0, QFixed *descent = 0, QFixed *leading = 0) const; QFont font(const QScriptItem &si) const; inline QFont font() const { return fnt; } diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index c5f0e35..4600a29 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -860,7 +860,7 @@ QRectF QTextLayout::boundingRect() const ymin = qMin(ymin, si.y); xmax = qMax(xmax, si.x+qMax(si.width, si.textWidth)); // ### shouldn't the ascent be used in ymin??? - ymax = qMax(ymax, si.y+si.ascent+si.descent+1); + ymax = qMax(ymax, si.y+si.height()); } return QRectF(xmin.toReal(), ymin.toReal(), (xmax-xmin).toReal(), (ymax-ymin).toReal()); } @@ -1071,10 +1071,10 @@ static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPo QTextLineItemIterator iterator(eng, lineNumber, pos, selection); - const QFixed y = QFixed::fromReal(pos.y()) + line.y + line.ascent; + + const qreal selectionY = pos.y() + line.y.toReal(); const qreal lineHeight = line.height().toReal(); - const qreal selectionY = (y - line.ascent).toReal(); QFixed lastSelectionX = iterator.x; QFixed lastSelectionWidth; @@ -1334,23 +1334,23 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition const qreal x = position.x() + l.cursorToX(cursorPosition); int itm = d->findItem(cursorPosition - 1); - QFixed ascent = sl.ascent; + QFixed base = sl.base(); QFixed descent = sl.descent; bool rightToLeft = (d->option.textDirection() == Qt::RightToLeft); if (itm >= 0) { const QScriptItem &si = d->layoutData->items.at(itm); if (si.ascent > 0) - ascent = si.ascent; + base = si.ascent; if (si.descent > 0) descent = si.descent; rightToLeft = si.analysis.bidiLevel % 2; } - qreal y = position.y() + (sl.y + sl.ascent - ascent).toReal(); + qreal y = position.y() + (sl.y + sl.base() - base).toReal(); bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing) && (p->transform().type() > QTransform::TxTranslate); if (toggleAntialiasing) p->setRenderHint(QPainter::Antialiasing); - p->fillRect(QRectF(x, y, qreal(width), (ascent + descent).toReal()), p->pen().brush()); + p->fillRect(QRectF(x, y, qreal(width), (base + descent + 1).toReal()), p->pen().brush()); if (toggleAntialiasing) p->setRenderHint(QPainter::Antialiasing, false); if (d->layoutData->hasBidi) { @@ -1500,9 +1500,11 @@ qreal QTextLine::descent() const } /*! - Returns the line's height. This is equal to ascent() + descent() + 1. + Returns the line's height. This is equal to ascent() + descent() + 1 + if leading is not included. If leading is included, this equals to + ascent() + descent() + leading() + 1. - \sa ascent() descent() + \sa ascent() descent() leading() setLeadingIncluded() */ qreal QTextLine::height() const { @@ -1510,6 +1512,51 @@ qreal QTextLine::height() const } /*! + \since 4.6 + + Returns the line's leading. + + \sa ascent() descent() height() +*/ +qreal QTextLine::leading() const +{ + return eng->lines[i].leading.toReal(); +} + +/*! \since 4.6 + + Includes positive leading into the line's height if \a included is true; + otherwise does not include leading. + + By default, leading is not included. + + Note that negative leading is ignored, it must be handled + in the code using the text lines by letting the lines overlap. + + \sa leadingIncluded() + +*/ +void QTextLine::setLeadingIncluded(bool included) +{ + eng->lines[i].leadingIncluded= included; + +} + +/*! \since 4.6 + + Returns true if positive leading is included into the line's height; otherwise returns false. + + By default, leading is not included. + + \sa setLeadingIncluded() +*/ +bool QTextLine::leadingIncluded() const +{ + return eng->lines[i].leadingIncluded; +} + + +/*! Returns the width of the line that is occupied by text. This is always \<= to width(), and is the minimum width that could be used by layout() without changing the line break position. @@ -1712,6 +1759,9 @@ void QTextLine::layout_helper(int maxGlyphs) } const QScriptItem ¤t = eng->layoutData->items[item]; + lbh.tmpData.leading = qMax(lbh.tmpData.leading + lbh.tmpData.ascent, + current.leading + current.ascent) - qMax(lbh.tmpData.ascent, + current.ascent); lbh.tmpData.ascent = qMax(lbh.tmpData.ascent, current.ascent); lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent); @@ -2042,7 +2092,9 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR QTextLineItemIterator iterator(eng, i, pos, selection); - const QFixed y = QFixed::fromReal(pos.y()) + line.y + line.ascent; + QFixed lineBase = line.base(); + + const QFixed y = QFixed::fromReal(pos.y()) + line.y + lineBase; bool suppressColors = (eng->option.flags() & QTextOption::SuppressColors); while (!iterator.atEnd()) { @@ -2065,7 +2117,7 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR if (selection) format.merge(selection->format); - setPenAndDrawBackground(p, pen, format, QRectF(iterator.x.toReal(), (y - line.ascent).toReal(), + setPenAndDrawBackground(p, pen, format, QRectF(iterator.x.toReal(), (y - lineBase).toReal(), iterator.itemWidth.toReal(), line.height().toReal())); QTextCharFormat::VerticalAlignment valign = format.verticalAlignment(); @@ -2086,7 +2138,7 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR if (si.analysis.flags == QScriptAnalysis::Object && eng->block.docHandle()) { QFixed itemY = y - si.ascent; if (format.verticalAlignment() == QTextCharFormat::AlignTop) { - itemY = y - line.ascent; + itemY = y - lineBase; } QRectF itemRect(iterator.x.toReal(), itemY.toReal(), iterator.itemWidth.toReal(), si.height().toReal()); diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h index 90afac8..9f170f5 100644 --- a/src/gui/text/qtextlayout.h +++ b/src/gui/text/qtextlayout.h @@ -196,6 +196,10 @@ public: qreal ascent() const; qreal descent() const; qreal height() const; + qreal leading() const; + + void setLeadingIncluded(bool included); + bool leadingIncluded() const; qreal naturalTextWidth() const; QRectF naturalTextRect() const; diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index b28ecd7..b7615a4 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -78,6 +78,7 @@ win32 { unix:x11 { HEADERS += \ text/qfontengine_x11_p.h \ + text/qfontdatabase_x11.cpp \ text/qfontengine_ft_p.h SOURCES += \ text/qfont_x11.cpp \ diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index 0e888d6..05e1e74 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -314,7 +314,7 @@ QSize QComboBoxPrivate::recomputeSizeHint(QSize &sh) const // height - sh.setHeight(qMax(fm.lineSpacing(), 14) + 2); + sh.setHeight(qMax(fm.height(), 14) + 2); if (hasIcon) { sh.setHeight(qMax(sh.height(), iconSize.height() + 2)); } diff --git a/src/gui/widgets/qdockwidget.cpp b/src/gui/widgets/qdockwidget.cpp index a574262f..6710275 100644 --- a/src/gui/widgets/qdockwidget.cpp +++ b/src/gui/widgets/qdockwidget.cpp @@ -456,7 +456,7 @@ int QDockWidgetLayout::titleHeight() const int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q); - return qMax(buttonHeight + 2, titleFontMetrics.lineSpacing() + 2*mw); + return qMax(buttonHeight + 2, titleFontMetrics.height() + 2*mw); } void QDockWidgetLayout::setGeometry(const QRect &geometry) diff --git a/src/gui/widgets/qfontcombobox.cpp b/src/gui/widgets/qfontcombobox.cpp index 7b39823..806db59 100644 --- a/src/gui/widgets/qfontcombobox.cpp +++ b/src/gui/widgets/qfontcombobox.cpp @@ -194,7 +194,7 @@ QSize QFontFamilyDelegate::sizeHint(const QStyleOptionViewItem &option, // font.setFamily(text); font.setPointSize(QFontInfo(font).pointSize() * 3/2); QFontMetrics fontMetrics(font); - return QSize(fontMetrics.width(text), fontMetrics.lineSpacing()); + return QSize(fontMetrics.width(text), fontMetrics.height()); } diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 629e839..e4252b5 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -624,7 +624,7 @@ QSize QLineEdit::sizeHint() const Q_D(const QLineEdit); ensurePolished(); QFontMetrics fm(font()); - int h = qMax(fm.lineSpacing(), 14) + 2*d->verticalMargin + int h = qMax(fm.height(), 14) + 2*d->verticalMargin + d->topTextMargin + d->bottomTextMargin + d->topmargin + d->bottommargin; int w = fm.width(QLatin1Char('x')) * 17 + 2*d->horizontalMargin diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index 687e1bc..ea25901 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -180,6 +180,21 @@ int QMenuPrivate::scrollerHeight() const } //Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't +QRect QMenuPrivate::popupGeometry(const QWidget *widget) const +{ +#ifdef Q_WS_WIN + return QApplication::desktop()->screenGeometry(widget); +#elif defined Q_WS_X11 + if (X11->desktopEnvironment == DE_KDE) + return QApplication::desktop()->screenGeometry(widget); + else + return QApplication::desktop()->availableGeometry(widget); +#else + return QApplication::desktop()->availableGeometry(widget); +#endif +} + +//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't QRect QMenuPrivate::popupGeometry(int screen) const { #ifdef Q_WS_WIN @@ -234,7 +249,7 @@ void QMenuPrivate::updateActionRects() const } int max_column_width = 0, - dh = popupGeometry(QApplication::desktop()->screenNumber(q)).height(), + dh = popupGeometry(q).height(), y = 0; QStyle *style = q->style(); QStyleOption opt; @@ -744,7 +759,7 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc if (newScrollFlags & QMenuScroller::ScrollUp) newOffset -= vmargin; - QRect screen = popupGeometry(QApplication::desktop()->screenNumber(q)); + QRect screen = popupGeometry(q); const int desktopFrame = q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q); if (q->height() < screen.height()-(desktopFrame*2)-1) { QRect geom = q->geometry(); @@ -960,10 +975,19 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e) return false; } +class ExceptionGuard +{ +public: + inline ExceptionGuard(bool *w = 0) : watched(w) { Q_ASSERT(!(*watched)); *watched = true; } + inline ~ExceptionGuard() { *watched = false; } + inline operator bool() { return *watched; } +private: + bool *watched; +}; + void QMenuPrivate::activateCausedStack(const QList<QPointer<QWidget> > &causedStack, QAction *action, QAction::ActionEvent action_e, bool self) { - Q_ASSERT(!activationRecursionGuard); - activationRecursionGuard = true; + ExceptionGuard guard(&activationRecursionGuard); #ifdef QT3_SUPPORT const int actionId = q_func()->findIdForAction(action); #endif @@ -1008,7 +1032,6 @@ void QMenuPrivate::activateCausedStack(const QList<QPointer<QWidget> > &causedSt #endif } } - activationRecursionGuard = false; } void QMenuPrivate::activateAction(QAction *action, QAction::ActionEvent action_e, bool self) @@ -1789,7 +1812,15 @@ void QMenu::popup(const QPoint &p, QAction *atAction) d->updateActionRects(); QPoint pos = p; QSize size = sizeHint(); - QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(p)); + QRect screen; +#ifndef QT_NO_GRAPHICSVIEW + bool isEmbedded = d->nearestGraphicsProxyWidget(this); + if (isEmbedded) + screen = d->popupGeometry(this); + else +#endif + screen = d->popupGeometry(QApplication::desktop()->screenNumber(p)); + const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this); bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen); #ifdef QT_KEYPAD_NAVIGATION @@ -2927,7 +2958,7 @@ void QMenu::internalDelayedPopup() QPoint pos(rightPos); QMenu *caused = qobject_cast<QMenu*>(d->activeMenu->d_func()->causedPopup.widget); - const QRect availGeometry(d->popupGeometry(QApplication::desktop()->screenNumber(caused))); + const QRect availGeometry(d->popupGeometry(caused)); if (isRightToLeft()) { pos = leftPos; if ((caused && caused->x() < x()) || pos.x() < availGeometry.left()) { diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h index 9c4f260..9348f7b 100644 --- a/src/gui/widgets/qmenu_p.h +++ b/src/gui/widgets/qmenu_p.h @@ -192,11 +192,12 @@ public: mutable QVector<QRect> actionRects; mutable QWidgetList widgetItems; void updateActionRects() const; - QRect popupGeometry(int screen=-1) const; + QRect popupGeometry(const QWidget *widget) const; + QRect popupGeometry(int screen = -1) const; mutable uint ncols : 4; //4 bits is probably plenty uint collapsibleSeparators : 1; - uint activationRecursionGuard : 1; + bool activationRecursionGuard; //selection static QPointer<QMenu> mouseDown; diff --git a/src/gui/widgets/qplaintextedit.cpp b/src/gui/widgets/qplaintextedit.cpp index 22438bf..fc61889 100644 --- a/src/gui/widgets/qplaintextedit.cpp +++ b/src/gui/widgets/qplaintextedit.cpp @@ -357,10 +357,8 @@ void QPlainTextDocumentLayout::layoutBlock(const QTextBlock &block) Q_D(QPlainTextDocumentLayout); QTextDocument *doc = document(); qreal margin = doc->documentMargin(); - QFontMetrics fm(doc->defaultFont()); qreal blockMaximumWidth = 0; - int leading = qMax(0, fm.leading()); qreal height = 0; QTextLayout *tl = block.layout(); QTextOption option = doc->defaultTextOption(); @@ -381,9 +379,8 @@ void QPlainTextDocumentLayout::layoutBlock(const QTextBlock &block) QTextLine line = tl->createLine(); if (!line.isValid()) break; + line.setLeadingIncluded(true); line.setLineWidth(availableWidth); - - height += leading; line.setPosition(QPointF(margin, height)); height += line.height(); blockMaximumWidth = qMax(blockMaximumWidth, line.naturalTextWidth() + 2*margin); diff --git a/src/gui/widgets/qpushbutton.cpp b/src/gui/widgets/qpushbutton.cpp index 1352e1b..eb34336 100644 --- a/src/gui/widgets/qpushbutton.cpp +++ b/src/gui/widgets/qpushbutton.cpp @@ -590,7 +590,7 @@ void QPushButtonPrivate::_q_popupPressed() int x = globalPos.x(); int y = globalPos.y(); if (horizontal) { - if (globalPos.y() + rect.height() + menuSize.height() <= QApplication::desktop()->height()) { + if (globalPos.y() + rect.height() + menuSize.height() <= QApplication::desktop()->availableGeometry(q).height()) { y += rect.height(); } else { y -= menuSize.height(); @@ -598,7 +598,7 @@ void QPushButtonPrivate::_q_popupPressed() if (q->layoutDirection() == Qt::RightToLeft) x += rect.width() - menuSize.width(); } else { - if (globalPos.x() + rect.width() + menu->sizeHint().width() <= QApplication::desktop()->width()) + if (globalPos.x() + rect.width() + menu->sizeHint().width() <= QApplication::desktop()->availableGeometry(q).width()) x += rect.width(); else x -= menuSize.width(); diff --git a/src/gui/widgets/qtextedit.cpp b/src/gui/widgets/qtextedit.cpp index b894aa8..f477fee 100644 --- a/src/gui/widgets/qtextedit.cpp +++ b/src/gui/widgets/qtextedit.cpp @@ -2079,8 +2079,8 @@ void QTextEdit::setReadOnly(bool ro) } else { flags = Qt::TextEditorInteraction; } - setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); d->control->setTextInteractionFlags(flags); + setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); } /*! |