From de73874e1f52ed323b87a36d072048023d22112e Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Tue, 4 May 2010 13:19:03 +0200 Subject: Fixed the position of the dock widget when undocked Reviewed-By: gabi Task-Number: QTBUG-9758 --- src/gui/widgets/qdockwidget.cpp | 6 +----- tests/auto/qdockwidget/tst_qdockwidget.cpp | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/gui/widgets/qdockwidget.cpp b/src/gui/widgets/qdockwidget.cpp index 54189de..ae00710 100644 --- a/src/gui/widgets/qdockwidget.cpp +++ b/src/gui/widgets/qdockwidget.cpp @@ -1270,11 +1270,7 @@ void QDockWidget::setFloating(bool floating) d->setWindowState(floating, false, floating ? r : QRect()); if (floating && r.isNull()) { - QDockWidgetLayout *layout = qobject_cast(this->layout()); - QRect titleArea = layout->titleArea(); - int h = layout->verticalTitleBar ? titleArea.width() : titleArea.height(); - QPoint p = mapToGlobal(QPoint(h, h)); - move(p); + setAttribute(Qt::WA_Moved, false); //we want it at the default position } } diff --git a/tests/auto/qdockwidget/tst_qdockwidget.cpp b/tests/auto/qdockwidget/tst_qdockwidget.cpp index a734985..8d9e7bbf 100644 --- a/tests/auto/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/qdockwidget/tst_qdockwidget.cpp @@ -96,6 +96,7 @@ private slots: void task248604_infiniteResize(); void task258459_visibilityChanged(); void taskQTBUG_1665_closableChanged(); + void taskQTBUG_9758_undockedGeometry(); }; // Testing get/set functions @@ -878,6 +879,25 @@ void tst_QDockWidget::taskQTBUG_1665_closableChanged() QVERIFY(!(dock.windowFlags() & Qt::WindowCloseButtonHint)); } +void tst_QDockWidget::taskQTBUG_9758_undockedGeometry() +{ + QMainWindow window; + QDockWidget dock1(&window); + QDockWidget dock2(&window); + window.addDockWidget(Qt::RightDockWidgetArea, &dock1); + window.addDockWidget(Qt::RightDockWidgetArea, &dock2); + window.tabifyDockWidget(&dock1, &dock2); + dock1.hide(); + dock2.hide(); + window.show(); + dock1.setFloating(true); + dock1.show(); + + QVERIFY(dock1.x() >= 0); + QVERIFY(dock1.y() >= 0); +} + + QTEST_MAIN(tst_QDockWidget) #include "tst_qdockwidget.moc" -- cgit v0.12 From 44144cf60e978f7d5d70aec49d114d57832a78c3 Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Wed, 5 May 2010 09:37:01 +0200 Subject: Fix a bug in QGraphicsItem::scroll. If the rect argument is null, well we should not do the scrolling with an null rectangle but rather with the boundingRect like the documentation says. Task-number:QTBUG-10400 Reviewed-by:janarve --- src/gui/graphicsview/qgraphicsitem.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 326f130..81138d9 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -5635,8 +5635,9 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect) // Adjust with 2 pixel margin. Notice the loss of precision // when converting to QRect. int adjust = 2; + QRectF scrollRect = !rect.isNull() ? rect : boundingRect(); QRectF br = boundingRect().adjusted(-adjust, -adjust, adjust, adjust); - QRect irect = rect.toRect().translated(-br.x(), -br.y()); + QRect irect = scrollRect.toRect().translated(-br.x(), -br.y()); pix.scroll(dx, dy, irect); @@ -5644,11 +5645,11 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect) // Translate the existing expose. foreach (QRectF exposedRect, c->exposed) - c->exposed += exposedRect.translated(dx, dy) & rect; + c->exposed += exposedRect.translated(dx, dy) & scrollRect; // Calculate exposure. QRegion exposed; - QRect r = rect.toRect(); + QRect r = scrollRect.toRect(); exposed += r; exposed -= r.translated(dx, dy); foreach (QRect rect, exposed.rects()) -- cgit v0.12 From 87f7444d2af1299460bdbfc1cbfa903ea504b7e3 Mon Sep 17 00:00:00 2001 From: aavit Date: Wed, 5 May 2010 10:20:03 +0200 Subject: Fixes regression: SVG image loading would fail from QBuffer with pos!=0 Was introduced with 2fe059c. Also now updates pos() as expected after reading in these cases. Autotest added to catch issues where pos != 0, or wrong pos after read. Reviewed-by: Kim --- src/plugins/imageformats/svg/qsvgiohandler.cpp | 10 ++-- tests/auto/qimagereader/tst_qimagereader.cpp | 63 +++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/plugins/imageformats/svg/qsvgiohandler.cpp b/src/plugins/imageformats/svg/qsvgiohandler.cpp index 8155569..7b8463d 100644 --- a/src/plugins/imageformats/svg/qsvgiohandler.cpp +++ b/src/plugins/imageformats/svg/qsvgiohandler.cpp @@ -82,15 +82,19 @@ bool QSvgIOHandlerPrivate::load(QIODevice *device) if (q->format().isEmpty()) q->canRead(); + // # The SVG renderer doesn't handle trailing, unrelated data, so we must + // assume that all available data in the device is to be read. bool res = false; QBuffer *buf = qobject_cast(device); if (buf) { - res = r.load(buf->data()); + const QByteArray &ba = buf->data(); + res = r.load(QByteArray::fromRawData(ba.constData() + buf->pos(), ba.size() - buf->pos())); + buf->seek(ba.size()); } else if (q->format() == "svgz") { - res = r.load(device->readAll()); // ### can't stream svgz + res = r.load(device->readAll()); } else { xmlReader.setDevice(device); - res = r.load(&xmlReader); //### doesn't leave pos() correctly + res = r.load(&xmlReader); } if (res) { diff --git a/tests/auto/qimagereader/tst_qimagereader.cpp b/tests/auto/qimagereader/tst_qimagereader.cpp index 1b4c502..aadee5b 100644 --- a/tests/auto/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/qimagereader/tst_qimagereader.cpp @@ -114,6 +114,9 @@ private slots: void readFromFileAfterJunk_data(); void readFromFileAfterJunk(); + void devicePosition_data(); + void devicePosition(); + void setBackgroundColor_data(); void setBackgroundColor(); @@ -1117,7 +1120,7 @@ void tst_QImageReader::readFromFileAfterJunk() QByteArray imageData = imageFile.readAll(); QVERIFY(!imageData.isNull()); - int iterations = 10; + int iterations = 3; if (format == "ppm" || format == "pbm" || format == "pgm" || format == "svg" || format == "svgz") iterations = 1; @@ -1147,6 +1150,64 @@ void tst_QImageReader::readFromFileAfterJunk() } } +void tst_QImageReader::devicePosition_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("format"); + + QTest::newRow("pbm") << QString("image.pbm") << QByteArray("pbm"); + QTest::newRow("pgm") << QString("image.pgm") << QByteArray("pgm"); + QTest::newRow("ppm-1") << QString("image.ppm") << QByteArray("ppm"); +#ifdef QTEST_HAVE_JPEG + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg"); + QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg"); + QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg"); +#endif +#if defined QTEST_HAVE_GIF + QTest::newRow("gif-1") << QString("earth.gif") << QByteArray("gif"); +#endif + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm"); + QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); + QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp"); + QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); +// QTest::newRow("mng-1") << QString("images/ball.mng") << QByteArray("mng"); +// QTest::newRow("mng-2") << QString("images/fire.mng") << QByteArray("mng"); +#if defined QTEST_HAVE_SVG + QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg"); + QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz"); +#endif +} + +void tst_QImageReader::devicePosition() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + + QImage expected(prefix + fileName); + QVERIFY(!expected.isNull()); + + QFile imageFile(prefix + fileName); + QVERIFY(imageFile.open(QFile::ReadOnly)); + QByteArray imageData = imageFile.readAll(); + QVERIFY(!imageData.isNull()); + int imageDataSize = imageData.size(); + + const char *preStr = "prebeef\n"; + int preLen = qstrlen(preStr); + imageData.prepend(preStr); + if (format != "svg" && format != "svgz") // Doesn't handle trailing data + imageData.append("\npostbeef"); + QBuffer buf(&imageData); + buf.open(QIODevice::ReadOnly); + buf.seek(preLen); + QImageReader reader(&buf, format); + QCOMPARE(expected, reader.read()); + if (format != "ppm" && format != "gif") // Known not to work + QCOMPARE(buf.pos(), qint64(preLen+imageDataSize)); +} + + void tst_QImageReader::description_data() { QTest::addColumn("fileName"); -- cgit v0.12 From c7ba0460fe21647181d2ff8c812ddea0e74a2768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Tue, 4 May 2010 15:41:42 +0200 Subject: Pack Graphics View booleans in quint32 bit fields. Reduces the memory footprint of a typical GV application by 27 * sizeof(bool). Nothing revolutionary, but you know, every byte counts :-) Reviewed-by: Jan-Arve --- src/gui/graphicsview/qgraphicsscene.cpp | 16 ++++++------- src/gui/graphicsview/qgraphicsscene_p.h | 40 ++++++++++++++++----------------- src/gui/graphicsview/qgraphicsview.cpp | 17 +++++++------- src/gui/graphicsview/qgraphicsview_p.h | 29 +++++++++++++----------- 4 files changed, 53 insertions(+), 49 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 0d4e48a..36fd5c8 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -290,13 +290,19 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() updateAll(false), calledEmitUpdated(false), processDirtyItemsEmitted(false), - selectionChanging(0), needSortTopLevelItems(true), holesInTopLevelSiblingIndex(false), topLevelSequentialOrdering(true), scenePosDescendantsUpdatePending(false), stickyFocus(false), hasFocus(false), + lastMouseGrabberItemHasImplicitMouseGrab(false), + allItemsIgnoreHoverEvents(true), + allItemsUseDefaultCursor(true), + painterStateProtection(true), + sortCacheEnabled(false), + allItemsIgnoreTouchEvents(true), + selectionChanging(0), rectAdjust(2), focusItem(0), lastFocusItem(0), @@ -306,16 +312,10 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() activationRefCount(0), childExplicitActivation(0), lastMouseGrabberItem(0), - lastMouseGrabberItemHasImplicitMouseGrab(false), dragDropItem(0), enterWidget(0), lastDropAction(Qt::IgnoreAction), - allItemsIgnoreHoverEvents(true), - allItemsUseDefaultCursor(true), - painterStateProtection(true), - sortCacheEnabled(false), - style(0), - allItemsIgnoreTouchEvents(true) + style(0) { } diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 0a85f0e..77bf450 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -97,24 +97,36 @@ public: int lastItemCount; QRectF sceneRect; - bool hasSceneRect; - bool dirtyGrowingItemsBoundingRect; + + quint32 hasSceneRect : 1; + quint32 dirtyGrowingItemsBoundingRect : 1; + quint32 updateAll : 1; + quint32 calledEmitUpdated : 1; + quint32 processDirtyItemsEmitted : 1; + quint32 needSortTopLevelItems : 1; + quint32 holesInTopLevelSiblingIndex : 1; + quint32 topLevelSequentialOrdering : 1; + quint32 scenePosDescendantsUpdatePending : 1; + quint32 stickyFocus : 1; + quint32 hasFocus : 1; + quint32 lastMouseGrabberItemHasImplicitMouseGrab : 1; + quint32 allItemsIgnoreHoverEvents : 1; + quint32 allItemsUseDefaultCursor : 1; + quint32 painterStateProtection : 1; + quint32 sortCacheEnabled : 1; // for compatibility + quint32 allItemsIgnoreTouchEvents : 1; + quint32 padding : 15; + QRectF growingItemsBoundingRect; void _q_emitUpdated(); QList updatedRects; - bool updateAll; - bool calledEmitUpdated; - bool processDirtyItemsEmitted; QPainterPath selectionArea; int selectionChanging; QSet selectedItems; QVector unpolishedItems; QList topLevelItems; - bool needSortTopLevelItems; - bool holesInTopLevelSiblingIndex; - bool topLevelSequentialOrdering; QMap movingItemsInitialPositions; void registerTopLevelItem(QGraphicsItem *item); @@ -125,7 +137,6 @@ public: void _q_processDirtyItems(); QSet scenePosItems; - bool scenePosDescendantsUpdatePending; void setScenePosItemEnabled(QGraphicsItem *item, bool enabled); void registerScenePosItem(QGraphicsItem *item); void unregisterScenePosItem(QGraphicsItem *item); @@ -136,9 +147,6 @@ public: QBrush backgroundBrush; QBrush foregroundBrush; - quint32 stickyFocus : 1; - quint32 hasFocus : 1; - quint32 padding : 30; quint32 rectAdjust; QGraphicsItem *focusItem; QGraphicsItem *lastFocusItem; @@ -155,7 +163,6 @@ public: void removePopup(QGraphicsWidget *widget, bool itemIsDying = false); QGraphicsItem *lastMouseGrabberItem; - bool lastMouseGrabberItemHasImplicitMouseGrab; QList mouseGrabberItems; void grabMouse(QGraphicsItem *item, bool implicit = false); void ungrabMouse(QGraphicsItem *item, bool itemIsDying = false); @@ -172,8 +179,6 @@ public: QList cachedItemsUnderMouse; QList hoverItems; QPointF lastSceneMousePos; - bool allItemsIgnoreHoverEvents; - bool allItemsUseDefaultCursor; void enableMouseTrackingOnViews(); QMap mouseGrabberButtonDownPos; QMap mouseGrabberButtonDownScenePos; @@ -187,8 +192,6 @@ public: void addView(QGraphicsView *view); void removeView(QGraphicsView *view); - bool painterStateProtection; - QMultiMap sceneEventFilters; void installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter); void removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter); @@ -210,8 +213,6 @@ public: void mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent); QGraphicsWidget *windowForItem(const QGraphicsItem *item) const; - bool sortCacheEnabled; // for compatibility - void drawItemHelper(QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget, bool painterStateProtection); @@ -295,7 +296,6 @@ public: int findClosestTouchPointId(const QPointF &scenePos); void touchEventHandler(QTouchEvent *touchEvent); bool sendTouchBeginEvent(QGraphicsItem *item, QTouchEvent *touchEvent); - bool allItemsIgnoreTouchEvents; void enableTouchEventsOnViews(); QList cachedTargetItems; diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 0bba7e9..96d5ba1 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -327,16 +327,20 @@ QGraphicsViewPrivate::QGraphicsViewPrivate() dragMode(QGraphicsView::NoDrag), sceneInteractionAllowed(true), hasSceneRect(false), connectedToScene(false), - mousePressButton(Qt::NoButton), + useLastMouseEvent(false), identityMatrix(true), dirtyScroll(true), accelerateScrolling(true), + keepLastCenterPoint(true), + transforming(false), + handScrolling(false), + mustAllocateStyleOptions(false), + mustResizeBackgroundPixmap(true), + fullUpdatePending(true), + mousePressButton(Qt::NoButton), leftIndent(0), topIndent(0), lastMouseEvent(QEvent::None, QPoint(), Qt::NoButton, 0, 0), - useLastMouseEvent(false), - keepLastCenterPoint(true), alignment(Qt::AlignCenter), - transforming(false), transformationAnchor(QGraphicsView::AnchorViewCenter), resizeAnchor(QGraphicsView::NoAnchor), viewportUpdateMode(QGraphicsView::MinimalViewportUpdate), optimizationFlags(0), @@ -345,14 +349,11 @@ QGraphicsViewPrivate::QGraphicsViewPrivate() rubberBanding(false), rubberBandSelectionMode(Qt::IntersectsItemShape), #endif - handScrolling(false), handScrollMotions(0), cacheMode(0), - mustAllocateStyleOptions(false), - mustResizeBackgroundPixmap(true), + handScrollMotions(0), cacheMode(0), #ifndef QT_NO_CURSOR hasStoredOriginalCursor(false), #endif lastDragDropEvent(0), - fullUpdatePending(true), updateSceneSlotReimplementedChecked(false) { styleOptions.reserve(QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS); diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h index aeff28a..1239ca4 100644 --- a/src/gui/graphicsview/qgraphicsview_p.h +++ b/src/gui/graphicsview/qgraphicsview_p.h @@ -77,11 +77,24 @@ public: QPainter::RenderHints renderHints; QGraphicsView::DragMode dragMode; - bool sceneInteractionAllowed; + + quint32 sceneInteractionAllowed : 1; + quint32 hasSceneRect : 1; + quint32 connectedToScene : 1; + quint32 useLastMouseEvent : 1; + quint32 identityMatrix : 1; + quint32 dirtyScroll : 1; + quint32 accelerateScrolling : 1; + quint32 keepLastCenterPoint : 1; + quint32 transforming : 1; + quint32 handScrolling : 1; + quint32 mustAllocateStyleOptions : 1; + quint32 mustResizeBackgroundPixmap : 1; + quint32 fullUpdatePending : 1; + quint32 padding : 19; + QRectF sceneRect; - bool hasSceneRect; void updateLastCenterPoint(); - bool connectedToScene; qint64 horizontalScroll() const; qint64 verticalScroll() const; @@ -98,26 +111,20 @@ public: QPoint dirtyScrollOffset; Qt::MouseButton mousePressButton; QTransform matrix; - bool identityMatrix; qint64 scrollX, scrollY; - bool dirtyScroll; void updateScroll(); - bool accelerateScrolling; qreal leftIndent; qreal topIndent; // Replaying mouse events QMouseEvent lastMouseEvent; - bool useLastMouseEvent; void replayLastMouseEvent(); void storeMouseEvent(QMouseEvent *event); void mouseMoveEventHandler(QMouseEvent *event); QPointF lastCenterPoint; - bool keepLastCenterPoint; Qt::Alignment alignment; - bool transforming; QGraphicsView::ViewportAnchor transformationAnchor; QGraphicsView::ViewportAnchor resizeAnchor; @@ -131,20 +138,17 @@ public: bool rubberBanding; Qt::ItemSelectionMode rubberBandSelectionMode; #endif - bool handScrolling; int handScrollMotions; QGraphicsView::CacheMode cacheMode; QVector styleOptions; - bool mustAllocateStyleOptions; QStyleOptionGraphicsItem *allocStyleOptionsArray(int numItems); void freeStyleOptionsArray(QStyleOptionGraphicsItem *array); QBrush backgroundBrush; QBrush foregroundBrush; QPixmap backgroundPixmap; - bool mustResizeBackgroundPixmap; QRegion backgroundPixmapExposed; #ifndef QT_NO_CURSOR @@ -161,7 +165,6 @@ public: QRect mapToViewRect(const QGraphicsItem *item, const QRectF &rect) const; QRegion mapToViewRegion(const QGraphicsItem *item, const QRectF &rect) const; - bool fullUpdatePending; QRegion dirtyRegion; QRect dirtyBoundingRect; void processPendingUpdates(); -- cgit v0.12 From 66f1a007291209781801a2d3d5f4009bb1963955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Wed, 5 May 2010 14:02:54 +0200 Subject: Fixes crash in QGraphicsItem::mouseMove for untransformable items. Caused by: 253b87180e0a6c5db0feaaed7e321139c4ff1643 Reviewed-by: Yoann --- src/gui/graphicsview/qgraphicsitem.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 81138d9..b8c240a 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -7132,7 +7132,11 @@ void QGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) // calculate their diff by mapping viewport coordinates // directly to parent coordinates. // COMBINE - QTransform viewToParentTransform = (item->d_func()->transformData->computedFullTransform().translate(item->d_ptr->pos.x(), item->d_ptr->pos.y())) + QTransform itemTransform; + if (item->d_ptr->transformData) + itemTransform = item->d_ptr->transformData->computedFullTransform(); + itemTransform.translate(item->d_ptr->pos.x(), item->d_ptr->pos.y()); + QTransform viewToParentTransform = itemTransform * (item->sceneTransform() * view->viewportTransform()).inverted(); currentParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->screenPos()))); buttonDownParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->buttonDownScreenPos(Qt::LeftButton)))); -- cgit v0.12 From c1c7dbf2a066868503dfabcd7113856fa6d2e457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Tue, 4 May 2010 13:14:10 +0200 Subject: Performance issue with QGraphicsItem::ItemClipsChildrenToShape. If the child rect is bigger than the parent rect and parent has the ItemClipsChildrenToShape flag set, then by updating the child, the whole child rect is marked as dirty, resulting in a much larger update area than required. This has a major impact on performance in Orbit/HB, where e.g. item-views typically consist of a container item that clips its children/items to shape. See attached video in QTBUG-9024. Auto test included. Task-number: QTBUG-9024 --- src/gui/graphicsview/qgraphicsitem.cpp | 20 ++++++++- src/gui/graphicsview/qgraphicsitem_p.h | 1 + src/gui/graphicsview/qgraphicsscene.cpp | 14 +++++- src/gui/graphicsview/qgraphicsview.cpp | 59 +++++++++++++++++++++++++- src/gui/graphicsview/qgraphicsview_p.h | 6 ++- tests/auto/qgraphicsview/tst_qgraphicsview.cpp | 57 +++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 5 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index b8c240a..65edb2a 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1812,7 +1812,7 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations | ItemIsSelectable); bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask); if (fullUpdate) - d_ptr->paintedViewBoundingRectsNeedRepaint = 1; + d_ptr->updatePaintedViewBoundingRects(/*children=*/true); // Keep the old flags to compare the diff. GraphicsItemFlags oldFlags = GraphicsItemFlags(d_ptr->flags); @@ -5432,6 +5432,24 @@ void QGraphicsItemPrivate::removeExtraItemCache() unsetExtra(ExtraCacheData); } +void QGraphicsItemPrivate::updatePaintedViewBoundingRects(bool updateChildren) +{ + if (!scene) + return; + + for (int i = 0; i < scene->d_func()->views.size(); ++i) { + QGraphicsViewPrivate *viewPrivate = scene->d_func()->views.at(i)->d_func(); + QRect rect = paintedViewBoundingRects.value(viewPrivate->viewport); + rect.translate(viewPrivate->dirtyScrollOffset); + viewPrivate->updateRect(rect); + } + + if (updateChildren) { + for (int i = 0; i < children.size(); ++i) + children.at(i)->d_ptr->updatePaintedViewBoundingRects(true); + } +} + // Traverses all the ancestors up to the top-level and updates the pointer to // always point to the top-most item that has a dirty scene transform. // It then backtracks to the top-most dirty item and start calculating the diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 569a329..e812f29 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -377,6 +377,7 @@ public: QGraphicsItemCache *extraItemCache() const; void removeExtraItemCache(); + void updatePaintedViewBoundingRects(bool updateChildren); void ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem); inline void ensureSceneTransform() { diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 36fd5c8..dfba7c9 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5116,9 +5116,15 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool // Process children. if (itemHasChildren && item->d_ptr->dirtyChildren) { + const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape; + if (itemClipsChildrenToShape) { + // Make sure child updates are clipped to the item's bounding rect. + for (int i = 0; i < views.size(); ++i) + views.at(i)->d_func()->setUpdateClip(item); + } if (!dirtyAncestorContainsChildren) { dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending - && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); + && itemClipsChildrenToShape; } const bool allChildrenDirty = item->d_ptr->allChildrenDirty; const bool parentIgnoresVisible = item->d_ptr->ignoreVisible; @@ -5141,6 +5147,12 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool } processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity); } + + if (itemClipsChildrenToShape) { + // Reset updateClip. + for (int i = 0; i < views.size(); ++i) + views.at(i)->d_func()->setUpdateClip(0); + } } else if (wasDirtyParentSceneTransform) { item->d_ptr->invalidateChildrenSceneTransform(); } diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 96d5ba1..0f951ef 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -337,6 +337,7 @@ QGraphicsViewPrivate::QGraphicsViewPrivate() mustAllocateStyleOptions(false), mustResizeBackgroundPixmap(true), fullUpdatePending(true), + hasUpdateClip(false), mousePressButton(Qt::NoButton), leftIndent(0), topIndent(0), lastMouseEvent(QEvent::None, QPoint(), Qt::NoButton, 0, 0), @@ -880,6 +881,52 @@ static inline void QRect_unite(QRect *rect, const QRect &other) } } +/* + Calling this function results in update rects being clipped to the item's + bounding rect. Note that updates prior to this function call is not clipped. + The clip is removed by passing 0. +*/ +void QGraphicsViewPrivate::setUpdateClip(QGraphicsItem *item) +{ + Q_Q(QGraphicsView); + // We simply ignore the request if the update mode is either FullViewportUpdate + // or NoViewportUpdate; in that case there's no point in clipping anything. + if (!item || viewportUpdateMode == QGraphicsView::NoViewportUpdate + || viewportUpdateMode == QGraphicsView::FullViewportUpdate) { + hasUpdateClip = false; + return; + } + + // Calculate the clip (item's bounding rect in view coordinates). + // Optimized version of: + // QRect clip = item->deviceTransform(q->viewportTransform()) + // .mapRect(item->boundingRect()).toAlignedRect(); + QRect clip; + if (item->d_ptr->itemIsUntransformable()) { + QTransform xform = item->deviceTransform(q->viewportTransform()); + clip = xform.mapRect(item->boundingRect()).toAlignedRect(); + } else if (item->d_ptr->sceneTransformTranslateOnly && identityMatrix) { + QRectF r(item->boundingRect()); + r.translate(item->d_ptr->sceneTransform.dx() - horizontalScroll(), + item->d_ptr->sceneTransform.dy() - verticalScroll()); + clip = r.toAlignedRect(); + } else if (!q->isTransformed()) { + clip = item->d_ptr->sceneTransform.mapRect(item->boundingRect()).toAlignedRect(); + } else { + QTransform xform = item->d_ptr->sceneTransform; + xform *= q->viewportTransform(); + clip = xform.mapRect(item->boundingRect()).toAlignedRect(); + } + + if (hasUpdateClip) { + // Intersect with old clip. + updateClip &= clip; + } else { + updateClip = clip; + hasUpdateClip = true; + } +} + bool QGraphicsViewPrivate::updateRegion(const QRectF &rect, const QTransform &xform) { if (rect.isEmpty()) @@ -910,6 +957,8 @@ bool QGraphicsViewPrivate::updateRegion(const QRectF &rect, const QTransform &xf viewRect.adjust(-1, -1, 1, 1); else viewRect.adjust(-2, -2, 2, 2); + if (hasUpdateClip) + viewRect &= updateClip; dirtyRegion += viewRect; } @@ -931,7 +980,10 @@ bool QGraphicsViewPrivate::updateRect(const QRect &r) viewport->update(); break; case QGraphicsView::BoundingRectViewportUpdate: - QRect_unite(&dirtyBoundingRect, r); + if (hasUpdateClip) + QRect_unite(&dirtyBoundingRect, r & updateClip); + else + QRect_unite(&dirtyBoundingRect, r); if (containsViewport(dirtyBoundingRect, viewport->width(), viewport->height())) { fullUpdatePending = true; viewport->update(); @@ -939,7 +991,10 @@ bool QGraphicsViewPrivate::updateRect(const QRect &r) break; case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE case QGraphicsView::MinimalViewportUpdate: - dirtyRegion += r; + if (hasUpdateClip) + dirtyRegion += r & updateClip; + else + dirtyRegion += r; break; default: break; diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h index 1239ca4..7bd9ecb 100644 --- a/src/gui/graphicsview/qgraphicsview_p.h +++ b/src/gui/graphicsview/qgraphicsview_p.h @@ -91,7 +91,8 @@ public: quint32 mustAllocateStyleOptions : 1; quint32 mustResizeBackgroundPixmap : 1; quint32 fullUpdatePending : 1; - quint32 padding : 19; + quint32 hasUpdateClip : 1; + quint32 padding : 18; QRectF sceneRect; void updateLastCenterPoint(); @@ -102,6 +103,7 @@ public: QRectF mapRectToScene(const QRect &rect) const; QRectF mapRectFromScene(const QRectF &rect) const; + QRect updateClip; QPointF mousePressItemPoint; QPointF mousePressScenePoint; QPoint mousePressViewPoint; @@ -195,6 +197,8 @@ public: #endif } + void setUpdateClip(QGraphicsItem *); + inline bool updateRectF(const QRectF &rect) { if (rect.isEmpty()) diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index 1df9a37..b8df7f6 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -218,6 +218,7 @@ private slots: void update(); void update2_data(); void update2(); + void update_ancestorClipsChildrenToShape(); void inputMethodSensitivity(); void inputContextReset(); void indirectPainting(); @@ -3758,6 +3759,62 @@ void tst_QGraphicsView::update2() #endif } +void tst_QGraphicsView::update_ancestorClipsChildrenToShape() +{ + QGraphicsScene scene(-150, -150, 300, 300); + + /* + Add three rects: + + +------------------+ + | child | + | +--------------+ | + | | parent | | + | | +-----------+ | + | | |grandParent| | + | | +-----------+ | + | +--------------+ | + +------------------+ + + ... where both the parent and the grand parent clips children to shape. + */ + QApplication::processEvents(); // Get rid of pending update. + + QGraphicsRectItem *grandParent = static_cast(scene.addRect(0, 0, 50, 50)); + grandParent->setBrush(Qt::black); + grandParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape); + + QGraphicsRectItem *parent = static_cast(scene.addRect(-50, -50, 100, 100)); + parent->setBrush(QColor(0, 0, 255, 125)); + parent->setParentItem(grandParent); + parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape); + + QGraphicsRectItem *child = static_cast(scene.addRect(-100, -100, 200, 200)); + child->setBrush(QColor(255, 0, 0, 125)); + child->setParentItem(parent); + + CustomView view(&scene); + view.show(); + QTest::qWaitForWindowShown(&view); + QTRY_VERIFY(view.painted); + + view.lastUpdateRegions.clear(); + view.painted = false; + + // Call child->update() and make sure the updated area is within the ancestors' clip. + QRectF expected = child->deviceTransform(view.viewportTransform()).mapRect(child->boundingRect()); + expected &= grandParent->deviceTransform(view.viewportTransform()).mapRect(grandParent->boundingRect()); + + child->update(); + QTRY_VERIFY(view.painted); + +#ifndef QT_MAC_USE_COCOA //cocoa doesn't support drawing regions + QTRY_VERIFY(view.painted); + QCOMPARE(view.lastUpdateRegions.size(), 1); + QCOMPARE(view.lastUpdateRegions.at(0), QRegion(expected.toAlignedRect())); +#endif +} + class FocusItem : public QGraphicsRectItem { public: -- cgit v0.12 From 78660bf18ec11e043f1c88d711f62d32237bd0e5 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Tue, 4 May 2010 18:15:35 +0200 Subject: QSortFilterProxyModel: Warning or assert failure A mapping was being created after QStandardItem::dataChanged() signal, even though one of the item's ancestors was being filtered out by the filter proxy. This let the QSortFilterProxyModel in a unstable state, triggering warnings and failing asserts. This patch partialy reverts commit f4bce41c10988. Auto-test included. Reviewed-by: mbm Task-number: QTBUG-10287 --- src/gui/itemviews/qsortfilterproxymodel.cpp | 2 +- .../tst_qsortfilterproxymodel.cpp | 61 ++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index dce5c6a..b12cd45 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -1099,7 +1099,7 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc if (!source_top_left.isValid() || !source_bottom_right.isValid()) return; QModelIndex source_parent = source_top_left.parent(); - IndexMap::const_iterator it = create_mapping(source_parent); + IndexMap::const_iterator it = source_index_mapping.find(source_parent); if (it == source_index_mapping.constEnd()) { // Don't care, since we don't have mapping for this index return; diff --git a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index 2339b21..992c95e 100644 --- a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -138,6 +138,7 @@ private slots: void taskQTBUG_6205_doubleProxySelectionSetSourceModel(); void taskQTBUG_7537_appearsAndSort(); void taskQTBUG_7716_unnecessaryDynamicSorting(); + void taskQTBUG_10287_unnecessaryMapCreation(); void testMultipleProxiesWithSelection(); @@ -3038,5 +3039,65 @@ void tst_QSortFilterProxyModel::testMultipleProxiesWithSelection() } +class Model10287 : public QStandardItemModel +{ + Q_OBJECT + +public: + Model10287(QObject *parent = 0) + : QStandardItemModel(0, 1, parent) + { + parentItem = new QStandardItem("parent"); + parentItem->setData(false, Qt::UserRole); + appendRow(parentItem); + + childItem = new QStandardItem("child"); + childItem->setData(true, Qt::UserRole); + parentItem->appendRow(childItem); + + childItem2 = new QStandardItem("child2"); + childItem2->setData(true, Qt::UserRole); + parentItem->appendRow(childItem2); + } + + void removeChild() + { + childItem2->setData(false, Qt::UserRole); + parentItem->removeRow(0); + } + +private: + QStandardItem *parentItem, *childItem, *childItem2; +}; + +class Proxy10287 : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + Proxy10287(QAbstractItemModel *model, QObject *parent = 0) + : QSortFilterProxyModel(parent) + { + setSourceModel(model); + setDynamicSortFilter(true); + } + +protected: + virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const + { + // Filter based on UserRole in model + QModelIndex i = sourceModel()->index(source_row, 0, source_parent); + return i.data(Qt::UserRole).toBool(); + } +}; + +void tst_QSortFilterProxyModel::taskQTBUG_10287_unnecessaryMapCreation() +{ + Model10287 m; + Proxy10287 p(&m); + m.removeChild(); + // No assert failure, it passes. +} + QTEST_MAIN(tst_QSortFilterProxyModel) #include "tst_qsortfilterproxymodel.moc" -- cgit v0.12 From 8f53bf1b99d32caaebe8cbd1d9bd3a7381821988 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Wed, 5 May 2010 17:41:20 +0200 Subject: Fixed the sizing of the dock area with fixed size dock widgets It could happen that a dock area could be too wide. The problem was that we didn't really care whether or not the tab bar was visible. We would always take its minimum sizehint into account. Task-Number: QTBUG-10391 Reviewed-By: gabi --- src/gui/widgets/qdockarealayout.cpp | 46 +++++++++++++++---------------------- src/gui/widgets/qdockarealayout_p.h | 4 +--- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/gui/widgets/qdockarealayout.cpp b/src/gui/widgets/qdockarealayout.cpp index 806654c..171000b 100644 --- a/src/gui/widgets/qdockarealayout.cpp +++ b/src/gui/widgets/qdockarealayout.cpp @@ -225,7 +225,7 @@ static const int zero = 0; QDockAreaLayoutInfo::QDockAreaLayoutInfo() : sep(&zero), dockPos(QInternal::LeftDock), o(Qt::Horizontal), mainWindow(0) #ifndef QT_NO_TABBAR - , tabbed(false), tabBar(0), tabBarShape(QTabBar::RoundedSouth), tabBarVisible(false) + , tabbed(false), tabBar(0), tabBarShape(QTabBar::RoundedSouth) #endif { } @@ -235,7 +235,7 @@ QDockAreaLayoutInfo::QDockAreaLayoutInfo(const int *_sep, QInternal::DockPositio QMainWindow *window) : sep(_sep), dockPos(_dockPos), o(_o), mainWindow(window) #ifndef QT_NO_TABBAR - , tabbed(false), tabBar(0), tabBarShape(static_cast(tbshape)), tabBarVisible(false) + , tabbed(false), tabBar(0), tabBarShape(static_cast(tbshape)) #endif { #ifdef QT_NO_TABBAR @@ -296,8 +296,8 @@ QSize QDockAreaLayoutInfo::minimumSize() const rperp(o, result) = b; #ifndef QT_NO_TABBAR - if (tabbed) { - QSize tbm = tabBarMinimumSize(); + QSize tbm = tabBarMinimumSize(); + if (!tbm.isNull()) { switch (tabBarShape) { case QTabBar::RoundedNorth: case QTabBar::RoundedSouth: @@ -369,8 +369,8 @@ QSize QDockAreaLayoutInfo::maximumSize() const rperp(o, result) = b; #ifndef QT_NO_TABBAR - if (tabbed) { - QSize tbh = tabBarSizeHint(); + QSize tbh = tabBarSizeHint(); + if (!tbh.isNull()) { switch (tabBarShape) { case QTabBar::RoundedNorth: case QTabBar::RoundedSouth: @@ -1500,7 +1500,7 @@ void QDockAreaLayoutInfo::apply(bool animate) QRect tab_rect; QSize tbh = tabBarSizeHint(); - if (tabBarVisible) { + if (!tbh.isNull()) { switch (tabBarShape) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: @@ -2079,10 +2079,11 @@ void QDockAreaLayoutInfo::updateSeparatorWidgets() const #endif //QT_NO_TABBAR #ifndef QT_NO_TABBAR -void QDockAreaLayoutInfo::updateTabBar() const +//returns whether the tabbar is visible or not +bool QDockAreaLayoutInfo::updateTabBar() const { if (!tabbed) - return; + return false; QDockAreaLayoutInfo *that = const_cast(this); @@ -2150,12 +2151,8 @@ void QDockAreaLayoutInfo::updateTabBar() const tabBar->blockSignals(blocked); - that->tabBarVisible = ( (gap ? 1 : 0) + tabBar->count()) > 1; - - if (changed || !tabBarMin.isValid() | !tabBarHint.isValid()) { - that->tabBarMin = tabBar->minimumSizeHint(); - that->tabBarHint = tabBar->sizeHint(); - } + //returns if the tabbar is visible or not + return ( (gap ? 1 : 0) + tabBar->count()) > 1; } void QDockAreaLayoutInfo::setTabBarShape(int shape) @@ -2163,11 +2160,8 @@ void QDockAreaLayoutInfo::setTabBarShape(int shape) if (shape == tabBarShape) return; tabBarShape = shape; - if (tabBar != 0) { + if (tabBar != 0) tabBar->setShape(static_cast(shape)); - tabBarMin = QSize(); - tabBarHint = QSize(); - } for (int i = 0; i < item_list.count(); ++i) { QDockAreaLayoutItem &item = item_list[i]; @@ -2178,22 +2172,18 @@ void QDockAreaLayoutInfo::setTabBarShape(int shape) QSize QDockAreaLayoutInfo::tabBarMinimumSize() const { - if (!tabbed) + if (!updateTabBar()) return QSize(0, 0); - updateTabBar(); - - return tabBarMin; + return tabBar->minimumSizeHint(); } QSize QDockAreaLayoutInfo::tabBarSizeHint() const { - if (!tabbed) + if (!updateTabBar()) return QSize(0, 0); - updateTabBar(); - - return tabBarHint; + return tabBar->sizeHint(); } QSet QDockAreaLayoutInfo::usedTabBars() const @@ -2240,7 +2230,7 @@ QRect QDockAreaLayoutInfo::tabContentRect() const QRect result = rect; QSize tbh = tabBarSizeHint(); - if (tabBarVisible) { + if (!tbh.isNull()) { switch (tabBarShape) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: diff --git a/src/gui/widgets/qdockarealayout_p.h b/src/gui/widgets/qdockarealayout_p.h index 0088f00..9cb77ba 100644 --- a/src/gui/widgets/qdockarealayout_p.h +++ b/src/gui/widgets/qdockarealayout_p.h @@ -208,11 +208,9 @@ public: QRect tabContentRect() const; bool tabbed; QTabBar *tabBar; - QSize tabBarMin, tabBarHint; int tabBarShape; - bool tabBarVisible; - void updateTabBar() const; + bool updateTabBar() const; void setTabBarShape(int shape); QSize tabBarMinimumSize() const; QSize tabBarSizeHint() const; -- cgit v0.12 From 4a934cb8bb610119367f918957d871fbbc2799ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Thu, 6 May 2010 14:17:47 +0200 Subject: Some EGL implementations does not return a EGLNativeDisplayType when using EGL_DEFAULT_DISPLAY. Actualy what was being returned was a void * Reviewed-by: Andy Nichols --- src/gui/egl/qegl_qws.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/egl/qegl_qws.cpp b/src/gui/egl/qegl_qws.cpp index 56383a5..50db397 100644 --- a/src/gui/egl/qegl_qws.cpp +++ b/src/gui/egl/qegl_qws.cpp @@ -94,7 +94,7 @@ void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) EGLNativeDisplayType QEgl::nativeDisplay() { - return EGL_DEFAULT_DISPLAY; + return EGLNativeDisplayType(EGL_DEFAULT_DISPLAY); } EGLNativeWindowType QEgl::nativeWindow(QWidget* widget) -- cgit v0.12 From 153f9f34008c0205cbbb88d03e7991aba932c913 Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Fri, 7 May 2010 14:32:49 +1000 Subject: Fix auto-test failure on Mac/Linux/QWS. / should not be present in the completer -> it's the current dir. This regression happened due to a bug fix i did so the auto-test was relying on a bug :D. Reviewed-by:TrustMe --- tests/auto/qfiledialog/tst_qfiledialog.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/auto/qfiledialog/tst_qfiledialog.cpp b/tests/auto/qfiledialog/tst_qfiledialog.cpp index 38a1ee7..ca7c445 100644 --- a/tests/auto/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/qfiledialog/tst_qfiledialog.cpp @@ -529,10 +529,6 @@ void tst_QFiledialog::completer() #endif ++expected; } -#if !defined(Q_OS_WIN) - if (inputStartsWithRootPath) - expected++; -#endif } QTest::qWait(1000); -- cgit v0.12 From f380ab3106cb6d39087adacd77f618184f6f90c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Thu, 6 May 2010 19:07:39 +0200 Subject: Fixed bug in QIODevice::read after first reading 0 bytes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change 02532ec80375c686503c4250c6ad6bb211515ec8 removed the early-exit for 0 byte reads, causing us to hit code that assumed the buffer was empty since nothing was read. It would thus read more into the end of the buffer, causing the buffer to grow bigger than QIODEVICE_BUFFERSIZE. Next, if the actual number of bytes we wanted to read was bigger than the original buffer size we'd read the same data twice. Reviewed-by: João Abecasis Reviewed-by: Thiago Macieira --- src/corelib/io/qiodevice.cpp | 3 +++ tests/auto/qbuffer/tst_qbuffer.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index bb11d6b..223df9b 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -810,6 +810,9 @@ qint64 QIODevice::read(char *data, qint64 maxSize) } } + if (!maxSize) + return readSoFar; + if ((d->openMode & Unbuffered) == 0 && maxSize < QIODEVICE_BUFFERSIZE) { // In buffered mode, we try to fill up the QIODevice buffer before // we do anything else. diff --git a/tests/auto/qbuffer/tst_qbuffer.cpp b/tests/auto/qbuffer/tst_qbuffer.cpp index fcef6a3..dd5ca91 100644 --- a/tests/auto/qbuffer/tst_qbuffer.cpp +++ b/tests/auto/qbuffer/tst_qbuffer.cpp @@ -76,6 +76,7 @@ private slots: void atEnd(); void readLineBoundaries(); void writeAfterQByteArrayResize(); + void read_null(); protected slots: void readyReadSlot(); @@ -529,5 +530,30 @@ void tst_QBuffer::writeAfterQByteArrayResize() QCOMPARE(buffer.buffer().size(), 1000); } +void tst_QBuffer::read_null() +{ + QByteArray buffer; + buffer.resize(32000); + for (int i = 0; i < buffer.size(); ++i) + buffer[i] = char(i & 0xff); + + QBuffer in(&buffer); + in.open(QIODevice::ReadOnly); + + QByteArray chunk; + + chunk.resize(16380); + in.read(chunk.data(), 16380); + + QCOMPARE(chunk, buffer.mid(0, chunk.size())); + + in.read(chunk.data(), 0); + + chunk.resize(8); + in.read(chunk.data(), chunk.size()); + + QCOMPARE(chunk, buffer.mid(16380, chunk.size())); +} + QTEST_MAIN(tst_QBuffer) #include "tst_qbuffer.moc" -- cgit v0.12 From e5233c4fd9a6f80ec5251cb847d08d7a088301a2 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Fri, 7 May 2010 11:05:10 +0200 Subject: Fix textdrawing under GL on N900. The driver in the N900 doesn't support glCopyTexSubImage or glReadPixels for FBO's that have a GL_ALPHA or POT color attachment. The ifdef'ed code in resize() was a previous attempt to make this work which didn't. We could have changed the texture to be GL_RGBA and changed the texture size to be NPOT, but that would have wasted precious GPU memory and would have been slower, so we waste a bit of system memory instead, by having a QImage copy along with the texture. Reviewed-by: Eskil Reviewed-by: Trond --- src/gui/painting/qtextureglyphcache_p.h | 2 +- .../gl2paintengineex/qtextureglyphcache_gl.cpp | 86 ++++++++++++++-------- .../gl2paintengineex/qtextureglyphcache_gl_p.h | 5 +- 3 files changed, 60 insertions(+), 33 deletions(-) diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index 390fe51..a818978 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -125,7 +125,7 @@ protected: }; -class QImageTextureGlyphCache : public QTextureGlyphCache +class Q_GUI_EXPORT QImageTextureGlyphCache : public QTextureGlyphCache { public: QImageTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix) diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 994c1c9..452d37d 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -42,6 +42,10 @@ #include "qtextureglyphcache_gl_p.h" #include "qpaintengineex_opengl2_p.h" +#if defined QT_OPENGL_ES_2 && !defined(QT_NO_EGL) +#include "private/qeglcontext_p.h" +#endif + QT_BEGIN_NAMESPACE #ifdef Q_WS_WIN @@ -49,12 +53,27 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled; #endif QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix) - : QTextureGlyphCache(type, matrix) + : QImageTextureGlyphCache(type, matrix) , ctx(context) , m_width(0) , m_height(0) + , m_broken_fbo_readback(false) { - glGenFramebuffers(1, &m_fbo); + // broken FBO readback is a bug in the SGX 1.3 and 1.4 drivers for the N900 where + // copying between FBO's is broken if the texture is either GL_ALPHA or POT. The + // workaround is to use a system-memory copy of the glyph cache for this device. + // Switching to NPOT and GL_RGBA would both cost a lot more graphics memory and + // be slower, so that is not desireable. +#if defined QT_OPENGL_ES_2 && !defined(QT_NO_EGL) + if (QByteArray((char*) glGetString(GL_RENDERER)).contains("SGX")) { + QGLContextPrivate *ctxd = context->d_func(); + m_broken_fbo_readback = QByteArray((char *) eglQueryString(ctxd->eglContext->display(), EGL_VERSION)).contains("1.3"); + } +#endif + + if (!m_broken_fbo_readback) + glGenFramebuffers(1, &m_fbo); + connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)), SLOT(contextDestroyed(const QGLContext*))); } @@ -63,7 +82,9 @@ QGLTextureGlyphCache::~QGLTextureGlyphCache() { if (ctx) { QGLShareContextScope scope(ctx); - glDeleteFramebuffers(1, &m_fbo); + + if (!m_broken_fbo_readback) + glDeleteFramebuffers(1, &m_fbo); if (m_width || m_height) glDeleteTextures(1, &m_texture); @@ -72,6 +93,12 @@ QGLTextureGlyphCache::~QGLTextureGlyphCache() void QGLTextureGlyphCache::createTextureData(int width, int height) { + // create in QImageTextureGlyphCache baseclass is meant to be called + // only to create the initial image and does not preserve the content, + // so we don't call when this function is called from resize. + if (m_broken_fbo_readback && image().isNull()) + QImageTextureGlyphCache::createTextureData(width, height); + glGenTextures(1, &m_texture); glBindTexture(GL_TEXTURE_2D, m_texture); @@ -93,14 +120,22 @@ void QGLTextureGlyphCache::createTextureData(int width, int height) void QGLTextureGlyphCache::resizeTextureData(int width, int height) { - // ### the QTextureGlyphCache API needs to be reworked to allow - // ### resizeTextureData to fail - int oldWidth = m_width; int oldHeight = m_height; GLuint oldTexture = m_texture; createTextureData(width, height); + + if (m_broken_fbo_readback) { + QImageTextureGlyphCache::resizeTextureData(width, height); + Q_ASSERT(image().depth() == 8); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, image().constBits()); + glDeleteTextures(1, &oldTexture); + return; + } + + // ### the QTextureGlyphCache API needs to be reworked to allow + // ### resizeTextureData to fail glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo); @@ -159,20 +194,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height) glBindTexture(GL_TEXTURE_2D, m_texture); -#ifdef QT_OPENGL_ES_2 - QDataBuffer buffer(4*oldWidth*oldHeight); - buffer.resize(4*oldWidth*oldHeight); - glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data()); - - // do an in-place conversion from GL_RGBA to GL_ALPHA - for (int i=0; i Date: Thu, 6 May 2010 21:09:50 +0200 Subject: Fix crash with stylesheet if widget change style in the changeEvent The problem appeared with KLineEdit and its proxy style. When setting a stylesheet, we create a QStyleSheetStyle in 9# and set it to the widget, which receive a changeEvent, that will set again the style so 3# will create a new QStyleSheetStyle with the new proxy. and set it. in 2# we will dereference the 'old' QStyleSheetStyle (the one created in #9) that will destroy it. Then, later in #7, we will still access that style ('newStyle') and we crash 0# QStyleSheetStyle::~QStyleSheetStyle() 1# QStyleSheetStyle::deref() 2# QWidgetPrivate::setStyle_helper(QStyle*, bool, bool) 3# QWidget::setStyle(QStyle*) (qwidget.cpp:2523) 4# ChangeEventWidget::changeEvent(QEvent*) [...] 6# QCoreApplication::sendEvent(QObject*, QEvent*) 7# QWidgetPrivate::setStyle_helper(QStyle*, bool, bool) 9# QWidget::setStyleSheet(QString const&) (qwidget.cpp:2470) The solution is to change the order, and do not use 'newstyle' after we sent the event. The origStyle is now protected wy a QWeakPointer, but this is just for safety reason and not related to the crash. Reviewed-by: JBache --- src/gui/kernel/qwidget.cpp | 20 +++++++------- .../auto/qstylesheetstyle/tst_qstylesheetstyle.cpp | 31 +++++++++++++++++++++- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 20d1d30..be0a8a0 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -2535,7 +2535,7 @@ void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate, bool Q_Q(QWidget); QStyle *oldStyle = q->style(); #ifndef QT_NO_STYLE_STYLESHEET - QStyle *origStyle = 0; + QWeakPointer origStyle; #endif #ifdef Q_WS_MAC @@ -2549,7 +2549,7 @@ void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate, bool createExtra(); #ifndef QT_NO_STYLE_STYLESHEET - origStyle = extra->style; + origStyle = extra->style.data(); #endif extra->style = newStyle; } @@ -2578,23 +2578,23 @@ void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate, bool } } - QEvent e(QEvent::StyleChange); - QApplication::sendEvent(q, &e); -#ifdef QT3_SUPPORT - q->styleChange(*oldStyle); -#endif - #ifndef QT_NO_STYLE_STYLESHEET if (!qobject_cast(newStyle)) { - if (const QStyleSheetStyle* cssStyle = qobject_cast(origStyle)) { + if (const QStyleSheetStyle* cssStyle = qobject_cast(origStyle.data())) { cssStyle->clearWidgetFont(q); } } #endif + QEvent e(QEvent::StyleChange); + QApplication::sendEvent(q, &e); +#ifdef QT3_SUPPORT + q->styleChange(*oldStyle); +#endif + #ifndef QT_NO_STYLE_STYLESHEET // dereference the old stylesheet style - if (QStyleSheetStyle *proxy = qobject_cast(origStyle)) + if (QStyleSheetStyle *proxy = qobject_cast(origStyle.data())) proxy->deref(); #endif } diff --git a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp index e0512a9..e370309 100644 --- a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp +++ b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp @@ -98,6 +98,7 @@ private slots: void complexWidgetFocus(); void task188195_baseBackground(); void task232085_spinBoxLineEditBg(); + void changeStyleInChangeEvent(); //at the end because it mess with the style. void widgetStyle(); @@ -1256,7 +1257,7 @@ void tst_QStyleSheetStyle::proxyStyle() QStyleOptionViewItemV4 opt; opt.initFrom(w); opt.features |= QStyleOptionViewItemV2::HasCheckIndicator; - QVERIFY(pb5->style()->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, + QVERIFY(pb5->style()->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &opt, pb5).width() == 3); delete w; delete proxy; @@ -1579,6 +1580,34 @@ void tst_QStyleSheetStyle::task232085_spinBoxLineEditBg() .toLocal8Bit().constData()); } +class ChangeEventWidget : public QWidget +{ public: + void changeEvent(QEvent * event) + { + if(event->type() == QEvent::StyleChange) { + static bool recurse = false; + if (!recurse) { + recurse = true; + QStyle *style = new QMotifStyle; + style->setParent(this); + setStyle(style); + recurse = false; + } + } + QWidget::changeEvent(event); + } +}; + +void tst_QStyleSheetStyle::changeStyleInChangeEvent() +{ //must not crash; + ChangeEventWidget wid; + wid.ensurePolished(); + wid.setStyleSheet(" /* */ "); + wid.ensurePolished(); + wid.setStyleSheet(" /* ** */ "); + wid.ensurePolished(); +} + QTEST_MAIN(tst_QStyleSheetStyle) #include "tst_qstylesheetstyle.moc" -- cgit v0.12 From 2f9f59d7a33a7cfa5fe2127d726706f10842ca53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 7 May 2010 12:03:12 +0200 Subject: Fixed source pixmap bug in widget graphics effect backend. The source pixmap shouldn't include the window background, as the graphics effect might then overwrite other widgets. Reviewed-by: Jens Bache-Wiig --- src/gui/kernel/qwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index be0a8a0..5d08d4b 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -5628,7 +5628,7 @@ QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint * QPixmap pixmap(effectRect.size()); pixmap.fill(Qt::transparent); - m_widget->render(&pixmap, pixmapOffset); + m_widget->render(&pixmap, pixmapOffset, QRegion(), QWidget::DrawChildren); return pixmap; } #endif //QT_NO_GRAPHICSEFFECT -- cgit v0.12 From 165fe7bdd7958cec3ec6c17f9ca15d92f30a4672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 7 May 2010 12:40:10 +0200 Subject: Fixed scrolling bugs in widget graphics effect backend. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cache wasn't invalidated for widgets with a graphics effect inside a scrolling QScrollArea, so for now we disable caching for widget source pixmaps. Also, we can't clip the source pixmap to device coordinates since there's no knowledge of which areas of the source pixmap the effect uses to compute the visible pixels. See change fd30cc9fabe6fc023 for the graphics item effect backend fix. Reviewed-by: Bjørn Erik Nilsen --- src/gui/effects/qgraphicseffect.cpp | 2 +- src/gui/kernel/qwidget.cpp | 35 +++-------------------------------- 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index ce4ce6a..5e4e49e 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -326,7 +326,7 @@ QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offse } QPixmap pm; - if (d->m_cachedSystem == system && d->m_cachedMode == mode) + if (item && d->m_cachedSystem == system && d->m_cachedMode == mode) QPixmapCache::find(d->m_cacheKey, &pm); if (pm.isNull()) { diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 5d08d4b..c058280 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -5583,47 +5583,18 @@ QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint * pixmapOffset = painterTransform.map(pixmapOffset); } - QRect effectRect; - if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) { + if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) effectRect = m_widget->graphicsEffect()->boundingRectFor(sourceRect).toAlignedRect(); - - } else if (mode == QGraphicsEffect::PadToTransparentBorder) { + else if (mode == QGraphicsEffect::PadToTransparentBorder) effectRect = sourceRect.adjusted(-1, -1, 1, 1).toAlignedRect(); - - } else { + else effectRect = sourceRect.toAlignedRect(); - } - if (offset) *offset = effectRect.topLeft(); - if (deviceCoordinates) { - // Clip to device rect. - int left, top, right, bottom; - effectRect.getCoords(&left, &top, &right, &bottom); - if (left < 0) { - if (offset) - offset->rx() += -left; - effectRect.setX(0); - } - if (top < 0) { - if (offset) - offset->ry() += -top; - effectRect.setY(0); - } - // NB! We use +-1 for historical reasons (see QRect documentation). - QPaintDevice *device = context->painter->device(); - const int deviceWidth = device->width(); - const int deviceHeight = device->height(); - if (right + 1 > deviceWidth) - effectRect.setRight(deviceWidth - 1); - if (bottom + 1 > deviceHeight) - effectRect.setBottom(deviceHeight -1); - } - pixmapOffset -= effectRect.topLeft(); QPixmap pixmap(effectRect.size()); -- cgit v0.12 From cafffc1b161a5b5f2f856c626e8ad2ee50d5d1e1 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 7 May 2010 13:45:12 +0200 Subject: fix tst_QDockWidget::taskQTBUG_9758_undockedGeometry on Linux --- tests/auto/qdockwidget/tst_qdockwidget.cpp | 31 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/auto/qdockwidget/tst_qdockwidget.cpp b/tests/auto/qdockwidget/tst_qdockwidget.cpp index 8d9e7bbf..3ac0ce7 100644 --- a/tests/auto/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/qdockwidget/tst_qdockwidget.cpp @@ -654,7 +654,7 @@ void tst_QDockWidget::dockLocationChanged() QCOMPARE(qvariant_cast(spy.at(0).at(0)), Qt::TopDockWidgetArea); spy.clear(); - + dw.setFloating(true); QTest::qWait(100); dw.setFloating(false); @@ -881,20 +881,21 @@ void tst_QDockWidget::taskQTBUG_1665_closableChanged() void tst_QDockWidget::taskQTBUG_9758_undockedGeometry() { - QMainWindow window; - QDockWidget dock1(&window); - QDockWidget dock2(&window); - window.addDockWidget(Qt::RightDockWidgetArea, &dock1); - window.addDockWidget(Qt::RightDockWidgetArea, &dock2); - window.tabifyDockWidget(&dock1, &dock2); - dock1.hide(); - dock2.hide(); - window.show(); - dock1.setFloating(true); - dock1.show(); - - QVERIFY(dock1.x() >= 0); - QVERIFY(dock1.y() >= 0); + QMainWindow window; + QDockWidget dock1(&window); + QDockWidget dock2(&window); + window.addDockWidget(Qt::RightDockWidgetArea, &dock1); + window.addDockWidget(Qt::RightDockWidgetArea, &dock2); + window.tabifyDockWidget(&dock1, &dock2); + dock1.hide(); + dock2.hide(); + window.show(); + dock1.setFloating(true); + dock1.show(); + QTest::qWaitForWindowShown(&dock1); + + QVERIFY(dock1.x() >= 0); + QVERIFY(dock1.y() >= 0); } -- cgit v0.12 From cb3f3858555bb5b385ee42bb51c4011b21779506 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 7 May 2010 16:12:10 +0200 Subject: Mark QFileDialog::Options as a Q_FLAGS So it can be inspected with designer Task-number: QTBUG-10323 Reviewed-by: jbache --- src/gui/dialogs/qfiledialog.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/dialogs/qfiledialog.h b/src/gui/dialogs/qfiledialog.h index 97fac4e..16cb317 100644 --- a/src/gui/dialogs/qfiledialog.h +++ b/src/gui/dialogs/qfiledialog.h @@ -67,6 +67,7 @@ class Q_GUI_EXPORT QFileDialog : public QDialog { Q_OBJECT Q_ENUMS(ViewMode FileMode AcceptMode Option) + Q_FLAGS(Options) Q_PROPERTY(ViewMode viewMode READ viewMode WRITE setViewMode) Q_PROPERTY(FileMode fileMode READ fileMode WRITE setFileMode) Q_PROPERTY(AcceptMode acceptMode READ acceptMode WRITE setAcceptMode) -- cgit v0.12 From a863691765b1788a17a67e826f483b68f0f34066 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 10 May 2010 10:11:18 +0200 Subject: Stabilize tst_QDockWidget::taskQTBUG_9758_undockedGeometry --- tests/auto/qdockwidget/tst_qdockwidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/qdockwidget/tst_qdockwidget.cpp b/tests/auto/qdockwidget/tst_qdockwidget.cpp index 3ac0ce7..2059101 100644 --- a/tests/auto/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/qdockwidget/tst_qdockwidget.cpp @@ -890,6 +890,7 @@ void tst_QDockWidget::taskQTBUG_9758_undockedGeometry() dock1.hide(); dock2.hide(); window.show(); + QTest::qWaitForWindowShown(&window); dock1.setFloating(true); dock1.show(); QTest::qWaitForWindowShown(&dock1); -- cgit v0.12 From 37b45fe0415bd6695640b26eb7545280b2e8ffe1 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 7 May 2010 16:23:10 +0200 Subject: Fix off-by-one in text layouts and widget size hints on Mac The mac font engine was made to return fractional values. This has exposed a few bugs where the rounded height of the font was used for text layouts and widget size hints. Since a fractional part of the font's height also creates pixels, rounding the height down in these cases is always wrong. The biggest culprit was QScriptLine::height. This is used to lay out text lines and returning a fractional height created problems all over the place. Rather than ceil the number in all places where it is used, we simply return a ceiled value for the line's height. In 4.6, this value would be qRound(ascent)+qRound(descent)+1, which would in some cases cause the previous and current line to overlap by one pixel. By ceiling the sum of the two, we guarantee that the text line contains the complete bounds of the font. A note about the removal of the code that gets the font metrics for QSmallFont: The condition would never be true since this is inside a branch which is only evaluated if fontIsSet is true. Task-number: QTBUG-9971 Reviewed-by: Gunnar --- src/gui/styles/qmacstyle_mac.mm | 20 +++++++++++--------- src/gui/text/qtextengine_p.h | 2 +- src/gui/widgets/qcombobox.cpp | 3 ++- src/gui/widgets/qcommandlinkbutton.cpp | 3 ++- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/gui/styles/qmacstyle_mac.mm b/src/gui/styles/qmacstyle_mac.mm index f5b0b0c..e065bcc 100644 --- a/src/gui/styles/qmacstyle_mac.mm +++ b/src/gui/styles/qmacstyle_mac.mm @@ -97,6 +97,7 @@ #include #include #include +#include #include #include #include @@ -2142,6 +2143,9 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW // The combo box popup has no frame. if (qstyleoption_cast(opt) != 0) ret = 0; + // Frame of mac style line edits is two pixels on top and one on the bottom + else if (qobject_cast(widget) != 0) + ret = 2; else ret = 1; break; @@ -5437,14 +5441,12 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op CGFloat height; QCFString groupText = qt_mac_removeMnemonics(groupBox->text); HIThemeGetTextDimensions(groupText, 0, &tti, &width, &height, 0); - tw = int(width); - h = int(height); + tw = qRound(width); + h = qCeil(height); } else { - QFontMetrics fm = groupBox->fontMetrics; - if (!checkable && !fontIsSet) - fm = QFontMetrics(qt_app_fonts_hash()->value("QSmallFont", QFont())); - h = fm.height(); - tw = fm.size(Qt::TextShowMnemonic, groupBox->text).width(); + QFontMetricsF fm = QFontMetricsF(groupBox->fontMetrics); + h = qCeil(fm.height()); + tw = qCeil(fm.size(Qt::TextShowMnemonic, groupBox->text).width()); } ret.setHeight(h); @@ -5491,10 +5493,10 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op fm = QFontMetrics(qt_app_fonts_hash()->value("QSmallFont", QFont())); yOffset = 5; if (hasNoText) - yOffset = -fm.height(); + yOffset = -qCeil(QFontMetricsF(fm).height()); } - ret = opt->rect.adjusted(0, fm.height() + yOffset, 0, 0); + ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0); if (sc == SC_GroupBoxContents) ret.adjust(3, 3, -3, -4); // guess } diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 5054b66..d92148f 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -389,7 +389,7 @@ struct Q_AUTOTEST_EXPORT QScriptLine mutable uint gridfitted : 1; uint hasTrailingSpaces : 1; uint leadingIncluded : 1; - QFixed height() const { return ascent + descent + 1 + QFixed height() const { return (ascent + descent).ceil() + 1 + (leadingIncluded? qMax(QFixed(),leading) : QFixed()); } QFixed base() const { return ascent + (leadingIncluded ? qMax(QFixed(),leading) : QFixed()); } diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index ca58e6d..e0b09aa 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #ifndef QT_NO_IM #include "qinputcontext.h" #endif @@ -328,7 +329,7 @@ QSize QComboBoxPrivate::recomputeSizeHint(QSize &sh) const // height - sh.setHeight(qMax(fm.height(), 14) + 2); + sh.setHeight(qMax(qCeil(QFontMetricsF(fm).height()), 14) + 2); if (hasIcon) { sh.setHeight(qMax(sh.height(), iconSize.height() + 2)); } diff --git a/src/gui/widgets/qcommandlinkbutton.cpp b/src/gui/widgets/qcommandlinkbutton.cpp index 6919bc0..e8fe299 100644 --- a/src/gui/widgets/qcommandlinkbutton.cpp +++ b/src/gui/widgets/qcommandlinkbutton.cpp @@ -46,6 +46,7 @@ #include "qtextlayout.h" #include "qcolor.h" #include "qfont.h" +#include #include "private/qpushbutton_p.h" @@ -242,7 +243,7 @@ int QCommandLinkButtonPrivate::descriptionHeight(int widgetWidth) const } layout.endLayout(); } - return qRound(descriptionheight); + return qCeil(descriptionheight); } /*! -- cgit v0.12 From abcec6ba4b126358c50bf4c539253f88da6bb2d6 Mon Sep 17 00:00:00 2001 From: Nicolai de Haan Date: Wed, 5 May 2010 16:54:34 +0200 Subject: Opt out of visual-config size checks with extension EGL_NV_post_convert_replication. QTBUG-9444. Task-number: QTBUG-9444 Merge-request: 612 Reviewed-by: Trond --- src/gui/egl/qegl_x11.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/egl/qegl_x11.cpp b/src/gui/egl/qegl_x11.cpp index cb8dcda..969acc4 100644 --- a/src/gui/egl/qegl_x11.cpp +++ b/src/gui/egl/qegl_x11.cpp @@ -163,6 +163,11 @@ VisualID QEgl::getCompatibleVisualId(EGLConfig config) int matchingCount = 0; chosenVisualInfo = XGetVisualInfo(X11->display, VisualIDMask, &visualInfoTemplate, &matchingCount); if (chosenVisualInfo) { + // Skip size checks if implementation supports non-matching visual + // and config (http://bugreports.qt.nokia.com/browse/QTBUG-9444). + if (QEgl::hasExtension("EGL_NV_post_convert_replication")) + return visualId; + int visualRedSize = countBits(chosenVisualInfo->red_mask); int visualGreenSize = countBits(chosenVisualInfo->green_mask); int visualBlueSize = countBits(chosenVisualInfo->blue_mask); -- cgit v0.12 From ae09e6a14dce54190758428a9ea369cd28d36d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 10 May 2010 15:23:09 +0200 Subject: Made paint engine texture drawing work in GL ES 2 and updated docs. Now QGLWidget::drawTexture() can be used on OpenGL ES 2.0 when there's an active painter. Task-number: QTBUG-10420 Reviewed-by: Trond --- src/opengl/qgl.cpp | 73 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index cfacf26..a3c1bac 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2773,23 +2773,27 @@ static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint tex /*! \since 4.4 - Draws the given texture, \a textureId, to the given target rectangle, - \a target, in OpenGL model space. The \a textureTarget should be a 2D - texture target. + This function supports the following use cases: + + \list + \i On OpenGL and OpenGL ES 1.x it draws the given texture, \a textureId, + to the given target rectangle, \a target, in OpenGL model space. The + \a textureTarget should be a 2D texture target. + \i On OpenGL and OpenGL ES 2.x, if a painter is active, not inside a + beginNativePainting / endNativePainting block, and uses the + engine with type QPaintEngine::OpenGL2, the function will draw the given + texture, \a textureId, to the given target rectangle, \a target, + respecting the current painter state. This will let you draw a texture + with the clip, transform, render hints, and composition mode set by the + painter. Note that the texture target needs to be GL_TEXTURE_2D for this + use case, and that this is the only supported use case under OpenGL ES 2.x. + \endlist - \note This function is not supported under OpenGL/ES 2.0. */ void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) { -#ifndef QT_OPENGL_ES_2 -#ifdef QT_OPENGL_ES - if (textureTarget != GL_TEXTURE_2D) { - qWarning("QGLContext::drawTexture(): texture target must be GL_TEXTURE_2D on OpenGL ES"); - return; - } -#else - - if (d_ptr->active_engine && +#if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2) + if (d_ptr->active_engine && d_ptr->active_engine->type() == QPaintEngine::OpenGL2) { QGL2PaintEngineEx *eng = static_cast(d_ptr->active_engine); if (!eng->isNativePaintingActive()) { @@ -2799,7 +2803,15 @@ void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum text return; } } +#endif +#ifndef QT_OPENGL_ES_2 +#ifdef QT_OPENGL_ES + if (textureTarget != GL_TEXTURE_2D) { + qWarning("QGLContext::drawTexture(): texture target must be GL_TEXTURE_2D on OpenGL ES"); + return; + } +#else const bool wasEnabled = glIsEnabled(GL_TEXTURE_2D); GLint oldTexture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexture); @@ -2821,7 +2833,7 @@ void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum text Q_UNUSED(target); Q_UNUSED(textureId); Q_UNUSED(textureTarget); - qWarning("drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) not supported with OpenGL ES/2.0"); + qWarning("drawTexture() with OpenGL ES 2.0 requires an active OpenGL2 paint engine"); #endif } @@ -2836,14 +2848,26 @@ void QGLContext::drawTexture(const QRectF &target, QMacCompatGLuint textureId, Q /*! \since 4.4 - Draws the given texture at the given \a point in OpenGL model - space. The \a textureTarget should be a 2D texture target. + This function supports the following use cases: + + \list + \i By default it draws the given texture, \a textureId, + at the given \a point in OpenGL model space. The + \a textureTarget should be a 2D texture target. + \i If a painter is active, not inside a + beginNativePainting / endNativePainting block, and uses the + engine with type QPaintEngine::OpenGL2, the function will draw the given + texture, \a textureId, at the given \a point, + respecting the current painter state. This will let you draw a texture + with the clip, transform, render hints, and composition mode set by the + painter. Note that the texture target needs to be GL_TEXTURE_2D for this + use case. + \endlist - \note This function is not supported under OpenGL/ES. + \note This function is not supported under any version of OpenGL ES. */ void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget) { - // this would be ok on OpenGL ES 2.0, but currently we don't have a define for that #ifdef QT_OPENGL_ES Q_UNUSED(point); Q_UNUSED(textureId); @@ -4911,11 +4935,8 @@ void QGLWidget::deleteTexture(QMacCompatGLuint id) /*! \since 4.4 - Draws the given texture, \a textureId to the given target rectangle, - \a target, in OpenGL model space. The \a textureTarget should be a 2D - texture target. - - Equivalent to the corresponding QGLContext::drawTexture(). + Calls the corresponding QGLContext::drawTexture() on + this widget's context. */ void QGLWidget::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) { @@ -4935,10 +4956,8 @@ void QGLWidget::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QM /*! \since 4.4 - Draws the given texture, \a textureId, at the given \a point in OpenGL - model space. The \a textureTarget should be a 2D texture target. - - Equivalent to the corresponding QGLContext::drawTexture(). + Calls the corresponding QGLContext::drawTexture() on + this widget's context. */ void QGLWidget::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget) { -- cgit v0.12 From e5622ab31b8cd20074fe29c1d597c1d7f4c6e6e8 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Mon, 10 May 2010 16:34:51 +0200 Subject: Fix typos in Elastic Nodes example documentation. Among other things, use \c instead of \e (courier instead of italic). --- doc/src/examples/elasticnodes.qdoc | 124 +++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 59 deletions(-) diff --git a/doc/src/examples/elasticnodes.qdoc b/doc/src/examples/elasticnodes.qdoc index edc62d8..e6e6594 100644 --- a/doc/src/examples/elasticnodes.qdoc +++ b/doc/src/examples/elasticnodes.qdoc @@ -83,7 +83,7 @@ also reimplements \l{QGraphicsItem::shape()}{shape()} to ensure its hit area has an elliptic shape (as opposed to the default bounding rectangle). - For edge management purposes the node provides a simple API for adding + For edge management purposes, the node provides a simple API for adding edges to a node, and for listing all connected edges. The \l{QGraphicsItem::advance()}{advance()} reimplementation is called @@ -126,16 +126,21 @@ \snippet examples/graphicsview/elasticnodes/node.cpp 2 - The \e calculateForces() function implements the elastic forces effect that - pulls and pushes on nodes in the grid. In addition to this algorithm, the - user can move one node around with the mouse. Because we do not want the - two to interfere, we start by checking if this \c Node is the current mouse - grabber item (i.e., QGraphicsScene::mouseGrabberItem()). Because we need to - find all neighboring (but not necessarily connected) nodes, we also make - sure the item is part of a scene in the first place. + There are two ways to move a node. The \c calculateForces() function + implements the elastic effect that pulls and pushes on nodes in the grid. + In addition, the user can directly move one node around with the mouse. + Because we do not want the two approaches to operate at the same time on + the same node, we start \c calculateForces() by checking if this \c Node is + the current mouse grabber item (i.e., QGraphicsScene::mouseGrabberItem()). + Because we need to find all neighboring (but not necessarily connected) + nodes, we also make sure the item is part of a scene in the first place. \snippet examples/graphicsview/elasticnodes/node.cpp 3 + The "elastic" effect comes from an algorithm that applies pushing and + pulling forces. The effect is impressive, and surprisingly simple to + implement. + The algorithm has two steps: the first is to calculate the forces that push the nodes apart, and the second is to subtract the forces that pull the nodes together. First we need to find all the nodes in the graph. We call @@ -143,19 +148,20 @@ qgraphicsitem_cast() to look for \c Node instances. We make use of \l{QGraphicsItem::mapFromItem()}{mapFromItem()} to create a - vector pointing from this node to each other node, in \l{The Graphics View - Coordinate System}{local coordinates}. We use the decomposed components of - this vector to determine the direction and strength of force that apply to - the node. The forces are added up for each node, and weighted so that the - closest nodes are given the strongest force. The sum of all forces are - stored in \e xvel (X-velocity) and \e yvel (Y-velocity). + temporary vector pointing from this node to each other node, in \l{The + Graphics View Coordinate System}{local coordinates}. We use the decomposed + components of this vector to determine the direction and strength of force + that should apply to the node. The forces accumulate for each node, and are + then adjusted so that the closest nodes are given the strongest force, with + rapid degradation when distance increases. The sum of all forces is stored + in \c xvel (X-velocity) and \c yvel (Y-velocity). \snippet examples/graphicsview/elasticnodes/node.cpp 4 - The edges between the nodes represent the forces that pull the nodes - together. By visiting each edge that is connected to this node, we can use - a similar approach as above to find the direction and strength of all - forces. These forces are subtracted from \e xvel and \e yvel. + The edges between the nodes represent forces that pull the nodes together. + By visiting each edge that is connected to this node, we can use a similar + approach as above to find the direction and strength of all pulling forces. + These forces are subtracted from \c xvel and \c yvel. \snippet examples/graphicsview/elasticnodes/node.cpp 5 @@ -166,20 +172,20 @@ \snippet examples/graphicsview/elasticnodes/node.cpp 6 - The final step of \e calculateForces() determines the node's new position. + The final step of \c calculateForces() determines the node's new position. We add the force to the node's current position. We also make sure the new position stays inside of our defined boundaries. We don't actually move the - item in this function; that's done in a separate step, from \e advance(). + item in this function; that's done in a separate step, from \c advance(). \snippet examples/graphicsview/elasticnodes/node.cpp 7 - The \e advance() function updates the item's current position. It is called - from \e GraphWidget::timerEvent(). If the node's position changed, the + The \c advance() function updates the item's current position. It is called + from \c GraphWidget::timerEvent(). If the node's position changed, the function returns true; otherwise false is returned. \snippet examples/graphicsview/elasticnodes/node.cpp 8 - The \e Node's bounding rectangle is a 20x20 sized rectangle centered around + The \c Node's bounding rectangle is a 20x20 sized rectangle centered around its origin (0, 0), adjusted by 2 units in all directions to compensate for the node's outline stroke, and by 3 units down and to the right to make room for a simple drop shadow. @@ -188,8 +194,8 @@ The shape is a simple ellipse. This ensures that you must click inside the node's elliptic shape in order to drag it around. You can test this effect - by running the example, and zooming far enough in so that the nodes become - very large. Without reimplementing \l{QGraphicsItem::shape()}{shape()}, the + by running the example, and zooming far in so that the nodes are very + large. Without reimplementing \l{QGraphicsItem::shape()}{shape()}, the item's hit area would be identical to its bounding rectangle (i.e., rectangular). @@ -197,7 +203,7 @@ This function implements the node's painting. We start by drawing a simple dark gray elliptic drop shadow at (-7, -7), that is, (3, 3) units down and - to the right. + to the right from the top-left corner (-10, -10) of the ellipse. We then draw an ellipse with a radial gradient fill. This fill is either Qt::yellow to Qt::darkYellow when raised, or the opposite when sunken. In @@ -217,8 +223,8 @@ calculations. This notification is the only reason why the nodes need to keep a pointer - back to the \e GraphWidget. Another approach could be to provide such - notification using a signal; in such case, \e Node would need to inherit + back to the \c GraphWidget. Another approach could be to provide such + notification using a signal; in such case, \c Node would need to inherit from QGraphicsObject. \snippet examples/graphicsview/elasticnodes/node.cpp 12 @@ -226,14 +232,14 @@ Because we have set the \l{QGraphicsItem::ItemIsMovable}{ItemIsMovable} flag, we don't need to implement the logic that moves the node according to mouse input; this is already provided for us. We still need to reimplement - the mouse press and release handlers though, to update the nodes' visual + the mouse press and release handlers, though, to update the nodes' visual appearance (i.e., sunken or raised). \section1 Edge Class Definition - The \e Edge class represents the arrow-lines between the nodes in this + The \c Edge class represents the arrow-lines between the nodes in this example. The class is very simple: it maintains a source- and destination - node pointer, and provides an \e adjust() function that makes sure the line + node pointer, and provides an \c adjust() function that makes sure the line starts at the position of the source, and ends at the position of the destination. The edges are the only items that change continuously as forces pull and push on the nodes. @@ -242,13 +248,13 @@ \snippet examples/graphicsview/elasticnodes/edge.h 0 - \e Edge inherits from QGraphicsItem, as it's a simple class that has no use + \c Edge inherits from QGraphicsItem, as it's a simple class that has no use for signals, slots, and properties (compare to QGraphicsObject). The constructor takes two node pointers as input. Both pointers are mandatory in this example. We also provide get-functions for each node. - The \e adjust() function repositions the edge, and the item also implements + The \c adjust() function repositions the edge, and the item also implements \l{QGraphicsItem::boundingRect()}{boundingRect()} and \{QGraphicsItem::paint()}{paint()}. @@ -256,7 +262,7 @@ \snippet examples/graphicsview/elasticnodes/edge.cpp 0 - The \e Edge constructor initializes its arrowSize data member to 10 units; + The \c Edge constructor initializes its \c arrowSize data member to 10 units; this determines the size of the arrow which is drawn in \l{QGraphicsItem::paint()}{paint()}. @@ -265,7 +271,7 @@ This ensures that the edge items are not considered for mouse input at all (i.e., you cannot click the edges). Then, the source and destination pointers are updated, this edge is registered with each node, and we call - \e adjust() to update this edge's start end end position. + \c adjust() to update this edge's start end end position. \snippet examples/graphicsview/elasticnodes/edge.cpp 1 @@ -274,7 +280,7 @@ \snippet examples/graphicsview/elasticnodes/edge.cpp 2 - In \e adjust(), we define two points: \e sourcePoint, and \e destPoint, + In \c adjust(), we define two points: \c sourcePoint, and \c destPoint, pointing at the source and destination nodes' origins respectively. Each point is calculated using \l{The Graphics View Coordinate System}{local coordinates}. @@ -295,7 +301,7 @@ It's important to notice that we call \l{QGraphicsItem::prepareGeometryChange()}{prepareGeometryChange()} in this - function. The reason is that the variables \e sourcePoint and \e destPoint + function. The reason is that the variables \c sourcePoint and \c destPoint are used directly when painting, and they are returned from the \l{QGraphicsItem::boundingRect()}{boundingRect()} reimplementation. We must always call @@ -338,26 +344,26 @@ \section1 GraphWidget Class Definition - \e GraphWidget is a subclass of QGraphicsView, which provides the main + \c GraphWidget is a subclass of QGraphicsView, which provides the main window with scrollbars. \snippet examples/graphicsview/elasticnodes/graphwidget.h 0 - It provides a basic constructor that initializes the scene, an \e + The class provides a basic constructor that initializes the scene, an \c itemMoved() function to notify changes in the scene's node graph, a few event handlers, a reimplementation of \l{QGraphicsView::drawBackground()}{drawBackground()}, and a helper - function for scaling the view by mouse or keyboard. + function for scaling the view by using the mouse wheel or keyboard. \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 0 - \e GraphicsWidget's constructor creates the scene, and because most items - move around most of the time, it sets QGraphicsScene::NoIndex. Then the - scene gets a fixed \l{QGraphicsScene::sceneRect}{scene rectangle}. - The scene is then assigned to the \e GraphWidget view. + \c GraphicsWidget's constructor creates the scene, and because most items + move around most of the time, it sets QGraphicsScene::NoIndex. The scene + then gets a fixed \l{QGraphicsScene::sceneRect}{scene rectangle}, and is + assigned to the \c GraphWidget view. The view enables QGraphicsView::CacheBackground to cache rendering of its - static and somewhat complex background. Because the graph renders a close + static, and somewhat complex, background. Because the graph renders a close collection of small items that all move around, it's unnecessary for Graphics View to waste time finding accurate update regions, so we set the QGraphicsView::BoundingRectViewportUpdate viewport update mode. The default @@ -381,15 +387,15 @@ \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 2 - \e GraphWidget is notified of node movement through this \e itemMoved() + \c GraphWidget is notified of node movement through this \c itemMoved() function. Its job is simply to restart the main timer in case it's not running already. The timer is designed to stop when the graph stabilizes, and start once it's unstable again. \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 3 - This is \e GraphWidget's key event handler. The arrow keys move the center - node around, the '+' and '-' keys zoom in and out by calling \e + This is \c GraphWidget's key event handler. The arrow keys move the center + node around, the '+' and '-' keys zoom in and out by calling \c scaleView(), and the enter and space keys randomize the positions of the nodes. All other key events (e.g., page up and page down) are handled by QGraphicsView's default implementation. @@ -398,16 +404,16 @@ The timer event handler's job is to run the whole force calculation machinery as a smooth animation. Each time the timer is triggered, the - handler will find all nodes in the scene, and call \e + handler will find all nodes in the scene, and call \c Node::calculateForces() on each node, one at a time. Then, in a final step - it will call \e Node::advance() to move all nodes to their new positions. - By checking the return value of \e advance(), we can decide if the grid + it will call \c Node::advance() to move all nodes to their new positions. + By checking the return value of \c advance(), we can decide if the grid stabilized (i.e., no nodes moved). If so, we can stop the timer. \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 5 In the wheel event handler, we convert the mouse wheel delta to a scale - factor, and pass this factor to \e scaleView(). This approach takes into + factor, and pass this factor to \c scaleView(). This approach takes into account the speed that the wheel is rolled. The faster you roll the mouse wheel, the faster the view will zoom. @@ -415,24 +421,24 @@ The view's background is rendered in a reimplementation of QGraphicsView::drawBackground(). We draw a large rectangle filled with a - linear gradient, with a drop shadow, and then render text in top. The text - is rendered twice to give a similar simple drop-shadow effect. + linear gradient, add a drop shadow, and then render text on top. The text + is rendered twice for a simple drop-shadow effect. This background rendering is quite expensive; this is why the view enables QGraphicsView::CacheBackground. \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 7 - The \e scaleView() helper function checks that the scale factor stays + The \c scaleView() helper function checks that the scale factor stays within certain limits (i.e., you cannot zoom too far in nor too far out), - and then applies this scale. + and then applies this scale to the view. \section1 The main() Function - In contrast to the complexity of the rest of this example, the \e main() + In contrast to the complexity of the rest of this example, the \c main() function is very simple: We create a QApplication instance, seed the - randomizer using qsrand(), and then create and show an instance of \e - GraphWidget. Because all nodes in the grid are moved initially, the \e + randomizer using qsrand(), and then create and show an instance of \c + GraphWidget. Because all nodes in the grid are moved initially, the \c GraphWidget timer will start immediately after control has returned to the event loop. */ -- cgit v0.12 From 121e325e7bb2f14f4c9e4e25078ac16b47dcd372 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 10 May 2010 21:13:21 +0200 Subject: Really fix tst_QDockWidget::taskQTBUG_9758_undockedGeometry on Linux If there is no window manager the current coordinate are taken in account even if WA_Moved is false. When a dockwidget is hidden, it is sent far in the negative coordinate. The test was failing because the WM is assync and may take some time to update the geometry. --- src/gui/widgets/qdockwidget.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/qdockwidget.cpp b/src/gui/widgets/qdockwidget.cpp index ae00710..11f0a94 100644 --- a/src/gui/widgets/qdockwidget.cpp +++ b/src/gui/widgets/qdockwidget.cpp @@ -1269,8 +1269,11 @@ void QDockWidget::setFloating(bool floating) QRect r = d->undockedGeometry; d->setWindowState(floating, false, floating ? r : QRect()); + if (floating && r.isNull()) { - setAttribute(Qt::WA_Moved, false); //we want it at the default position + if (x() < 0 || y() < 0) //may happen if we have been hidden + move(QPoint()); + setAttribute(Qt::WA_Moved, false); //we want it at the default position } } -- cgit v0.12 From a7b128ae838b006be1259ef6ba79da5440ed52dd Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 11 May 2010 09:59:56 +0200 Subject: Stabilize tst_QColumnView::parentCurrentIndex --- tests/auto/qcolumnview/tst_qcolumnview.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/auto/qcolumnview/tst_qcolumnview.cpp b/tests/auto/qcolumnview/tst_qcolumnview.cpp index 90f499d..1da8c5d 100644 --- a/tests/auto/qcolumnview/tst_qcolumnview.cpp +++ b/tests/auto/qcolumnview/tst_qcolumnview.cpp @@ -596,11 +596,11 @@ void tst_QColumnView::clicked() QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, localPoint); QCOMPARE(clickedSpy.count(), 1); qApp->processEvents(); - + if (sizeof(qreal) != sizeof(double)) { QSKIP("Skipped due to rounding errors", SkipAll); } - + for (int i = 0; i < view.createdColumns.count(); ++i) { QAbstractItemView *column = view.createdColumns.at(i); if (column && column->selectionModel() && (column->rootIndex() == home)) @@ -961,9 +961,9 @@ void tst_QColumnView::parentCurrentIndex() QVERIFY(third.isValid()); view.setCurrentIndex(third); QTest::qWait(ANIMATION_DELAY); - QCOMPARE(view.createdColumns[0]->currentIndex(), first); - QCOMPARE(view.createdColumns[1]->currentIndex(), second); - QCOMPARE(view.createdColumns[2]->currentIndex(), third); + QTRY_COMPARE(view.createdColumns[0]->currentIndex(), first); + QTRY_COMPARE(view.createdColumns[1]->currentIndex(), second); + QTRY_COMPARE(view.createdColumns[2]->currentIndex(), third); first = model.index(0, 0, QModelIndex()); second = model.index(secondRow, 0, first); -- cgit v0.12 From 814f7d3d607edacca091273302297b6b2674424f Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 11 May 2010 12:49:32 +0200 Subject: Fix compiler warning in QT_REQUIRE_VERSION warning: format not a string literal and no format arguments Task-number: QTBUG-8967 Reviewed-by: Gabriel --- src/gui/dialogs/qmessagebox.h | 2 +- tests/auto/qmessagebox/tst_qmessagebox.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/dialogs/qmessagebox.h b/src/gui/dialogs/qmessagebox.h index bc6170d..f1ff6cc 100644 --- a/src/gui/dialogs/qmessagebox.h +++ b/src/gui/dialogs/qmessagebox.h @@ -354,7 +354,7 @@ if (!qApp){ \ QString s = QApplication::tr("Executable '%1' requires Qt "\ "%2, found Qt %3.").arg(qAppName()).arg(QString::fromLatin1(\ str)).arg(QString::fromLatin1(qVersion())); QMessageBox::critical(0, QApplication::tr(\ -"Incompatible Qt Library Error"), s, QMessageBox::Abort, 0); qFatal(s.toLatin1().data()); }} +"Incompatible Qt Library Error"), s, QMessageBox::Abort, 0); qFatal("%s", s.toLatin1().data()); }} #endif // QT_NO_MESSAGEBOX diff --git a/tests/auto/qmessagebox/tst_qmessagebox.cpp b/tests/auto/qmessagebox/tst_qmessagebox.cpp index 2de1c52..d4ca064 100644 --- a/tests/auto/qmessagebox/tst_qmessagebox.cpp +++ b/tests/auto/qmessagebox/tst_qmessagebox.cpp @@ -140,6 +140,8 @@ private: tst_QMessageBox::tst_QMessageBox() : keyToSend(-1) { + int argc = qApp->argc(); + QT_REQUIRE_VERSION(argc, qApp->argv(), "4.6.2") } int tst_QMessageBox::exec(QMessageBox *msgBox, int key) -- cgit v0.12 From ad7988629c47a5fc1a671d36d9cdaed630f5e7f2 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 12 May 2010 09:24:39 +0200 Subject: Stabilize tst_QWidgetAction::visibilityUpdate --- tests/auto/qwidgetaction/tst_qwidgetaction.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/auto/qwidgetaction/tst_qwidgetaction.cpp b/tests/auto/qwidgetaction/tst_qwidgetaction.cpp index 5dfcd43..53dc4b5 100644 --- a/tests/auto/qwidgetaction/tst_qwidgetaction.cpp +++ b/tests/auto/qwidgetaction/tst_qwidgetaction.cpp @@ -51,6 +51,8 @@ #include #include +#include "../../shared/util.h" + //TESTED_CLASS= //TESTED_FILES= @@ -190,8 +192,8 @@ void tst_QWidgetAction::visibilityUpdate() QVERIFY(action->isVisible()); action->setVisible(false); - QTest::qWait(100); //the call to hide is delayed by the toolbar layout - QVERIFY(!combo->isVisible()); + qApp->processEvents(); //the call to hide is delayed by the toolbar layout + QTRY_VERIFY(!combo->isVisible()); delete action; // action also deletes combo -- cgit v0.12 From 9b6041bf62cfd2b0be62134ff6ee0fd488ce5921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Wed, 12 May 2010 12:37:47 +0200 Subject: Modified QPainter and QPixmap benchmarks to use raster pixmaps. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These benchmarks are not written in a way that supports robust benchmarking of asynchronous pixmap backends. Reviewed-by: Bjørn Erik Nilsen --- tests/benchmarks/gui/image/qpixmap/tst_qpixmap.cpp | 38 +++++++++-- .../gui/painting/qpainter/tst_qpainter.cpp | 79 +++++++++++++++------- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/tests/benchmarks/gui/image/qpixmap/tst_qpixmap.cpp b/tests/benchmarks/gui/image/qpixmap/tst_qpixmap.cpp index 9ffbefb..8e9de4a 100644 --- a/tests/benchmarks/gui/image/qpixmap/tst_qpixmap.cpp +++ b/tests/benchmarks/gui/image/qpixmap/tst_qpixmap.cpp @@ -43,6 +43,7 @@ #include #include #include +#include class tst_QPixmap : public QObject { @@ -67,6 +68,31 @@ Q_DECLARE_METATYPE(QImage::Format) Q_DECLARE_METATYPE(Qt::AspectRatioMode) Q_DECLARE_METATYPE(Qt::TransformationMode) +QPixmap rasterPixmap(int width, int height) +{ + QPixmapData *data = + new QRasterPixmapData(QPixmapData::PixmapType); + + data->resize(width, height); + + return QPixmap(data); +} + +QPixmap rasterPixmap(const QSize &size) +{ + return rasterPixmap(size.width(), size.height()); +} + +QPixmap rasterPixmap(const QImage &image) +{ + QPixmapData *data = + new QRasterPixmapData(QPixmapData::PixmapType); + + data->fromImage(image, Qt::AutoColor); + + return QPixmap(data); +} + tst_QPixmap::tst_QPixmap() { } @@ -90,7 +116,7 @@ void tst_QPixmap::fill() QFETCH(int, height); const QColor color = opaque ? QColor(255, 0, 0) : QColor(255, 0, 0, 200); - QPixmap pixmap(width, height); + QPixmap pixmap = rasterPixmap(width, height); QBENCHMARK { pixmap.fill(color); @@ -126,8 +152,8 @@ void tst_QPixmap::scaled() QFETCH(Qt::AspectRatioMode, ratioMode); QFETCH(Qt::TransformationMode, transformMode); - QPixmap opaque(size); - QPixmap transparent(size); + QPixmap opaque = rasterPixmap(size); + QPixmap transparent = rasterPixmap(size); opaque.fill(QColor(255, 0, 0)); transparent.fill(QColor(255, 0, 0, 200)); @@ -180,8 +206,8 @@ void tst_QPixmap::transformed() QFETCH(QTransform, transform); QFETCH(Qt::TransformationMode, transformMode); - QPixmap opaque(size); - QPixmap transparent(size); + QPixmap opaque = rasterPixmap(size); + QPixmap transparent = rasterPixmap(size); opaque.fill(QColor(255, 0, 0)); transparent.fill(QColor(255, 0, 0, 200)); @@ -209,7 +235,7 @@ void tst_QPixmap::mask() { QFETCH(QSize, size); - QPixmap src(size); + QPixmap src = rasterPixmap(size); src.fill(Qt::transparent); { QPainter p(&src); diff --git a/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp b/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp index d570bb3..318b671 100644 --- a/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp +++ b/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp @@ -50,6 +50,8 @@ #define M_PI 3.14159265358979323846 #endif +#include + Q_DECLARE_METATYPE(QLine) Q_DECLARE_METATYPE(QRect) Q_DECLARE_METATYPE(QSize) @@ -125,6 +127,32 @@ struct PrimitiveSet { }; +QPixmap rasterPixmap(int width, int height) +{ + QPixmapData *data = + new QRasterPixmapData(QPixmapData::PixmapType); + + data->resize(width, height); + + return QPixmap(data); +} + +QPixmap rasterPixmap(const QSize &size) +{ + return rasterPixmap(size.width(), size.height()); +} + +QPixmap rasterPixmap(const QImage &image) +{ + QPixmapData *data = + new QRasterPixmapData(QPixmapData::PixmapType); + + data->fromImage(image, Qt::AutoColor); + + return QPixmap(data); +} + + class tst_QPainter : public QObject { Q_OBJECT @@ -222,7 +250,8 @@ private: QPaintDevice *surface() { - return new QPixmap(1024, 1024); + m_pixmap = rasterPixmap(1024, 1024); + return &m_pixmap; } @@ -233,6 +262,7 @@ private: PrimitiveSet m_primitives_100; PrimitiveSet m_primitives_1000; + QPixmap m_pixmap; QPaintDevice *m_surface; QPainter m_painter; @@ -490,7 +520,7 @@ void tst_QPainter::setupBrushes() void tst_QPainter::beginAndEnd() { - QPixmap pixmap(100, 100); + QPixmap pixmap = rasterPixmap(100, 100); QBENCHMARK { QPainter p; @@ -505,10 +535,11 @@ void tst_QPainter::drawLine() QFETCH(QPen, pen); const int offset = 5; - QPixmap pixmapUnclipped(qMin(line.x1(), line.x2()) - + 2*offset + qAbs(line.dx()), - qMin(line.y1(), line.y2()) - + 2*offset + qAbs(line.dy())); + QPixmap pixmapUnclipped = + rasterPixmap(qMin(line.x1(), line.x2()) + + 2*offset + qAbs(line.dx()), + qMin(line.y1(), line.y2()) + + 2*offset + qAbs(line.dy())); pixmapUnclipped.fill(Qt::white); QPainter p(&pixmapUnclipped); @@ -535,10 +566,11 @@ void tst_QPainter::drawLine_clipped() QFETCH(QPen, pen); const int offset = 5; - QPixmap pixmapClipped(qMin(line.x1(), line.x2()) - + 2*offset + qAbs(line.dx()), - qMin(line.y1(), line.y2()) - + 2*offset + qAbs(line.dy())); + QPixmap pixmapClipped + = rasterPixmap(qMin(line.x1(), line.x2()) + + 2*offset + qAbs(line.dx()), + qMin(line.y1(), line.y2()) + + 2*offset + qAbs(line.dy())); const QRect clip = QRect(line.p1(), line.p2()).normalized(); @@ -569,10 +601,11 @@ void tst_QPainter::drawLine_antialiased_clipped() QFETCH(QPen, pen); const int offset = 5; - QPixmap pixmapClipped(qMin(line.x1(), line.x2()) - + 2*offset + qAbs(line.dx()), - qMin(line.y1(), line.y2()) - + 2*offset + qAbs(line.dy())); + QPixmap pixmapClipped + = rasterPixmap(qMin(line.x1(), line.x2()) + + 2*offset + qAbs(line.dx()), + qMin(line.y1(), line.y2()) + + 2*offset + qAbs(line.dy())); const QRect clip = QRect(line.p1(), line.p2()).normalized(); @@ -696,8 +729,8 @@ void tst_QPainter::drawPixmap() QImage sourceImage = createImage(type, size).convertToFormat(sourceFormat); QImage targetImage(size, targetFormat); - QPixmap sourcePixmap = QPixmap::fromImage(sourceImage); - QPixmap targetPixmap = QPixmap::fromImage(targetImage); + QPixmap sourcePixmap = rasterPixmap(sourceImage); + QPixmap targetPixmap = rasterPixmap(targetImage); QPainter p(&targetPixmap); @@ -759,10 +792,10 @@ void tst_QPainter::compositionModes() QFETCH(QSize, size); QFETCH(QColor, color); - QPixmap src(size); + QPixmap src = rasterPixmap(size); src.fill(color); - QPixmap dest(size); + QPixmap dest = rasterPixmap(size); if (mode < QPainter::RasterOp_SourceOrDestination) color.setAlpha(127); // porter-duff needs an alpha channel dest.fill(color); @@ -844,11 +877,11 @@ void tst_QPainter::drawTiledPixmap() QFETCH(QColor, color); QFETCH(QPainter::RenderHint, renderHint); - QPixmap src(srcSize); + QPixmap src = rasterPixmap(srcSize); src.fill(color); const QRect dstRect = transform.mapRect(QRect(QPoint(), dstSize)); - QPixmap dst(dstRect.right() + 5, dstRect.bottom() + 5); + QPixmap dst = rasterPixmap(dstRect.right() + 5, dstRect.bottom() + 5); QPainter p(&dst); p.setTransform(transform); p.setRenderHint(renderHint); @@ -1411,7 +1444,7 @@ void tst_QPainter::drawBorderPixmapRoundedRect() rp.drawRoundedRect(QRectF(qreal(pw)/2+1, qreal(pw)/2+1, rectImage.width()-(pw+1), rectImage.height()-(pw+1)), radius, radius); else rp.drawRoundedRect(QRectF(qreal(pw)/2, qreal(pw)/2, rectImage.width()-pw, rectImage.height()-pw), radius, radius); - QPixmap rectPixmap = QPixmap::fromImage(rectImage); + QPixmap rectPixmap = rasterPixmap(rectImage); //setup surface QImage surface(100, 100, QImage::Format_RGB16); @@ -1466,7 +1499,7 @@ void tst_QPainter::drawScaledBorderPixmapRoundedRect() else rp.drawRoundedRect(QRectF(qreal(pw)/2, qreal(pw)/2, rectImage.width()-pw, rectImage.height()-pw), radius, radius); - QPixmap rectPixmap = QPixmap::fromImage(rectImage); + QPixmap rectPixmap = rasterPixmap(rectImage); //setup surface QImage surface(400, 400, QImage::Format_RGB16); @@ -1522,7 +1555,7 @@ void tst_QPainter::drawTransformedBorderPixmapRoundedRect() else rp.drawRoundedRect(QRectF(qreal(pw)/2, qreal(pw)/2, rectImage.width()-pw, rectImage.height()-pw), radius, radius); - QPixmap rectPixmap = QPixmap::fromImage(rectImage); + QPixmap rectPixmap = rasterPixmap(rectImage); //setup surface QImage surface(400, 400, QImage::Format_RGB16); -- cgit v0.12 From c46688b8a88da02028405604ab633b27d3fefa68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 11 May 2010 12:46:46 +0200 Subject: Made curve tesselation be dynamically adjusted based on transform. This lets us avoid having to use a very low curve threshold value for all scales, and thus avoids the performance regression from change c41dbbb5e6495e26cd32. Task-number: QTBUG-9218 Reviewed-by: Gunnar Sletta --- src/gui/painting/qbezier.cpp | 228 +----------------------------------- src/gui/painting/qbezier_p.h | 7 +- src/gui/painting/qpaintengineex.cpp | 2 + src/gui/painting/qstroker.cpp | 23 ++-- src/gui/painting/qstroker_p.h | 18 ++- src/gui/painting/qtransform.cpp | 9 +- src/s60installs/bwins/QtGuiu.def | 4 +- src/s60installs/eabi/QtGuiu.def | 4 +- 8 files changed, 50 insertions(+), 245 deletions(-) diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp index 7ff2a37..2a9b31a 100644 --- a/src/gui/painting/qbezier.cpp +++ b/src/gui/painting/qbezier.cpp @@ -93,7 +93,7 @@ QBezier QBezier::fromPoints(const QPointF &p1, const QPointF &p2, /*! \internal */ -QPolygonF QBezier::toPolygon() const +QPolygonF QBezier::toPolygon(qreal bezier_flattening_threshold) const { // flattening is done by splitting the bezier until we can replace the segment by a straight // line. We split further until the control points are close enough to the line connecting the @@ -108,7 +108,7 @@ QPolygonF QBezier::toPolygon() const QPolygonF polygon; polygon.append(QPointF(x1, y1)); - addToPolygon(&polygon); + addToPolygon(&polygon, bezier_flattening_threshold); return polygon; } @@ -117,34 +117,6 @@ QBezier QBezier::mapBy(const QTransform &transform) const return QBezier::fromPoints(transform.map(pt1()), transform.map(pt2()), transform.map(pt3()), transform.map(pt4())); } -//0.05 is really low, but required for scaled-up beziers... -static const qreal flatness = 0.05; - -//based on "Fast, precise flattening of cubic Bezier path and offset curves" -// by T. F. Hain, A. L. Ahmad, S. V. R. Racherla and D. D. Langan -static inline void flattenBezierWithoutInflections(QBezier &bez, - QPolygonF *&p) -{ - QBezier left; - - while (1) { - qreal dx = bez.x2 - bez.x1; - qreal dy = bez.y2 - bez.y1; - - qreal normalized = qSqrt(dx * dx + dy * dy); - if (qFuzzyIsNull(normalized)) - break; - - qreal d = qAbs(dx * (bez.y3 - bez.y2) - dy * (bez.x3 - bez.x2)); - - qreal t = qSqrt(4. / 3. * normalized * flatness / d); - if (t > 1 || qFuzzyIsNull(t - (qreal)1.)) - break; - bez.parameterSplitLeft(t, &left); - p->append(bez.pt1()); - } -} - QBezier QBezier::getSubRange(qreal t0, qreal t1) const { QBezier result; @@ -223,7 +195,7 @@ static inline bool findInflections(qreal a, qreal b, qreal c, } -void QBezier::addToPolygon(QPolygonF *polygon) const +void QBezier::addToPolygon(QPolygonF *polygon, qreal bezier_flattening_threshold) const { QBezier beziers[32]; beziers[0] = *this; @@ -243,7 +215,7 @@ void QBezier::addToPolygon(QPolygonF *polygon) const qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3); l = 1.; } - if (d < flatness*l || b == beziers + 31) { + if (d < bezier_flattening_threshold*l || b == beziers + 31) { // good enough, we pop it off and add the endpoint polygon->append(QPointF(b->x4, b->y4)); --b; @@ -255,55 +227,6 @@ void QBezier::addToPolygon(QPolygonF *polygon) const } } -void QBezier::addToPolygonMixed(QPolygonF *polygon) const -{ - qreal ax = -x1 + 3*x2 - 3*x3 + x4; - qreal ay = -y1 + 3*y2 - 3*y3 + y4; - qreal bx = 3*x1 - 6*x2 + 3*x3; - qreal by = 3*y1 - 6*y2 + 3*y3; - qreal cx = -3*x1 + 3*x2; - qreal cy = -3*y1 + 2*y2; - qreal a = 6 * (ay * bx - ax * by); - qreal b = 6 * (ay * cx - ax * cy); - qreal c = 2 * (by * cx - bx * cy); - - if ((qFuzzyIsNull(a) && qFuzzyIsNull(b)) || - (b * b - 4 * a *c) < 0) { - QBezier bez(*this); - flattenBezierWithoutInflections(bez, polygon); - polygon->append(QPointF(x4, y4)); - } else { - QBezier beziers[32]; - beziers[0] = *this; - QBezier *b = beziers; - - while (b >= beziers) { - // check if we can pop the top bezier curve from the stack - qreal y4y1 = b->y4 - b->y1; - qreal x4x1 = b->x4 - b->x1; - qreal l = qAbs(x4x1) + qAbs(y4y1); - qreal d; - if (l > 1.) { - d = qAbs( (x4x1)*(b->y1 - b->y2) - (y4y1)*(b->x1 - b->x2) ) - + qAbs( (x4x1)*(b->y1 - b->y3) - (y4y1)*(b->x1 - b->x3) ); - } else { - d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) + - qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3); - l = 1.; - } - if (d < .5*l || b == beziers + 31) { - // good enough, we pop it off and add the endpoint - polygon->append(QPointF(b->x4, b->y4)); - --b; - } else { - // split, second half of the polygon goes lower into the stack - b->split(b+1, b); - ++b; - } - } - } -} - QRectF QBezier::bounds() const { qreal xmin = x1; @@ -824,147 +747,4 @@ QBezier QBezier::bezierOnInterval(qreal t0, qreal t1) const return result; } - -static inline void bindInflectionPoint(const QBezier &bez, const qreal t, - qreal *tMinus , qreal *tPlus) -{ - if (t <= 0) { - *tMinus = *tPlus = -1; - return; - } else if (t >= 1) { - *tMinus = *tPlus = 2; - return; - } - - QBezier left, right; - splitBezierAt(bez, t, &left, &right); - - qreal ax = -right.x1 + 3*right.x2 - 3*right.x3 + right.x4; - qreal ay = -right.y1 + 3*right.y2 - 3*right.y3 + right.y4; - qreal ex = 3 * (right.x2 - right.x3); - qreal ey = 3 * (right.y2 - right.y3); - - qreal s4 = qAbs(6 * (ey * ax - ex * ay) / qSqrt(ex * ex + ey * ey)) + 0.00001f; - qreal tf = qPow(qreal(9 * flatness / s4), qreal(1./3.)); - *tMinus = t - (1 - t) * tf; - *tPlus = t + (1 - t) * tf; -} - -void QBezier::addToPolygonIterative(QPolygonF *p) const -{ - qreal t1, t2, tcusp; - qreal t1min, t1plus, t2min, t2plus; - - qreal ax = -x1 + 3*x2 - 3*x3 + x4; - qreal ay = -y1 + 3*y2 - 3*y3 + y4; - qreal bx = 3*x1 - 6*x2 + 3*x3; - qreal by = 3*y1 - 6*y2 + 3*y3; - qreal cx = -3*x1 + 3*x2; - qreal cy = -3*y1 + 2*y2; - - if (findInflections(6 * (ay * bx - ax * by), - 6 * (ay * cx - ax * cy), - 2 * (by * cx - bx * cy), - &t1, &t2, &tcusp)) { - bindInflectionPoint(*this, t1, &t1min, &t1plus); - bindInflectionPoint(*this, t2, &t2min, &t2plus); - - QBezier tmpBez = *this; - QBezier left, right, bez1, bez2, bez3; - if (t1min > 0) { - if (t1min >= 1) { - flattenBezierWithoutInflections(tmpBez, p); - } else { - splitBezierAt(tmpBez, t1min, &left, &right); - flattenBezierWithoutInflections(left, p); - p->append(tmpBez.pointAt(t1min)); - - if (t2min < t1plus) { - if (tcusp < 1) { - p->append(tmpBez.pointAt(tcusp)); - } - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &right); - flattenBezierWithoutInflections(right, p); - } - } else if (t1plus < 1) { - if (t2min < 1) { - splitBezierAt(tmpBez, t2min, &bez3, &right); - splitBezierAt(bez3, t1plus, &left, &bez2); - - flattenBezierWithoutInflections(bez2, p); - p->append(tmpBez.pointAt(t2min)); - - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } else { - splitBezierAt(tmpBez, t1plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } - } - } else if (t1plus > 0) { - p->append(QPointF(x1, y1)); - if (t2min < t1plus) { - if (tcusp < 1) { - p->append(tmpBez.pointAt(tcusp)); - } - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } else if (t1plus < 1) { - if (t2min < 1) { - splitBezierAt(tmpBez, t2min, &bez3, &right); - splitBezierAt(bez3, t1plus, &left, &bez2); - - flattenBezierWithoutInflections(bez2, p); - - p->append(tmpBez.pointAt(t2min)); - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } else { - splitBezierAt(tmpBez, t1plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } - } else if (t2min > 0) { - if (t2min < 1) { - splitBezierAt(tmpBez, t2min, &bez1, &right); - flattenBezierWithoutInflections(bez1, p); - p->append(tmpBez.pointAt(t2min)); - - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } else { - //### in here we should check whether the area of the - // triangle formed between pt1/pt2/pt3 is smaller - // or equal to 0 and then do iterative flattening - // if not we should fallback and do the recursive - // flattening. - flattenBezierWithoutInflections(tmpBez, p); - } - } else if (t2plus > 0) { - p->append(QPointF(x1, y1)); - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } else { - flattenBezierWithoutInflections(tmpBez, p); - } - } else { - QBezier bez = *this; - flattenBezierWithoutInflections(bez, p); - } - - p->append(QPointF(x4, y4)); -} - QT_END_NAMESPACE diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h index 846635f..18ec116 100644 --- a/src/gui/painting/qbezier_p.h +++ b/src/gui/painting/qbezier_p.h @@ -79,10 +79,9 @@ public: inline QPointF derivedAt(qreal t) const; inline QPointF secondDerivedAt(qreal t) const; - QPolygonF toPolygon() const; - void addToPolygon(QPolygonF *p) const; - void addToPolygonIterative(QPolygonF *p) const; - void addToPolygonMixed(QPolygonF *p) const; + QPolygonF toPolygon(qreal bezier_flattening_threshold = 0.5) const; + void addToPolygon(QPolygonF *p, qreal bezier_flattening_threshold = 0.5) const; + QRectF bounds() const; qreal length(qreal error = 0.01) const; void addIfClose(qreal *length, qreal error) const; diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index fda937e..ff82d59 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -461,6 +461,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) // change the current transform. Normal transformed, // non-cosmetic pens will be transformed as part of fill // later, so they are also covered here.. + d->activeStroker->setCurveThresholdFromTransform(state()->matrix); d->activeStroker->begin(d->strokeHandler); if (types) { while (points < lastPoint) { @@ -518,6 +519,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) QPainterPath painterPath = state()->matrix.map(path.convertToPainterPath()); d->activeStroker->strokePath(painterPath, d->strokeHandler, QTransform()); } else { + d->activeStroker->setCurveThresholdFromTransform(state()->matrix); d->activeStroker->begin(d->strokeHandler); if (types) { while (points < lastPoint) { diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp index 9b8e099..eabbd8a 100644 --- a/src/gui/painting/qstroker.cpp +++ b/src/gui/painting/qstroker.cpp @@ -120,8 +120,8 @@ private: class QSubpathFlatIterator { public: - QSubpathFlatIterator(const QDataBuffer *path) - : m_path(path), m_pos(0), m_curve_index(-1) { } + QSubpathFlatIterator(const QDataBuffer *path, qreal threshold) + : m_path(path), m_pos(0), m_curve_index(-1), m_curve_threshold(threshold) { } inline bool hasNext() const { return m_curve_index >= 0 || m_pos < m_path->size(); } @@ -152,7 +152,7 @@ public: QPointF(qt_fixed_to_real(m_path->at(m_pos+1).x), qt_fixed_to_real(m_path->at(m_pos+1).y)), QPointF(qt_fixed_to_real(m_path->at(m_pos+2).x), - qt_fixed_to_real(m_path->at(m_pos+2).y))).toPolygon(); + qt_fixed_to_real(m_path->at(m_pos+2).y))).toPolygon(m_curve_threshold); m_curve_index = 1; e.type = QPainterPath::LineToElement; e.x = m_curve.at(0).x(); @@ -169,6 +169,7 @@ private: int m_pos; QPolygonF m_curve; int m_curve_index; + qreal m_curve_threshold; }; template bool qt_stroke_side(Iterator *it, QStroker *stroker, @@ -187,7 +188,12 @@ static inline qreal adapted_angle_on_x(const QLineF &line) } QStrokerOps::QStrokerOps() - : m_elements(0), m_customData(0), m_moveTo(0), m_lineTo(0), m_cubicTo(0) + : m_elements(0) + , m_curveThreshold(qt_real_to_fixed(0.25)) + , m_customData(0) + , m_moveTo(0) + , m_lineTo(0) + , m_cubicTo(0) { } @@ -195,7 +201,6 @@ QStrokerOps::~QStrokerOps() { } - /*! Prepares the stroker. Call this function once before starting a stroke by calling moveTo, lineTo or cubicTo. @@ -238,6 +243,7 @@ void QStrokerOps::strokePath(const QPainterPath &path, void *customData, const Q if (path.isEmpty()) return; + setCurveThresholdFromTransform(matrix); begin(customData); int count = path.elementCount(); if (matrix.isIdentity()) { @@ -308,6 +314,8 @@ void QStrokerOps::strokePolygon(const QPointF *points, int pointCount, bool impl { if (!pointCount) return; + + setCurveThresholdFromTransform(matrix); begin(data); if (matrix.isIdentity()) { moveTo(qt_real_to_fixed(points[0].x()), qt_real_to_fixed(points[0].y())); @@ -348,6 +356,7 @@ void QStrokerOps::strokeEllipse(const QRectF &rect, void *data, const QTransform } } + setCurveThresholdFromTransform(matrix); begin(data); moveTo(qt_real_to_fixed(start.x()), qt_real_to_fixed(start.y())); for (int i=0; i<12; i+=3) { @@ -366,12 +375,10 @@ QStroker::QStroker() { m_strokeWidth = qt_real_to_fixed(1); m_miterLimit = qt_real_to_fixed(2); - m_curveThreshold = qt_real_to_fixed(0.25); } QStroker::~QStroker() { - } Qt::PenCapStyle QStroker::capForJoinMode(LineJoinMode mode) @@ -1135,7 +1142,7 @@ void QDashStroker::processCurrentSubpath() QPainterPath dashPath; - QSubpathFlatIterator it(&m_elements); + QSubpathFlatIterator it(&m_elements, m_curveThreshold); qfixed2d prev = it.next(); bool clipping = !m_clip_rect.isEmpty(); diff --git a/src/gui/painting/qstroker_p.h b/src/gui/painting/qstroker_p.h index 3e622a8..0f133ef 100644 --- a/src/gui/painting/qstroker_p.h +++ b/src/gui/painting/qstroker_p.h @@ -124,6 +124,9 @@ typedef void (*qStrokerCubicToHook)(qfixed c1x, qfixed c1y, qfixed ex, qfixed ey, void *data); +// qtransform.cpp +extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); + class Q_GUI_EXPORT QStrokerOps { public: @@ -161,6 +164,16 @@ public: QRectF clipRect() const { return m_clip_rect; } void setClipRect(const QRectF &clip) { m_clip_rect = clip; } + void setCurveThresholdFromTransform(const QTransform &transform) + { + qreal scale; + qt_scaleForTransform(transform, &scale); + setCurveThreshold(scale == 0 ? qreal(0.5) : (qreal(0.5) / scale)); + } + + void setCurveThreshold(qfixed threshold) { m_curveThreshold = threshold; } + qfixed curveThreshold() const { return m_curveThreshold; } + protected: inline void emitMoveTo(qfixed x, qfixed y); inline void emitLineTo(qfixed x, qfixed y); @@ -170,6 +183,7 @@ protected: QDataBuffer m_elements; QRectF m_clip_rect; + qfixed m_curveThreshold; void *m_customData; qStrokerMoveToHook m_moveTo; @@ -208,9 +222,6 @@ public: void setMiterLimit(qfixed length) { m_miterLimit = length; } qfixed miterLimit() const { return m_miterLimit; } - void setCurveThreshold(qfixed threshold) { m_curveThreshold = threshold; } - qfixed curveThreshold() const { return m_curveThreshold; } - void joinPoints(qfixed x, qfixed y, const QLineF &nextLine, LineJoinMode join); inline void emitMoveTo(qfixed x, qfixed y); inline void emitLineTo(qfixed x, qfixed y); @@ -227,7 +238,6 @@ protected: qfixed m_strokeWidth; qfixed m_miterLimit; - qfixed m_curveThreshold; LineJoinMode m_capStyle; LineJoinMode m_joinStyle; diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 80b7520..c72a08e 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1545,12 +1545,19 @@ static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transfor return true; } +bool qt_scaleForTransform(const QTransform &transform, qreal *scale); static inline bool cubicTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, bool needsMoveTo) { // Convert projective xformed curves to line // segments so they can be transformed more accurately - QPolygonF segment = QBezier::fromPoints(a, b, c, d).toPolygon(); + + qreal scale; + qt_scaleForTransform(transform, &scale); + + qreal curveThreshold = scale == 0 ? qreal(0.25) : (qreal(0.25) / scale); + + QPolygonF segment = QBezier::fromPoints(a, b, c, d).toPolygon(curveThreshold); for (int i = 0; i < segment.size() - 1; ++i) if (lineTo_clipped(path, transform, segment.at(i), segment.at(i+1), needsMoveTo)) diff --git a/src/s60installs/bwins/QtGuiu.def b/src/s60installs/bwins/QtGuiu.def index c3a3a08..8957c34 100644 --- a/src/s60installs/bwins/QtGuiu.def +++ b/src/s60installs/bwins/QtGuiu.def @@ -2126,8 +2126,8 @@ EXPORTS ?addToGroup@QGraphicsItemGroup@@QAEXPAVQGraphicsItem@@@Z @ 2125 NONAME ; void QGraphicsItemGroup::addToGroup(class QGraphicsItem *) ?addToIndex@QGraphicsItem@@IAEXXZ @ 2126 NONAME ; void QGraphicsItem::addToIndex(void) ?addToPolygon@QBezier@@QBEXPAVQPolygonF@@@Z @ 2127 NONAME ; void QBezier::addToPolygon(class QPolygonF *) const - ?addToPolygonIterative@QBezier@@QBEXPAVQPolygonF@@@Z @ 2128 NONAME ; void QBezier::addToPolygonIterative(class QPolygonF *) const - ?addToPolygonMixed@QBezier@@QBEXPAVQPolygonF@@@Z @ 2129 NONAME ; void QBezier::addToPolygonMixed(class QPolygonF *) const + ?addToPolygonIterative@QBezier@@QBEXPAVQPolygonF@@@Z @ 2128 NONAME ABSENT ; void QBezier::addToPolygonIterative(class QPolygonF *) const + ?addToPolygonMixed@QBezier@@QBEXPAVQPolygonF@@@Z @ 2129 NONAME ABSENT ; void QBezier::addToPolygonMixed(class QPolygonF *) const ?addToolBar@QMainWindow@@QAEPAVQToolBar@@ABVQString@@@Z @ 2130 NONAME ; class QToolBar * QMainWindow::addToolBar(class QString const &) ?addToolBar@QMainWindow@@QAEXPAVQToolBar@@@Z @ 2131 NONAME ; void QMainWindow::addToolBar(class QToolBar *) ?addToolBar@QMainWindow@@QAEXW4ToolBarArea@Qt@@PAVQToolBar@@@Z @ 2132 NONAME ; void QMainWindow::addToolBar(enum Qt::ToolBarArea, class QToolBar *) diff --git a/src/s60installs/eabi/QtGuiu.def b/src/s60installs/eabi/QtGuiu.def index b1166c5..d127b41 100644 --- a/src/s60installs/eabi/QtGuiu.def +++ b/src/s60installs/eabi/QtGuiu.def @@ -9901,9 +9901,9 @@ EXPORTS _ZNK7QBezier10addIfCloseEPff @ 9900 NONAME _ZNK7QBezier12addToPolygonEP9QPolygonF @ 9901 NONAME _ZNK7QBezier16bezierOnIntervalEff @ 9902 NONAME - _ZNK7QBezier17addToPolygonMixedEP9QPolygonF @ 9903 NONAME + _ZNK7QBezier17addToPolygonMixedEP9QPolygonF @ 9903 NONAME ABSENT _ZNK7QBezier17stationaryYPointsERfS0_ @ 9904 NONAME - _ZNK7QBezier21addToPolygonIterativeEP9QPolygonF @ 9905 NONAME + _ZNK7QBezier21addToPolygonIterativeEP9QPolygonF @ 9905 NONAME ABSENT _ZNK7QBezier5tForYEfff @ 9906 NONAME _ZNK7QBezier6boundsEv @ 9907 NONAME _ZNK7QBezier6lengthEf @ 9908 NONAME -- cgit v0.12 From 953411c6eecc4175752ade1834bf8db3398961c5 Mon Sep 17 00:00:00 2001 From: Mirko Damiani Date: Wed, 12 May 2010 16:08:23 +0200 Subject: Skip definition of wintab functions in case of QT_NO_TABLETEVENT. Following functions are not compiled when QT_NO_TABLETEVENT is defined (both declaration and definition): - qt_tablet_init - qt_tablet_cleanup - init_wintab_functions - qt_tablet_init_wce - qt_tablet_cleanup_wce Merge-request: 2388 Reviewed-by: Benjamin Poulain --- src/gui/kernel/qwidget_win.cpp | 5 +++++ src/gui/kernel/qwidget_wince.cpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index 7d647b7..c2a24fe 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -123,9 +123,11 @@ static PtrWTClose ptrWTClose = 0; static PtrWTInfo ptrWTInfo = 0; static PtrWTQueueSizeGet ptrWTQueueSizeGet = 0; static PtrWTQueueSizeSet ptrWTQueueSizeSet = 0; +#ifndef QT_NO_TABLETEVENT static void init_wintab_functions(); static void qt_tablet_init(); static void qt_tablet_cleanup(); +#endif // QT_NO_TABLETEVENT extern HCTX qt_tablet_context; extern bool qt_tablet_tilt_support; @@ -136,6 +138,8 @@ QWidget* qt_get_tablet_widget() } extern bool qt_is_gui_used; + +#ifndef QT_NO_TABLETEVENT static void init_wintab_functions() { #if defined(Q_OS_WINCE) @@ -227,6 +231,7 @@ static void qt_tablet_cleanup() delete qt_tablet_widget; qt_tablet_widget = 0; } +#endif // QT_NO_TABLETEVENT const QString qt_reg_winclass(QWidget *w); // defined in qapplication_win.cpp diff --git a/src/gui/kernel/qwidget_wince.cpp b/src/gui/kernel/qwidget_wince.cpp index 509847b..9c2c8c7 100644 --- a/src/gui/kernel/qwidget_wince.cpp +++ b/src/gui/kernel/qwidget_wince.cpp @@ -63,6 +63,7 @@ typedef BOOL (API *PtrWTGet)(HCTX, LPLOGCONTEXT); typedef int (API *PtrWTQueueSizeGet)(HCTX); typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int); +#ifndef QT_NO_TABLETEVENT static void qt_tablet_init_wce(); static void qt_tablet_cleanup_wce(); @@ -135,6 +136,7 @@ static void qt_tablet_cleanup_wce() { delete qt_tablet_widget; qt_tablet_widget = 0; } +#endif // QT_NO_TABLETEVENT // The internal qWinRequestConfig, defined in qapplication_win.cpp, stores move, -- cgit v0.12 From e4902b4f25ca9c1ecff99609dbe376b407d9c6c5 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 11 May 2010 16:02:16 +0200 Subject: New Pad Nagivator example implementation. The old implementation was demo-quality and didn't really belong in the examples section. This new code cleans up the implementation, and also makes use of brand new features such as the state machine and animated transitions system. The new code is more suitable for documentation, and full docs are coming up in the next commit. --- examples/graphicsview/padnavigator/backside.ui | 208 ---------------- .../graphicsview/padnavigator/flippablepad.cpp | 90 +++++++ examples/graphicsview/padnavigator/flippablepad.h | 63 +++++ examples/graphicsview/padnavigator/main.cpp | 12 +- .../graphicsview/padnavigator/padnavigator.cpp | 265 +++++++++++++++++++++ examples/graphicsview/padnavigator/padnavigator.h | 65 +++++ .../graphicsview/padnavigator/padnavigator.pro | 23 +- examples/graphicsview/padnavigator/panel.cpp | 238 ------------------ examples/graphicsview/padnavigator/panel.h | 92 ------- .../graphicsview/padnavigator/roundrectitem.cpp | 129 +++------- examples/graphicsview/padnavigator/roundrectitem.h | 48 ++-- examples/graphicsview/padnavigator/splashitem.cpp | 44 ++-- examples/graphicsview/padnavigator/splashitem.h | 23 +- 13 files changed, 577 insertions(+), 723 deletions(-) delete mode 100644 examples/graphicsview/padnavigator/backside.ui create mode 100644 examples/graphicsview/padnavigator/flippablepad.cpp create mode 100644 examples/graphicsview/padnavigator/flippablepad.h create mode 100644 examples/graphicsview/padnavigator/padnavigator.cpp create mode 100644 examples/graphicsview/padnavigator/padnavigator.h delete mode 100644 examples/graphicsview/padnavigator/panel.cpp delete mode 100644 examples/graphicsview/padnavigator/panel.h diff --git a/examples/graphicsview/padnavigator/backside.ui b/examples/graphicsview/padnavigator/backside.ui deleted file mode 100644 index afa488c..0000000 --- a/examples/graphicsview/padnavigator/backside.ui +++ /dev/null @@ -1,208 +0,0 @@ - - BackSide - - - - 0 - 0 - 378 - 385 - - - - BackSide - - - - - - Settings - - - true - - - true - - - - - - Title: - - - - - - - Pad Navigator Example - - - - - - - Modified: - - - - - - - Extent - - - - - - - - - 42 - - - Qt::Horizontal - - - - - - - 42 - - - - - - - - - - - - - - - Other input - - - true - - - true - - - - - - - Widgets On Graphics View - - - - - QGraphicsProxyWidget - - - - QGraphicsWidget - - - - QObject - - - - - QGraphicsItem - - - - - QGraphicsLayoutItem - - - - - - - QGraphicsGridLayout - - - - QGraphicsLayout - - - - QGraphicsLayoutItem - - - - - - - QGraphicsLinearLayout - - - - QGraphicsLayout - - - - QGraphicsLayoutItem - - - - - - - - - - - - - groupBox - hostName - dateTimeEdit - horizontalSlider - spinBox - groupBox_2 - treeWidget - - - - - horizontalSlider - valueChanged(int) - spinBox - setValue(int) - - - 184 - 125 - - - 275 - 127 - - - - - spinBox - valueChanged(int) - horizontalSlider - setValue(int) - - - 272 - 114 - - - 190 - 126 - - - - - diff --git a/examples/graphicsview/padnavigator/flippablepad.cpp b/examples/graphicsview/padnavigator/flippablepad.cpp new file mode 100644 index 0000000..61f421f --- /dev/null +++ b/examples/graphicsview/padnavigator/flippablepad.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 "flippablepad.h" + +#include + +static QRectF boundsFromSize(const QSize &size) +{ + return QRectF((-size.width() / 2.0) * 150, (-size.height() / 2.0) * 150, + size.width() * 150, size.height() * 150); +} + +static QPointF posForLocation(int x, int y, const QSize &size) +{ + return QPointF(x * 150, y * 150) + - QPointF((size.width() - 1) * 75, (size.height() - 1) * 75); +} + +FlippablePad::FlippablePad(const QSize &size, QGraphicsItem *parent) + : RoundRectItem(boundsFromSize(size), QColor(226, 255, 92, 64), parent) +{ + columns = size.width(); + + int numIcons = size.width() * size.height(); + QList pixmaps; + QDirIterator it(":/images", QStringList() << "*.png"); + while (it.hasNext() && pixmaps.size() < numIcons) + pixmaps << it.next(); + + const QRectF iconRect(-54, -54, 108, 108); + const QColor iconColor(214, 240, 110, 128); + + iconGrid.resize(size.height()); + + int n = 0; + for (int y = 0; y < size.height(); ++y) { + iconGrid[y].resize(columns); + for (int x = 0; x < size.width(); ++x) { + RoundRectItem *rect = new RoundRectItem(iconRect, iconColor, this); + rect->setZValue(1); + rect->setPos(posForLocation(x, y, size)); + rect->setPixmap(pixmaps.at(n++ % pixmaps.size())); + iconGrid[y][x] = rect; + } + } +} + +RoundRectItem *FlippablePad::iconAt(int x, int y) const +{ + return iconGrid[y][x]; +} diff --git a/examples/graphicsview/padnavigator/flippablepad.h b/examples/graphicsview/padnavigator/flippablepad.h new file mode 100644 index 0000000..9adb18b --- /dev/null +++ b/examples/graphicsview/padnavigator/flippablepad.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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$ +** +****************************************************************************/ + +#ifndef FLIPPABLEPAD_H +#define FLIPPABLEPAD_H + +#include "roundrectitem.h" + +#include +#include +#include + +class FlippablePad : public RoundRectItem +{ +public: + FlippablePad(const QSize &size, QGraphicsItem *parent = 0); + + RoundRectItem *iconAt(int x, int y) const; + +private: + int columns; + QVector > iconGrid; +}; + +#endif // FLIPPABLEPAD_H diff --git a/examples/graphicsview/padnavigator/main.cpp b/examples/graphicsview/padnavigator/main.cpp index fb6c120..6d148bb 100644 --- a/examples/graphicsview/padnavigator/main.cpp +++ b/examples/graphicsview/padnavigator/main.cpp @@ -39,21 +39,17 @@ ** ****************************************************************************/ -#include -#ifndef QT_NO_OPENGL -# include -#endif +#include "padnavigator.h" -#include "panel.h" +#include int main(int argc, char *argv[]) { QApplication app(argc, argv); Q_INIT_RESOURCE(padnavigator); - Panel panel(3, 3); - panel.setFocus(); - panel.show(); + PadNavigator navigator(QSize(3, 3)); + navigator.show(); return app.exec(); } diff --git a/examples/graphicsview/padnavigator/padnavigator.cpp b/examples/graphicsview/padnavigator/padnavigator.cpp new file mode 100644 index 0000000..456b3f4 --- /dev/null +++ b/examples/graphicsview/padnavigator/padnavigator.cpp @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 "flippablepad.h" +#include "padnavigator.h" +#include "splashitem.h" +#include "ui_form.h" + +#include +#ifndef QT_NO_OPENGL +#include +#endif + +PadNavigator::PadNavigator(const QSize &size, QWidget *parent) + : QGraphicsView(parent) +{ + // Prepare splash item + SplashItem *splash = new SplashItem; + splash->setZValue(1); + + // Prepare pad item + FlippablePad *pad = new FlippablePad(size); + QGraphicsRotation *flipRotation = new QGraphicsRotation(pad); + flipRotation->setAxis(Qt::YAxis); + QGraphicsRotation *xRotation = new QGraphicsRotation(pad); + xRotation->setAxis(Qt::YAxis); + QGraphicsRotation *yRotation = new QGraphicsRotation(pad); + yRotation->setAxis(Qt::XAxis); + pad->setTransformations(QList() + << flipRotation + << xRotation << yRotation); + + // Prepare backitem + form = new Ui_Form; + QWidget *widget = new QWidget; + form->setupUi(widget); + form->hostName->setFocus(); + QGraphicsProxyWidget *backItem = new QGraphicsProxyWidget(pad); + backItem->setCacheMode(QGraphicsItem::ItemCoordinateCache); + backItem->setWidget(widget); + backItem->setTransform(QTransform() + .rotate(180, Qt::YAxis) + .translate(-backItem->rect().width()/2, -backItem->rect().height()/2)); + backItem->setFocus(); + backItem->setVisible(false); + + // Prepare selection item + RoundRectItem *selectionItem = new RoundRectItem(QRectF(-60, -60, 120, 120), + Qt::gray, pad); + selectionItem->setZValue(0.5); + + // Selection animation setup + QPropertyAnimation *smoothXSelection = new QPropertyAnimation(selectionItem, "x"); + smoothXSelection->setDuration(125); + smoothXSelection->setEasingCurve(QEasingCurve::InOutQuad); + QPropertyAnimation *smoothYSelection = new QPropertyAnimation(selectionItem, "y"); + smoothYSelection->setDuration(125); + smoothYSelection->setEasingCurve(QEasingCurve::InOutQuad); + QPropertyAnimation *smoothXRotation = new QPropertyAnimation(xRotation, "angle"); + smoothXRotation->setDuration(125); + smoothXRotation->setEasingCurve(QEasingCurve::InOutQuad); + QPropertyAnimation *smoothYRotation = new QPropertyAnimation(yRotation, "angle"); + smoothYRotation->setDuration(125); + smoothYRotation->setEasingCurve(QEasingCurve::InOutQuad); + QPropertyAnimation *smoothScale = new QPropertyAnimation(pad, "scale"); + smoothScale->setDuration(500); + smoothScale->setKeyValueAt(0, qVariantValue(1.0)); + smoothScale->setKeyValueAt(0.5, qVariantValue(0.7)); + smoothScale->setKeyValueAt(1, qVariantValue(1.0)); + smoothScale->setEasingCurve(QEasingCurve::InOutQuad); + + // Flip animation setup + QPropertyAnimation *smoothFlipRotation = new QPropertyAnimation(flipRotation, "angle"); + smoothFlipRotation->setDuration(500); + smoothFlipRotation->setEasingCurve(QEasingCurve::InOutQuad); + QPropertyAnimation *flipSmoothXRotation = new QPropertyAnimation(xRotation, "angle"); + flipSmoothXRotation->setDuration(500); + flipSmoothXRotation->setEasingCurve(QEasingCurve::InOutQuad); + QPropertyAnimation *flipSmoothYRotation = new QPropertyAnimation(yRotation, "angle"); + flipSmoothYRotation->setDuration(500); + flipSmoothYRotation->setEasingCurve(QEasingCurve::InOutQuad); + QPropertyAnimation *setBackItemVisibleAnim = new QPropertyAnimation(backItem, "visible"); + setBackItemVisibleAnim->setDuration(0); + QPropertyAnimation *setSelectionItemVisibleAnim = new QPropertyAnimation(selectionItem, "visible"); + setSelectionItemVisibleAnim->setDuration(0); + QPropertyAnimation *setFillAnim = new QPropertyAnimation(pad, "fill"); + setFillAnim->setDuration(0); + QSequentialAnimationGroup *setVisibleAnimation = new QSequentialAnimationGroup; + setVisibleAnimation->addPause(250); + setVisibleAnimation->addAnimation(setBackItemVisibleAnim); + setVisibleAnimation->addAnimation(setSelectionItemVisibleAnim); + setVisibleAnimation->addAnimation(setFillAnim); + QParallelAnimationGroup *flipAnimation = new QParallelAnimationGroup(this); + flipAnimation->addAnimation(smoothFlipRotation); + flipAnimation->addAnimation(smoothScale); + flipAnimation->addAnimation(flipSmoothXRotation); + flipAnimation->addAnimation(flipSmoothYRotation); + flipAnimation->addAnimation(setVisibleAnimation); + + QPropertyAnimation *smoothSplashMove = new QPropertyAnimation(splash, "y"); + smoothSplashMove->setEasingCurve(QEasingCurve::InQuad); + smoothSplashMove->setDuration(250); + QPropertyAnimation *smoothSplashOpacity = new QPropertyAnimation(splash, "opacity"); + smoothSplashOpacity->setDuration(250); + + // Build the state machine + QStateMachine *stateMachine = new QStateMachine(this); + QState *splashState = new QState(stateMachine); + QState *frontState = new QState(stateMachine); + QHistoryState *historyState = new QHistoryState(frontState); + QState *backState = new QState(stateMachine); + frontState->assignProperty(splash, "opacity", 0.0); + frontState->assignProperty(flipRotation, "angle", qVariantValue(0.0)); + frontState->assignProperty(backItem, "visible", false); + frontState->assignProperty(selectionItem, "visible", true); + frontState->assignProperty(pad, "fill", false); + backState->assignProperty(flipRotation, "angle", qVariantValue(180.0)); + backState->assignProperty(xRotation, "angle", qVariantValue(0.0)); + backState->assignProperty(yRotation, "angle", qVariantValue(0.0)); + backState->assignProperty(selectionItem, "visible", false); + backState->assignProperty(backItem, "visible", true); + backState->assignProperty(pad, "fill", true); + stateMachine->addDefaultAnimation(smoothXRotation); + stateMachine->addDefaultAnimation(smoothYRotation); + stateMachine->addDefaultAnimation(smoothXSelection); + stateMachine->addDefaultAnimation(smoothYSelection); + stateMachine->setInitialState(splashState); + + // Transitions + QEventTransition *anyKeyTransition = new QEventTransition(this, QEvent::KeyPress, splashState); + anyKeyTransition->setTargetState(frontState); + anyKeyTransition->addAnimation(smoothSplashMove); + anyKeyTransition->addAnimation(smoothSplashOpacity); + + QKeyEventTransition *enterTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Enter, backState); + enterTransition->setTargetState(historyState); + QKeyEventTransition *returnTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Return, backState); + returnTransition->setTargetState(historyState); + QKeyEventTransition *backEnterTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Enter, frontState); + backEnterTransition->setTargetState(backState); + QKeyEventTransition *backReturnTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Return, frontState); + backReturnTransition->setTargetState(backState); + enterTransition->addAnimation(flipAnimation); + returnTransition->addAnimation(flipAnimation); + backEnterTransition->addAnimation(flipAnimation); + backReturnTransition->addAnimation(flipAnimation); + + // Substates, one for each icon + int columns = size.width(); + int rows = size.height(); + QVector< QVector< QState * > > stateGrid; + stateGrid.resize(rows); + for (int y = 0; y < rows; ++y) { + stateGrid[y].resize(columns); + for (int x = 0; x < columns; ++x) { + QState *state = new QState(frontState); + stateGrid[y][x] = state; + } + } + frontState->setInitialState(stateGrid[0][0]); + selectionItem->setPos(pad->iconAt(0, 0)->pos()); + + // Enable key navigation using state transitions + for (int y = 0; y < rows; ++y) { + for (int x = 0; x < columns; ++x) { + QState *state = stateGrid[y][x]; + QKeyEventTransition *rightTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Right, state); + rightTransition->setTargetState(stateGrid[y][(x + 1) % columns]); + QKeyEventTransition *leftTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Left, state); + leftTransition->setTargetState(stateGrid[y][((x - 1) + columns) % columns]); + QKeyEventTransition *downTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Down, state); + downTransition->setTargetState(stateGrid[(y + 1) % rows][x]); + QKeyEventTransition *upTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Up, state); + upTransition->setTargetState(stateGrid[((y - 1) + rows) % rows][x]); + + RoundRectItem *icon = pad->iconAt(x, y); + state->assignProperty(xRotation, "angle", -icon->x() / 6.0); + state->assignProperty(yRotation, "angle", icon->y() / 6.0); + state->assignProperty(selectionItem, "x", icon->x()); + state->assignProperty(selectionItem, "y", icon->y()); + frontState->assignProperty(icon, "visible", true); + backState->assignProperty(icon, "visible", false); + + QPropertyAnimation *setVisibleAnim = new QPropertyAnimation(icon, "visible"); + setVisibleAnim->setDuration(0); + setVisibleAnimation->addAnimation(setVisibleAnim); + } + } + + // Setup scene + QGraphicsScene *scene = new QGraphicsScene(this); + scene->setBackgroundBrush(QPixmap(":/images/blue_angle_swirl.jpg")); + scene->setItemIndexMethod(QGraphicsScene::NoIndex); + scene->addItem(pad); + scene->setSceneRect(scene->itemsBoundingRect()); + setScene(scene); + + // Adjust splash item + splash->setPos(-splash->boundingRect().width() / 2, scene->sceneRect().top()); + frontState->assignProperty(splash, "y", splash->y() - 100.0); + scene->addItem(splash); + + // Setup view + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setMinimumSize(50, 50); + setViewportUpdateMode(FullViewportUpdate); + setCacheMode(CacheBackground); + setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform + | QPainter::TextAntialiasing); +#ifndef QT_NO_OPENGL + setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); +#endif + + stateMachine->start(); +} + +PadNavigator::~PadNavigator() +{ + delete form; +} + +void PadNavigator::resizeEvent(QResizeEvent *event) +{ + QGraphicsView::resizeEvent(event); + fitInView(scene()->sceneRect(), Qt::KeepAspectRatio); +} diff --git a/examples/graphicsview/padnavigator/padnavigator.h b/examples/graphicsview/padnavigator/padnavigator.h new file mode 100644 index 0000000..c79a13c --- /dev/null +++ b/examples/graphicsview/padnavigator/padnavigator.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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$ +** +****************************************************************************/ + +#ifndef PADNAVIGATOR_H +#define PADNAVIGATOR_H + +#include + +class QState; +class QStateMachine; +class Ui_Form; + +class PadNavigator : public QGraphicsView +{ + Q_OBJECT +public: + explicit PadNavigator(const QSize &size, QWidget *parent = 0); + ~PadNavigator(); + +protected: + void resizeEvent(QResizeEvent *event); + +private: + Ui_Form *form; +}; + +#endif // PADNAVIGATOR_H diff --git a/examples/graphicsview/padnavigator/padnavigator.pro b/examples/graphicsview/padnavigator/padnavigator.pro index d6f536c..93ea293 100644 --- a/examples/graphicsview/padnavigator/padnavigator.pro +++ b/examples/graphicsview/padnavigator/padnavigator.pro @@ -1,19 +1,20 @@ -HEADERS += \ - panel.h \ - roundrectitem.h \ - splashitem.h +SOURCES += main.cpp \ + roundrectitem.cpp \ + flippablepad.cpp \ + padnavigator.cpp \ + splashitem.cpp -SOURCES += \ - panel.cpp \ - roundrectitem.cpp \ - splashitem.cpp \ - main.cpp +HEADERS += \ + roundrectitem.h \ + flippablepad.h \ + padnavigator.h \ + splashitem.h RESOURCES += \ - padnavigator.qrc + padnavigator.qrc FORMS += \ - backside.ui + form.ui contains(QT_CONFIG, opengl):QT += opengl diff --git a/examples/graphicsview/padnavigator/panel.cpp b/examples/graphicsview/padnavigator/panel.cpp deleted file mode 100644 index c4a5cd9..0000000 --- a/examples/graphicsview/padnavigator/panel.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples 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 "panel.h" -#include "roundrectitem.h" -#include "splashitem.h" -#include "ui_backside.h" - -#ifndef QT_NO_OPENGL -#include -#else -#endif -#include - -#include - -Panel::Panel(int width, int height) - : selectedX(0), - selectedY(0), - width(width), - height(height), - flipped(false), - flipLeft(true) -{ - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setCacheMode(CacheBackground); - setViewportUpdateMode(FullViewportUpdate); - setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform - | QPainter::TextAntialiasing); - setBackgroundBrush(QPixmap(":/images/blue_angle_swirl.jpg")); -#ifndef QT_NO_OPENGL - setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); -#endif - setMinimumSize(50, 50); - - selectionTimeLine = new QTimeLine(150, this); - flipTimeLine = new QTimeLine(500, this); - - QRectF bounds((-width / 2.0) * 150, (-height / 2.0) * 150, width * 150, height * 150); - - scene = new QGraphicsScene(bounds, this); - scene->setItemIndexMethod(QGraphicsScene::NoIndex); - setScene(scene); - - baseItem = new RoundRectItem(bounds, QColor(226, 255, 92, 64)); - scene->addItem(baseItem); - - QWidget *embed = new QWidget; - ui = new Ui_BackSide; - ui->setupUi(embed); - ui->hostName->setFocus(); - - backItem = new RoundRectItem(bounds, embed->palette().window(), embed); - backItem->setTransform(QTransform().rotate(180, Qt::YAxis)); - backItem->setParentItem(baseItem); - - selectionItem = new RoundRectItem(QRectF(-60, -60, 120, 120), Qt::gray); - selectionItem->setParentItem(baseItem); - selectionItem->setZValue(-1); - selectionItem->setPos(posForLocation(0, 0)); - startPos = selectionItem->pos(); - - grid = new QGraphicsItem **[height]; - - for (int y = 0; y < height; ++y) { - grid[y] = new QGraphicsItem *[width]; - - for (int x = 0; x < width; ++x) { - RoundRectItem *item = new RoundRectItem(QRectF(-54, -54, 108, 108), - QColor(214, 240, 110, 128)); - item->setPos(posForLocation(x, y)); - - item->setParentItem(baseItem); - item->setFlag(QGraphicsItem::ItemIsFocusable); - grid[y][x] = item; - - switch (qrand() % 9) { - case 0: item->setPixmap(QPixmap(":/images/kontact_contacts.png")); break; - case 1: item->setPixmap(QPixmap(":/images/kontact_journal.png")); break; - case 2: item->setPixmap(QPixmap(":/images/kontact_notes.png")); break; - case 3: item->setPixmap(QPixmap(":/images/kopeteavailable.png")); break; - case 4: item->setPixmap(QPixmap(":/images/metacontact_online.png")); break; - case 5: item->setPixmap(QPixmap(":/images/minitools.png")); break; - case 6: item->setPixmap(QPixmap(":/images/kontact_journal.png")); break; - case 7: item->setPixmap(QPixmap(":/images/kontact_contacts.png")); break; - case 8: item->setPixmap(QPixmap(":/images/kopeteavailable.png")); break; - default: - break; - } - - connect(item, SIGNAL(activated()), this, SLOT(flip())); - } - } - - grid[0][0]->setFocus(); - - connect(backItem, SIGNAL(activated()), - this, SLOT(flip())); - connect(selectionTimeLine, SIGNAL(valueChanged(qreal)), - this, SLOT(updateSelectionStep(qreal))); - connect(flipTimeLine, SIGNAL(valueChanged(qreal)), - this, SLOT(updateFlipStep(qreal))); - - splash = new SplashItem; - splash->setZValue(5); - splash->setPos(-splash->rect().width() / 2, scene->sceneRect().top()); - scene->addItem(splash); - - splash->grabKeyboard(); - - updateSelectionStep(0); - - setWindowTitle(tr("Pad Navigator Example")); -} - -Panel::~Panel() -{ - for (int y = 0; y < height; ++y) - delete [] grid[y]; - delete [] grid; -} - -void Panel::keyPressEvent(QKeyEvent *event) -{ - if (splash->isVisible() || event->key() == Qt::Key_Return || flipped) { - QGraphicsView::keyPressEvent(event); - return; - } - - selectedX = (selectedX + width + (event->key() == Qt::Key_Right) - (event->key() == Qt::Key_Left)) % width; - selectedY = (selectedY + height + (event->key() == Qt::Key_Down) - (event->key() == Qt::Key_Up)) % height; - grid[selectedY][selectedX]->setFocus(); - - selectionTimeLine->stop(); - startPos = selectionItem->pos(); - endPos = posForLocation(selectedX, selectedY); - selectionTimeLine->start(); -} - -void Panel::resizeEvent(QResizeEvent *event) -{ - QGraphicsView::resizeEvent(event); - fitInView(scene->sceneRect(), Qt::KeepAspectRatio); -} - -void Panel::updateSelectionStep(qreal val) -{ - QPointF newPos(startPos.x() + (endPos - startPos).x() * val, - startPos.y() + (endPos - startPos).y() * val); - selectionItem->setPos(newPos); - - QTransform transform; - yrot = newPos.x() / 6.0; - xrot = newPos.y() / 6.0; - transform.rotate(newPos.x() / 6.0, Qt::YAxis); - transform.rotate(newPos.y() / 6.0, Qt::XAxis); - baseItem->setTransform(transform); -} - -void Panel::updateFlipStep(qreal val) -{ - qreal finalxrot = xrot - xrot * val; - qreal finalyrot; - if (flipLeft) - finalyrot = yrot - yrot * val - 180 * val; - else - finalyrot = yrot - yrot * val + 180 * val; - QTransform transform; - transform.rotate(finalyrot, Qt::YAxis); - transform.rotate(finalxrot, Qt::XAxis); - qreal scale = 1 - sin(3.14 * val) * 0.3; - transform.scale(scale, scale); - baseItem->setTransform(transform); - if (val == 0) - grid[selectedY][selectedX]->setFocus(); -} - -void Panel::flip() -{ - if (flipTimeLine->state() == QTimeLine::Running) - return; - - if (flipTimeLine->currentValue() == 0) { - flipTimeLine->setDirection(QTimeLine::Forward); - flipTimeLine->start(); - flipped = true; - flipLeft = selectionItem->pos().x() < 0; - } else { - flipTimeLine->setDirection(QTimeLine::Backward); - flipTimeLine->start(); - flipped = false; - } -} - -QPointF Panel::posForLocation(int x, int y) const -{ - return QPointF(x * 150, y * 150) - - QPointF((width - 1) * 75, (height - 1) * 75); -} diff --git a/examples/graphicsview/padnavigator/panel.h b/examples/graphicsview/padnavigator/panel.h deleted file mode 100644 index 908092b..0000000 --- a/examples/graphicsview/padnavigator/panel.h +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples 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 - -QT_BEGIN_NAMESPACE -class QTimeLine; -class Ui_BackSide; -QT_END_NAMESPACE - -class RoundRectItem; - -class Panel : public QGraphicsView -{ - Q_OBJECT -public: - Panel(int width, int height); - ~Panel(); - -protected: - void keyPressEvent(QKeyEvent *event); - void resizeEvent(QResizeEvent *event); - -private Q_SLOTS: - void updateSelectionStep(qreal val); - void updateFlipStep(qreal val); - void flip(); - -private: - QPointF posForLocation(int x, int y) const; - - QGraphicsScene *scene; - RoundRectItem *selectionItem; - RoundRectItem *baseItem; - RoundRectItem *backItem; - QGraphicsWidget *splash; - QTimeLine *selectionTimeLine; - QTimeLine *flipTimeLine; - int selectedX, selectedY; - - QGraphicsItem ***grid; - - QPointF startPos; - QPointF endPos; - qreal xrot, yrot; - qreal xrot2, yrot2; - - int width; - int height; - bool flipped; - bool flipLeft; - - Ui_BackSide *ui; -}; diff --git a/examples/graphicsview/padnavigator/roundrectitem.cpp b/examples/graphicsview/padnavigator/roundrectitem.cpp index d53eea4..2141e9a 100644 --- a/examples/graphicsview/padnavigator/roundrectitem.cpp +++ b/examples/graphicsview/padnavigator/roundrectitem.cpp @@ -43,122 +43,61 @@ #include -RoundRectItem::RoundRectItem(const QRectF &rect, const QBrush &brush, QWidget *embeddedWidget) - : QGraphicsRectItem(rect), - brush(brush), - timeLine(75), - lastVal(0), - opa(1), - proxyWidget(0) +RoundRectItem::RoundRectItem(const QRectF &bounds, const QColor &color, + QGraphicsItem *parent) + : QGraphicsObject(parent), fillRect(false), color(color), bounds(bounds) { - connect(&timeLine, SIGNAL(valueChanged(qreal)), - this, SLOT(updateValue(qreal))); - - if (embeddedWidget) { - proxyWidget = new QGraphicsProxyWidget(this); - proxyWidget->setFocusPolicy(Qt::StrongFocus); - proxyWidget->setWidget(embeddedWidget); - proxyWidget->setGeometry(boundingRect().adjusted(25, 25, -25, -25)); - } -} + gradient.setStart(bounds.topLeft()); + gradient.setFinalStop(bounds.bottomRight()); + gradient.setColorAt(0, color); + gradient.setColorAt(1, color.dark(200)); -void RoundRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) -{ - QTransform x = painter->worldTransform(); - - QLineF unit = x.map(QLineF(0, 0, 1, 1)); - if (unit.p1().x() > unit.p2().x() || unit.p1().y() > unit.p2().y()) { - if (proxyWidget && proxyWidget->isVisible()) { - proxyWidget->hide(); - proxyWidget->setGeometry(rect()); - } - return; - } - - if (proxyWidget && !proxyWidget->isVisible()) { - proxyWidget->show(); - proxyWidget->setFocus(); - } - if (proxyWidget && proxyWidget->pos() != QPoint()) - proxyWidget->setGeometry(boundingRect().adjusted(25, 25, -25, -25)); - - painter->setOpacity(opacity()); - painter->setPen(Qt::NoPen); - painter->setBrush(QColor(0, 0, 0, 64)); - painter->drawRoundRect(rect().translated(2, 2)); - - if (!proxyWidget) { - QLinearGradient gradient(rect().topLeft(), rect().bottomRight()); - const QColor col = brush.color(); - gradient.setColorAt(0, col); - gradient.setColorAt(1, col.dark(int(200 + lastVal * 50))); - painter->setBrush(gradient); - } else { - painter->setBrush(brush); - } - - painter->setPen(QPen(Qt::black, 1)); - painter->drawRoundRect(rect()); - if (!pix.isNull()) { - painter->scale(1.95, 1.95); - painter->drawPixmap(-pix.width() / 2, -pix.height() / 2, pix);; - } + setCacheMode(ItemCoordinateCache); } -QRectF RoundRectItem::boundingRect() const +QPixmap RoundRectItem::pixmap() const { - qreal penW = 0.5; - qreal shadowW = 2.0; - return rect().adjusted(-penW, -penW, penW + shadowW, penW + shadowW); + return pix; } void RoundRectItem::setPixmap(const QPixmap &pixmap) { pix = pixmap; - if (scene() && isVisible()) - update(); -} - -qreal RoundRectItem::opacity() const -{ - RoundRectItem *parent = parentItem() ? (RoundRectItem *)parentItem() : 0; - return opa + (parent ? parent->opacity() : 0); + update(); } -void RoundRectItem::setOpacity(qreal opacity) +QRectF RoundRectItem::boundingRect() const { - opa = opacity; - update(); + return bounds.adjusted(0, 0, 2, 2); } -void RoundRectItem::keyPressEvent(QKeyEvent *event) +void RoundRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget) { - if (event->isAutoRepeat() || event->key() != Qt::Key_Return - || (timeLine.state() == QTimeLine::Running && timeLine.direction() == QTimeLine::Forward)) { - QGraphicsRectItem::keyPressEvent(event); - return; + Q_UNUSED(option); + Q_UNUSED(widget); + painter->setPen(Qt::NoPen); + painter->setBrush(QColor(0, 0, 0, 64)); + painter->drawRoundRect(bounds.translated(2, 2)); + if (fillRect) + painter->setBrush(QApplication::palette().brush(QPalette::Window)); + else + painter->setBrush(gradient); + painter->setPen(QPen(Qt::black, 1)); + painter->drawRoundRect(bounds); + if (!pix.isNull()) { + painter->scale(1.95, 1.95); + painter->drawPixmap(-pix.width() / 2, -pix.height() / 2, pix); } - - timeLine.stop(); - timeLine.setDirection(QTimeLine::Forward); - timeLine.start(); - emit activated(); } -void RoundRectItem::keyReleaseEvent(QKeyEvent *event) +bool RoundRectItem::fill() const { - if (event->key() != Qt::Key_Return) { - QGraphicsRectItem::keyReleaseEvent(event); - return; - } - timeLine.stop(); - timeLine.setDirection(QTimeLine::Backward); - timeLine.start(); + return fillRect; } -void RoundRectItem::updateValue(qreal value) +void RoundRectItem::setFill(bool fill) { - lastVal = value; - if (!proxyWidget) - setTransform(QTransform().scale(1 - value / 10.0, 1 - value / 10.0)); + fillRect = fill; + update(); } diff --git a/examples/graphicsview/padnavigator/roundrectitem.h b/examples/graphicsview/padnavigator/roundrectitem.h index 683c09f..ae5fb4c 100644 --- a/examples/graphicsview/padnavigator/roundrectitem.h +++ b/examples/graphicsview/padnavigator/roundrectitem.h @@ -39,45 +39,35 @@ ** ****************************************************************************/ -#include -#include -#include -#include +#ifndef ROUNDRECTITEM_H +#define ROUNDRECTITEM_H -QT_BEGIN_NAMESPACE -class QGraphicsProxyWidget; -QT_END_NAMESPACE +#include +#include -class RoundRectItem : public QObject, public QGraphicsRectItem +class RoundRectItem : public QGraphicsObject { Q_OBJECT + Q_PROPERTY(bool fill READ fill WRITE setFill) public: - RoundRectItem(const QRectF &rect, const QBrush &brush, QWidget *embeddedWidget = 0); - - void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *); - QRectF boundingRect() const; + RoundRectItem(const QRectF &bounds, const QColor &color, + QGraphicsItem *parent = 0); + QPixmap pixmap() const; void setPixmap(const QPixmap &pixmap); - qreal opacity() const; - void setOpacity(qreal opacity); - -Q_SIGNALS: - void activated(); - -protected: - void keyPressEvent(QKeyEvent *event); - void keyReleaseEvent(QKeyEvent *event); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); -private slots: - void updateValue(qreal value); + bool fill() const; + void setFill(bool fill); private: - QBrush brush; QPixmap pix; - QTimeLine timeLine; - qreal lastVal; - qreal opa; - - QGraphicsProxyWidget *proxyWidget; + bool fillRect; + QColor color; + QRectF bounds; + QLinearGradient gradient; }; + +#endif // ROUNDRECTITEM_H diff --git a/examples/graphicsview/padnavigator/splashitem.cpp b/examples/graphicsview/padnavigator/splashitem.cpp index b5b03d4..e609656 100644 --- a/examples/graphicsview/padnavigator/splashitem.cpp +++ b/examples/graphicsview/padnavigator/splashitem.cpp @@ -43,31 +43,31 @@ #include -SplashItem::SplashItem(QGraphicsItem *parent) - : QGraphicsWidget(parent) +SplashItem::SplashItem(QGraphicsItem *parent) : + QGraphicsObject(parent) { - opacity = 1.0; - - - timeLine = new QTimeLine(350); - timeLine->setCurveShape(QTimeLine::EaseInCurve); - connect(timeLine, SIGNAL(valueChanged(qreal)), this, SLOT(setValue(qreal))); - text = tr("Welcome to the Pad Navigator Example. You can use the" " keyboard arrows to navigate the icons, and press enter" - " to activate an item. Please press any key to continue."); - resize(400, 175); + " to activate an item. Press any key to begin."); + setCacheMode(DeviceCoordinateCache); +} + +QRectF SplashItem::boundingRect() const +{ + return QRectF(0, 0, 400, 175); } -void SplashItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +void SplashItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget) { - painter->setOpacity(opacity); + Q_UNUSED(option); + Q_UNUSED(widget); painter->setPen(QPen(Qt::black, 2)); painter->setBrush(QColor(245, 245, 255, 220)); - painter->setClipRect(rect()); + painter->setClipRect(boundingRect()); painter->drawRoundRect(3, -100 + 3, 400 - 6, 250 - 6); - QRectF textRect = rect().adjusted(10, 10, -10, -10); + QRectF textRect = boundingRect().adjusted(10, 10, -10, -10); int flags = Qt::AlignTop | Qt::AlignLeft | Qt::TextWordWrap; QFont font; @@ -76,17 +76,3 @@ void SplashItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWid painter->setFont(font); painter->drawText(textRect, flags, text); } - -void SplashItem::keyPressEvent(QKeyEvent * /* event */) -{ - if (timeLine->state() == QTimeLine::NotRunning) - timeLine->start(); -} - -void SplashItem::setValue(qreal value) -{ - opacity = 1 - value; - setPos(x(), scene()->sceneRect().top() - rect().height() * value); - if (value == 1) - hide(); -} diff --git a/examples/graphicsview/padnavigator/splashitem.h b/examples/graphicsview/padnavigator/splashitem.h index 7a33bee..9d57653 100644 --- a/examples/graphicsview/padnavigator/splashitem.h +++ b/examples/graphicsview/padnavigator/splashitem.h @@ -39,25 +39,22 @@ ** ****************************************************************************/ -#include -#include -#include +#ifndef SPLASHITEM_H +#define SPLASHITEM_H -class SplashItem : public QGraphicsWidget +#include + +class SplashItem : public QGraphicsObject { Q_OBJECT public: - SplashItem(QGraphicsItem *parent = 0); - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); - -protected: - void keyPressEvent(QKeyEvent *event); + explicit SplashItem(QGraphicsItem *parent = 0); -private Q_SLOTS: - void setValue(qreal value); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); private: - QTimeLine *timeLine; QString text; - qreal opacity; }; + +#endif // SPLASHITEM_H -- cgit v0.12 From 812f78e55aa3db4d51ec8617320358d80c4a71d5 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 12 May 2010 16:32:12 +0200 Subject: Documentation for the Pad Navigator Example. This also does a few touch-ups on the source code. --- doc/src/examples/padnavigator.qdoc | 552 ++++++++++++++++++++- doc/src/getting-started/examples.qdoc | 1 + .../graphicsview/padnavigator/flippablepad.cpp | 27 +- examples/graphicsview/padnavigator/flippablepad.h | 5 +- examples/graphicsview/padnavigator/main.cpp | 2 + .../graphicsview/padnavigator/padnavigator.cpp | 218 ++++---- examples/graphicsview/padnavigator/padnavigator.h | 6 +- .../graphicsview/padnavigator/roundrectitem.cpp | 19 +- examples/graphicsview/padnavigator/roundrectitem.h | 5 +- examples/graphicsview/padnavigator/splashitem.cpp | 10 +- examples/graphicsview/padnavigator/splashitem.h | 2 + 11 files changed, 736 insertions(+), 111 deletions(-) diff --git a/doc/src/examples/padnavigator.qdoc b/doc/src/examples/padnavigator.qdoc index 70e131e..e29a3b2 100644 --- a/doc/src/examples/padnavigator.qdoc +++ b/doc/src/examples/padnavigator.qdoc @@ -43,9 +43,555 @@ \example graphicsview/padnavigator \title Pad Navigator Example - The Pad Navigator Example shows how you can use Graphics View - together with embedded widgets to create a simple but useful - dynamic user interface for embedded devices. + The Pad Navigator Example shows how you can use Graphics View together with + embedded widgets and Qt's \l{State Machine Framework} to create a simple + but useful, dynamic, animated user interface. \image padnavigator-example.png + + The interface consists of a flippable, rotating pad with icons that can be + selected using the arrow keys on your keyboard or keypad. Pressing enter + will flip the pad around and reveal its back side, which has a form + embedded into a QGraphicsProxyWidget. You can interact with the form, and + press the enter key to flip back to the front side of the pad at any time. + + Graphics View provides the QGraphicsScene class for managing and + interacting with a large number of custom-made 2D graphical items derived + from the QGraphicsItem class, and a QGraphicsView widget for visualizing + the items, with support for zooming and rotation. + + This example consists of a \c RoundRectItem class, a \c FlippablePad class, + a \c PadNavigator class, a \c SplashItem class, and a \c main() function. + + \section1 RoundRectItem Class Definition + + The \c RoundRectItem class is used by itself to diplay the icons on the + pad, and as a base class for \c FlippablePad, the class for the pad itself. + The role of the class is to paint a round rectangle of a specified size and + gradient color, and optionally to paint a pixmap icon on top. To support \c + FlippablePad it also allows filling its contents with a plain window + background color. + + Let's start by reviewing the \c RoundRectItem class declaration. + + \snippet examples/graphicsview/padnavigator/roundrectitem.h 0 + + \c RoundRectItem inherits QGraphicsObject, which makes it easy to control + its properties using QPropertyAnimation. Its constructor takes a rectangle + to determine its bounds, and a color. + + Besides implementing the mandatory \l{QGraphicsItem::paint()}{paint()} and + \l{QGraphicsItem::boundingRect()}{boundingRect()} pure virtual functions, + it also provides the \c pixmap and \c fill properties. + + The \c pixmap property sets an optional pixmap that is drawn on top of the + round rectangle. The \c fill property will, when true, fill the round + rectangle contents with a fixed QPalette::Window background color. + Otherwise the contents are filled using a gradient based on the color + passed to \c RoundRectItem's constructor. + + \snippet examples/graphicsview/padnavigator/roundrectitem.h 1 + + The private data members are: + + \list + \o \c pix: The optional pixmap that is drawn on top of the rectangle. + \o \c fillRect: Corresponds to the \c fill property. + \o \c color: The configurable gradient color fill of the rectangle. + \o \c bounds: The bounds of the rectangle. + \o \c gradient: A precalculated gradient used to fill the rectangle. + \endlist + + We will now review the \c RoundRectItem implementation. Let's start by + looking at its constructor: + + \snippet examples/graphicsview/padnavigator/roundrectitem.cpp 0 + + The constructor initializes its member variables and forwards the \c parent + argument to QGraphicsObject's constructor. It then constructs the linear + gradient that is used in \l{QGraphicsItem::paint()}{paint()} to draw the + round rectangle's gradient background. The linear gradient's starting point + is at the top-left corner of the bounds, and the end is at the bottom-left + corner. The start color is identical to the color passed as an argument, + and a slightly darker color is chosen for the final stop. + + We store this gradient as a member variable to avoid having to recreate the + gradient every time the item is repainted. + + Finally we set the cache mode + \l{QGraphicsItem::ItemCoordinateCache}{ItemCoordinateCache}. This mode + causes the item's rendering to be cached into an off-screen pixmap that + remains persistent as we move and transform the item. This mode is ideal + for this example, and works particularily well with OpenGL and OpenGL ES. + + \snippet examples/graphicsview/padnavigator/roundrectitem.cpp 1 + + The \c pixmap property implementation simple returns the member pixmap, or + sets it and then calls \l{QGraphicsItem::update()}{update()}. + + \snippet examples/graphicsview/padnavigator/roundrectitem.cpp 2 + + As the \l{QGraphicsItem::paint()}{paint()} implementation below draws a + simple drop shadow down and to the right of the item, we return a slightly + adjusted rectangle from \l{QGraphicsItem::boundingRect()}{boundingRect()}. + + \snippet examples/graphicsview/padnavigator/roundrectitem.cpp 3 + + The \l{QGraphicsItem::paint()}{paint()} implementation starts by rendering + a semi transparent black round rectangle drop shadow, two units down and to + the right of the main item. + + \snippet examples/graphicsview/padnavigator/roundrectitem.cpp 4 + + We then draw the "foreground" round rectangle itself. The fill depends on + the \c fill property; if true, we will with a plain QPalette::Window color. + We get the corrent brush from QApplication::palette(). We assign a single + unit wide pen for the stroke, assign the brush, and then draw the + rectangle. + + \snippet examples/graphicsview/padnavigator/roundrectitem.cpp 5 + + If a pixmap has been assigned to the \e pixmap property, we draw this + pixmap in the center of the rectangle item. The pixmaps are scaled to match + the size of the icons; in arguably a better approach would have been to + store the icons with the right size in the first places. + + \snippet examples/graphicsview/padnavigator/roundrectitem.cpp 6 + + Finally, for completeness we include the \c fill property implementation. + It returns the \c fill member variable's value, and when assigned to, it + calls \l{QGraphicsItem::update()}{update()}. + + As mentioned already, \c RoundRectItem is the base class for \c + FlippablePad, which is the class representing the tilting pad itself. We + will proceed to reviewing \c FlippablePad. + + \section1 FlippablePad Class Definition + + \c FlippablePad is, in addition to its inherited \c RoundRectItem + responsibilities, responsible for creating and managing a grid of icons. + + \snippet examples/graphicsview/padnavigator/flippablepad.h 0 + + Its declaration is very simple: It inherits \c RoundRectItem and does not + need any special polymorphic behavior. It's suitable to declare its own + constructor, and a getter-function that allows \c PadNavigator to access + the icons in the grid by (row, column). + + The example has no "real" behavior or logic of any kind, and because of + that, the icons do not need to provide any \e behavior or special + interactions management. In a real application, however, it would be + natural for the \c FlippablePad and its icons to handle more of the + navigation logic. In this example, we have chosen to leave this to + the \c PadNavigator class, which we will get back to below. + + We will now review the \c FlippablePad implementation. This implementation + starts with two helper functions: \c boundsFromSize() and \c + posForLocation(): + + \snippet examples/graphicsview/padnavigator/flippablepad.cpp 0 + + \c boundsForSize() takes a QSize argument, and returns the bounding + rectangle of the flippable pad item. The QSize determines how many rows and + columns the icon grid should have. Each icon is given 150x150 units of + space, and this determines the bounds. + + \snippet examples/graphicsview/padnavigator/flippablepad.cpp 1 + + \c posForLocation() returns the position of an icon given its row and + column position. Like \c boundsForSize(), the function assumes each icon is + given 150x150 units of space, and that all icons are centered around the + flippable pad item's origin (0, 0). + + \snippet examples/graphicsview/padnavigator/flippablepad.cpp 2 + + The \c FlippablePad constructor passes suitable bounds (using \c + boundsForSize()) and specific color to \c RoundRectItem's constructor. + + \snippet examples/graphicsview/padnavigator/flippablepad.cpp 3 + + It then loads pixmaps from compiled-in resources to use for its icons. + QDirIterator is very useful in this context, as it allows us to fetch all + resource "*.png" files inside the \c :/images directory without explicitly + naming the files. + + We also make sure not to load more pixmaps than we need. + + \snippet examples/graphicsview/padnavigator/flippablepad.cpp 4 + + Now that we have the pixmaps, we can create icons, position then and assign + pixmaps. We start by finding a suitable size and color for the icons, and + initializing a convenient grid structure for storing the icons. This \c + iconGrid is also used later to find the icon for a specific (column, row) + location. + + For each row and column in our grid, we proceed to constructing each icon + as an instance of \c RoundRectItem. The item is placed by using the \c + posForLocation() helper function. To make room for the slip-behind + selection item, we give each icon a \l{QGraphicsItem::zValue()}{Z-value} of + 1. The pixmaps are distributed to the icons in round-robin fasion. + + Again, this approach is only suitable for example purposes. In a real-life + application where each icon represents a specific action, it would be more + natural to assign the pixmaps directly, or that the icons themselves + provide suitable pixmaps. + + \snippet examples/graphicsview/padnavigator/flippablepad.cpp 5 + + Finally, the \c iconAt() function returns a pointer to the icon at a + specific row and column. It makes a somewhat bold assumption that the input + is valid, which is fair because the \c PadNavigator class only calls this + function with correct input. + + We will now review the \c SplashItem class. + + \section1 SplashItem Class Definition + + The \c SplashItem class represents the "splash window", a semitransparent + white overlay with text that appears immediately after the application has + started, and disappears after pressing any key. The animation is controlled + by \c PadNavigator; this class is very simple by itself. + + \snippet examples/graphicsview/padnavigator/splashitem.h 0 + + The class declaration shows that \c SplashItem inherits QGraphicsObject to + allow it to be controlled by QPropertyAnimation. It reimplements the + mandatory \l{QGraphicsItem::paint()}{paint()} and + \l{QGraphicsItem::boundingRect()}{boundingRect()} pure virtual functions, + and keeps a \c text member variable which will contain the information text + displayed on this splash item. + + Let's look at its implementation. + + \snippet examples/graphicsview/padnavigator/splashitem.cpp 0 + + The constructor forwards to QGraphicsObject as expected, assigns a text + message to the \c text member variable, and enables + \l{QGraphicsItem::DeviceCoordinateCache}{DeviceCoordinateCache}. This cache + mode is suitable because the splash item only moves and is never + transformed, and because it contains text, it's important that it has a + pixel perfect visual appearance (in constrast to + \l{QGraphicsItem::ItemCoordinateCache}{ItemCoordinateCache}, where the + visual appearance is not as good). + + We use caching to avoid having to relayout and rerender the text for each + frame. An alterative approach would be to use the new QStaticText class. + + \snippet examples/graphicsview/padnavigator/splashitem.cpp 1 + + \c SplashItem's bounding rectangle is fixed at (400x175). + + \snippet examples/graphicsview/padnavigator/splashitem.cpp 2 + + The \l{QGraphicsItem::paint()}{paint()} implementation draws a clipped + round rectangle with a thick 2-unit border and a semi-transparent white + background. It proceeds to finding a suitable text area by adjusting the + splash item's bounding rectangle with 10 units in each side. The text is + rendered inside this rectangle, with top-left alignment, and with word + wrapping enabled. + + The main class now remains. We will proceed to reviewing \c PadNavigator. + + \section1 PadNavigator Class Definition + + \c PadNavigator represents the main window of our Pad Navigator Example + application. It creates and controls a somewhat complex state machine, and + several animations. Its class declaration is very simple: + + \snippet examples/graphicsview/padnavigator/padnavigator.h 0 + + It inherits QGraphicsView and reimplements only one function: + \l{QGraphicsView::resizeEvent()}{resizeEvent()}, to ensure the scene is + scaled to fit inside the view when resizing the main window. + + The \c PadNavigator constructor takes a QSize argument that determines the + number or rows and columns in the grid. + + It also keeps a private member instance, \c form, which is the generated + code for the pad's back side item's QGraphicsProxyWidget-embedded form. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 0 + + \c PadNavigator's constructor is a bit long. In short, its job is to create + all items, including the \c FlippablePad, the \c SplashItem and the + QGraphicsProxyWidget \c backItem, and then to set up all animations, states + and transitions that control the behavior of the application. + + It starts out simple, by forwarding to QGraphicsView's constructor. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 1 + + The first item to be created is \c SplashItem. This is going to be a top-level + item in the scene, next to \c FlippablePad, and stacked on top of it, so we + assign it a \l{QGraphicsItem::zValue()}{Z-value} of 1. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 2 + + Now we construct the \c FlippablePad item, passing its column-row count to + its constructor. + + The pad is constrolled by three transformations, and we create one + QGraphicsRotation object for each of these. + + \list + \o \c flipRotation: Rotates the grid around its Qt::YAxis. This rotation is + animated from 0 to 180, and eventually back, when enter is pressed on the + keyboard, flipping the pad around. + \o \c xRotation: Rotates the grid around its Qt::XAxis. This is used to + tilt the pad vertically corresponding to which item is currently selected. + This way, the selected item is always kept in front. + \o \c yRotation: Rotates the grid around its Qt::YAxis. This is used to + tilt the pad horizontally corresponding to which item is selected. This + way, the selected item is always kept in front. + \endlist + + The combination of all three rotations is assigned via + QGraphicsItem::setTransformations(). + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 3 + + Now we construct the QGraphicsProxyWidget-embedded \c backItem. The proxy + widget is created as a child of the pad. We create a new QWidget and + populate it with the \c form member. To ensure the \c hostName line edit is + the first to receive input focus when this item is shown, we call + \l{QWidget::setFocus()}{setFocus()} immediately. This will not give the + widget focus right away; it will only prepare the item to automatically + receive focus once it is shown. + + The QWidget based form is embedded into the proxy widget. The proxy is + hidden initially; we only want to show it when the pad is rotated at least + 90 degrees, and we also rotate the proxy itself by 180 degrees. This way we + give the impression that the proxy widget is "behind" the flipped pad, when + in fact, it's actually \e{on top of it}. + + We enable \l{QGraphicsItem::ItemCoordinateCache}{ItemCoordinateCache} to + ensure the flip animation can run smoothly. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 4 + + We now create the selection item. This is simply another instance of \c + RoundRectItem that is slightly larger than the icons on the pad. We create + it as an immediate child of the \c FlippablePad, so the selection item is a + sibling to all the icons. By giving it a + \l{QGraphicsItem::zValue()}{Z-value} of 0.5 we ensure it will slide beteen + the pad and its icons. + + What follows now is a series of animation initializations. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 5 + + We begin with the animations that apply to the splash item. The first + animation, \c smoothSplashMove, ensures that the "y" property of \c splash + will be animated with a 250-millisecond duration + \l{QEasingCurve::InQuad}{InQuad} easing function. \c smoothSplashOpacity + ensures the opacity of \c splash eases in and out in 250 milliseconds. + + The values are assigned by \c PadNavigator's state machine, which is + created later. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 6 + + These are the animations that control the selection item's movement and the + \c xRotation and \c yRotation QGraphicsRotation objects that tilt the pad. + All animations have a duration of 125 milliseconds, and they all use the + \l{QEasingCurve::InOutQuad}{InOutQuad} easing function. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 7 + + We now create the animations that control the flip-effect when you press + the enter key. The main goal is to rotate the pad by 180 degrees or back, + but we also need to make sure the selection item's tilt rotations are reset + back to 0 when the pad is flipped, and restored back to their original + values when flipped back: + + \list + \o \c smoothFlipRotation: Animates the main 180 degree rotation of the pad. + \o \c smoothFlipScale: Scales the pad out and then in again while the pad is rotating. + \o \c smoothFlipXRotation: Animates the selection item's X-tilt to 0 and back. + \o \c smoothFlipYRotation: Animates the selection item's Y-tilt to 0 and back. + \o \c flipAnimation: A parallel animation group that ensures all the above animations are run in parallel. + \endlist + + All animations are given a 500 millisecond duration and an + \l{QEasingCurve::InOutQuad}{InOutQuad} easing function. + + It's worth taking a close look at \c smoothFlipScale. This animation's + start and end values are both 1.0, but at animation step 0.5 the + animation's value is 0.7. This means that after 50% of the animation's + duration, or 250 milliseconds, the pad will be scaled down to 0.7x of its + original size, which gives a great visual effect while flipping. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 8 + + This section uses a trick to ensure that certain properties are assigned + precisely when the flip animation passes 50%, or 90 degrees, rotation. In + short, the pad's icons and selection item are all hidden, the pad's \c fill + property is enabled, and \c backItem is shown when flipping over. When + flipping back, the reverse properties are applied. + + The way this is achieved is by running a sequential animation in parallel + to the other animations. This sequence, dubbed \c setVariablesSequence, + starts with a 250 millisecond pause, and then executes several animations + with a duration of 0. Each animation will ensure that properties are set + immediate at this point. + + This approach can also be used to call functions or set any other + properties at a specific time while an animation is running. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 9 + + We will now create the state machine. The whole \c PadNavigator state + machinery is controlled by one single state machine that has a + straight-forward state structure. The state engine itself is created + as a child of the \c PadNavigator itself. We then create three top level + states: + + \list + \o \c splashState: The initial state where the splash item is visible. + \o \c frontState: The base state where the splash is gone and we can see + the front side of the pad, and navigate the selection item. + \o \c backState: The flipped state where the \c backItem is visible, and we + can interact with the QGraphicsProxyWidget-embedded form. + \endlist + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 10 + + Each state assigns specific properties to objects on entry. Most + interesting perhaps is the assignment of the value 0.0 to the pad's \c + flipRotation angle property when in \c frontState, and 180.0 when in \c + backState. At the end of this section we register default animations with + the state engine; these animations will apply to their respective objects + and properties for any state transition. Otherwise it's common to assign + animations to specific transitions. + + The \c splashState state is set as the initial state. This is required + before we start the state engine. We proceed with creating some + transitions. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 11 + + QEventTransition defines a very flexible transition type. You can use this + class to trigger a transition based on an object receiving an event of a + specific type. In this case, we would like to transition from \c + splashState into \c frontState if \c PadNavigator receives any key press + event (QEvent::KeyPress). + + We register the \c splashItem's animations to this transition to ensure they + are used to animate the item's movement and opacity. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 12 + + We use QKeyEventTransition to capture specific key events. In this case, we + detect that the user presses Qt::Key_Return or Qt::Key_Enter, and use this + to trigger transitions between \c frontState and backState. We register \c + flipAnimation, our complex parallel animation group, with these + transitions. + + We continue by defining the states for each of the icons in the grid. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 13 + + We will use state groups to control transitions between icons. Each icon + represents a \e substate of \c frontState. We will then define transitions + between the states by detecting key presses, using QKeyEventTransition. + + We start by creating all the substates, and at the same time we create a + temporary grid structure for the states to make it easier to find which + states represents icons that are up, down, left and to the right each + other. + + Once the first substate is known, we set this up as the initial substate of + \c frontState. We will use the (0, 0), or top-left, icon for the initial + substate. We initialze the selection item's position to be exactly where + the top-left icon is. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 14 + + We can now create four transitions for each icon. Each transition ensures + that we move to the state corresponding to which arrow key has been + pressed. It's clear from this techinique that we could design any other + specific transitions to and from each of the sub states depending on these + and other keys. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 15 + + Also, for each of the icons, we assign suitable values to the \c xRotation + and \c yRotation objects' "angle"-properties. If you recall, these + properties "tilt" the pad corresponding to which item is currently + selected. We ensure each icon is invisible when the pad is flipped, and + visible when the pad is not flipped. To ensure the visible property is + assigned at the right time, we add property-controlling animations to the + \c setVariableSequence animation defined earlier. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 16 + + We are now finished with all states, transitions, and animations. We now + create the scene that will contain all our items. The scene gets a defined + background pixmap, and we disable item indexing (as most items in this + scene are animated). We add our \c pad item to the scene, and use its + bounding rectangle to fixate the scene rectangle. This rectangle is used by + the view to find a suitable size for the application window. + + Then the scene is assigned to the view, or in our case, \c PadNavigator + itself. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 17 + + Now that the scene has received its final size, we can position the splash + item at the very top, find its fade-out position, and add it to the scene. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 18 + + The view toggles a few necessary properties: + + \list + \o It disables its scroll bars - this application has no use for scroll bars. + \o It assigns a minimum size. This is necessary to avoid numerical errors + in our fit-in-view \c resizeEvent() implementation. + \o It sets \l{QGraphicsView::FullViewportUpdate}{FullViewportUpdate}, to + ensure QGraphicsView doesn't spend time figuring out precisely what needs + to be redrawn. This application is very simple - if anything changes, + everything is updated. + \o It enables background caching - this makes no performance difference + with OpenGL, but without OpenGL it avoids unnecessary re-scaling of the + background pixmap. + \o It sets render hints that increase rendering quality. + \o If OpenGL is supported, a QGLWidget viewport is assigned to the view. + \endlist + + Finally, we start the state engine. + + \snippet examples/graphicsview/padnavigator/padnavigator.cpp 19 + + The \l{QGraphicsView::resizeEvent()}{resizeEvent()} implementation calls + the base implementation, and then calls QGraphicsView::fitInView() to scale + the scene so that it fits perfectly inside the view. + + By resizing the main application window, you can see this effect yourself. + The scene contents grow when you make the window larger, and shrink when + you make it smaller, while keeping the aspect ratio intact. + + \section1 The main() Function + + \snippet examples/graphicsview/padnavigator/main.cpp 0 + + The \c main function creates the QApplication instance, uses + Q_INIT_RESOURCE to ensure our compiled-in resources aren't removed by the + linker, and then creates a 3x3 \c PadNavigator instance and shows it. + + Our flippable pad shows up with a suitable splash item once control returns + to the event loop. + + \section1 Performance Notes + + The example uses OpenGL if this is available, to achieve optimal + performance; otherwise perspective tranformations can be quite costly. + + Although this example does use QGraphicsProxyWidget to demonstrate + integration of Qt widget components integrated into Graphics View, using + QGraphicsProxyWidget comes with a performance penalty, and is therefore not + recommended for embedded development. + + This example uses extensive item caching to avoid rerendering of static + elements, at the expense of graphics memory. */ diff --git a/doc/src/getting-started/examples.qdoc b/doc/src/getting-started/examples.qdoc index 542f672..f511cd6 100644 --- a/doc/src/getting-started/examples.qdoc +++ b/doc/src/getting-started/examples.qdoc @@ -651,6 +651,7 @@ \o \l{graphicsview/diagramscene}{Diagram Scene}\raisedaster \o \l{graphicsview/dragdroprobot}{Drag and Drop Robot}\raisedaster \o \l{graphicsview/elasticnodes}{Elastic Nodes}\raisedaster + \o \l{graphicsview/padnavigator}{Pad Navigator}\raisedaster \o \l{graphicsview/portedasteroids}{Ported Asteroids} \o \l{graphicsview/portedcanvas}{Ported Canvas} \endlist diff --git a/examples/graphicsview/padnavigator/flippablepad.cpp b/examples/graphicsview/padnavigator/flippablepad.cpp index 61f421f..58aea00 100644 --- a/examples/graphicsview/padnavigator/flippablepad.cpp +++ b/examples/graphicsview/padnavigator/flippablepad.cpp @@ -43,37 +43,43 @@ #include +//! [0] static QRectF boundsFromSize(const QSize &size) { return QRectF((-size.width() / 2.0) * 150, (-size.height() / 2.0) * 150, size.width() * 150, size.height() * 150); } +//! [0] -static QPointF posForLocation(int x, int y, const QSize &size) +//! [1] +static QPointF posForLocation(int column, int row, const QSize &size) { - return QPointF(x * 150, y * 150) + return QPointF(column * 150, row * 150) - QPointF((size.width() - 1) * 75, (size.height() - 1) * 75); } +//! [1] +//! [2] FlippablePad::FlippablePad(const QSize &size, QGraphicsItem *parent) : RoundRectItem(boundsFromSize(size), QColor(226, 255, 92, 64), parent) { - columns = size.width(); - +//! [2] +//! [3] int numIcons = size.width() * size.height(); QList pixmaps; QDirIterator it(":/images", QStringList() << "*.png"); while (it.hasNext() && pixmaps.size() < numIcons) pixmaps << it.next(); +//! [3] +//! [4] const QRectF iconRect(-54, -54, 108, 108); const QColor iconColor(214, 240, 110, 128); - iconGrid.resize(size.height()); - int n = 0; + for (int y = 0; y < size.height(); ++y) { - iconGrid[y].resize(columns); + iconGrid[y].resize(size.width()); for (int x = 0; x < size.width(); ++x) { RoundRectItem *rect = new RoundRectItem(iconRect, iconColor, this); rect->setZValue(1); @@ -83,8 +89,11 @@ FlippablePad::FlippablePad(const QSize &size, QGraphicsItem *parent) } } } +//! [4] -RoundRectItem *FlippablePad::iconAt(int x, int y) const +//! [5] +RoundRectItem *FlippablePad::iconAt(int column, int row) const { - return iconGrid[y][x]; + return iconGrid[row][column]; } +//! [5] diff --git a/examples/graphicsview/padnavigator/flippablepad.h b/examples/graphicsview/padnavigator/flippablepad.h index 9adb18b..7d99536 100644 --- a/examples/graphicsview/padnavigator/flippablepad.h +++ b/examples/graphicsview/padnavigator/flippablepad.h @@ -48,16 +48,17 @@ #include #include +//! [0] class FlippablePad : public RoundRectItem { public: FlippablePad(const QSize &size, QGraphicsItem *parent = 0); - RoundRectItem *iconAt(int x, int y) const; + RoundRectItem *iconAt(int column, int row) const; private: - int columns; QVector > iconGrid; }; +//! [0] #endif // FLIPPABLEPAD_H diff --git a/examples/graphicsview/padnavigator/main.cpp b/examples/graphicsview/padnavigator/main.cpp index 6d148bb..984b976 100644 --- a/examples/graphicsview/padnavigator/main.cpp +++ b/examples/graphicsview/padnavigator/main.cpp @@ -43,6 +43,7 @@ #include +//! [0] int main(int argc, char *argv[]) { QApplication app(argc, argv); @@ -53,3 +54,4 @@ int main(int argc, char *argv[]) return app.exec(); } +//! [0] diff --git a/examples/graphicsview/padnavigator/padnavigator.cpp b/examples/graphicsview/padnavigator/padnavigator.cpp index 456b3f4..b1d19f6 100644 --- a/examples/graphicsview/padnavigator/padnavigator.cpp +++ b/examples/graphicsview/padnavigator/padnavigator.cpp @@ -42,175 +42,213 @@ #include "flippablepad.h" #include "padnavigator.h" #include "splashitem.h" -#include "ui_form.h" #include #ifndef QT_NO_OPENGL #include #endif +//! [0] PadNavigator::PadNavigator(const QSize &size, QWidget *parent) : QGraphicsView(parent) { - // Prepare splash item +//! [0] +//! [1] + // Splash item SplashItem *splash = new SplashItem; splash->setZValue(1); +//! [1] - // Prepare pad item +//! [2] + // Pad item FlippablePad *pad = new FlippablePad(size); QGraphicsRotation *flipRotation = new QGraphicsRotation(pad); - flipRotation->setAxis(Qt::YAxis); QGraphicsRotation *xRotation = new QGraphicsRotation(pad); - xRotation->setAxis(Qt::YAxis); QGraphicsRotation *yRotation = new QGraphicsRotation(pad); + flipRotation->setAxis(Qt::YAxis); + xRotation->setAxis(Qt::YAxis); yRotation->setAxis(Qt::XAxis); pad->setTransformations(QList() << flipRotation << xRotation << yRotation); +//! [2] - // Prepare backitem - form = new Ui_Form; - QWidget *widget = new QWidget; - form->setupUi(widget); - form->hostName->setFocus(); +//! [3] + // Back (proxy widget) item QGraphicsProxyWidget *backItem = new QGraphicsProxyWidget(pad); - backItem->setCacheMode(QGraphicsItem::ItemCoordinateCache); + QWidget *widget = new QWidget; + form.setupUi(widget); + form.hostName->setFocus(); backItem->setWidget(widget); + backItem->setVisible(false); + backItem->setFocus(); + backItem->setCacheMode(QGraphicsItem::ItemCoordinateCache); + const QRectF r = backItem->rect(); backItem->setTransform(QTransform() .rotate(180, Qt::YAxis) - .translate(-backItem->rect().width()/2, -backItem->rect().height()/2)); - backItem->setFocus(); - backItem->setVisible(false); + .translate(-r.width()/2, -r.height()/2)); +//! [3] - // Prepare selection item +//! [4] + // Selection item RoundRectItem *selectionItem = new RoundRectItem(QRectF(-60, -60, 120, 120), Qt::gray, pad); selectionItem->setZValue(0.5); +//! [4] - // Selection animation setup +//! [5] + // Splash animations + QPropertyAnimation *smoothSplashMove = new QPropertyAnimation(splash, "y"); + QPropertyAnimation *smoothSplashOpacity = new QPropertyAnimation(splash, "opacity"); + smoothSplashMove->setEasingCurve(QEasingCurve::InQuad); + smoothSplashMove->setDuration(250); + smoothSplashOpacity->setDuration(250); +//! [5] + +//! [6] + // Selection animation QPropertyAnimation *smoothXSelection = new QPropertyAnimation(selectionItem, "x"); - smoothXSelection->setDuration(125); - smoothXSelection->setEasingCurve(QEasingCurve::InOutQuad); QPropertyAnimation *smoothYSelection = new QPropertyAnimation(selectionItem, "y"); - smoothYSelection->setDuration(125); - smoothYSelection->setEasingCurve(QEasingCurve::InOutQuad); QPropertyAnimation *smoothXRotation = new QPropertyAnimation(xRotation, "angle"); - smoothXRotation->setDuration(125); - smoothXRotation->setEasingCurve(QEasingCurve::InOutQuad); QPropertyAnimation *smoothYRotation = new QPropertyAnimation(yRotation, "angle"); + smoothXSelection->setDuration(125); + smoothYSelection->setDuration(125); + smoothXRotation->setDuration(125); smoothYRotation->setDuration(125); + smoothXSelection->setEasingCurve(QEasingCurve::InOutQuad); + smoothYSelection->setEasingCurve(QEasingCurve::InOutQuad); + smoothXRotation->setEasingCurve(QEasingCurve::InOutQuad); smoothYRotation->setEasingCurve(QEasingCurve::InOutQuad); - QPropertyAnimation *smoothScale = new QPropertyAnimation(pad, "scale"); - smoothScale->setDuration(500); - smoothScale->setKeyValueAt(0, qVariantValue(1.0)); - smoothScale->setKeyValueAt(0.5, qVariantValue(0.7)); - smoothScale->setKeyValueAt(1, qVariantValue(1.0)); - smoothScale->setEasingCurve(QEasingCurve::InOutQuad); +//! [6] +//! [7] // Flip animation setup QPropertyAnimation *smoothFlipRotation = new QPropertyAnimation(flipRotation, "angle"); + QPropertyAnimation *smoothFlipScale = new QPropertyAnimation(pad, "scale"); + QPropertyAnimation *smoothFlipXRotation = new QPropertyAnimation(xRotation, "angle"); + QPropertyAnimation *smoothFlipYRotation = new QPropertyAnimation(yRotation, "angle"); + QParallelAnimationGroup *flipAnimation = new QParallelAnimationGroup(this); + smoothFlipScale->setDuration(500); smoothFlipRotation->setDuration(500); + smoothFlipXRotation->setDuration(500); + smoothFlipYRotation->setDuration(500); + smoothFlipScale->setEasingCurve(QEasingCurve::InOutQuad); smoothFlipRotation->setEasingCurve(QEasingCurve::InOutQuad); - QPropertyAnimation *flipSmoothXRotation = new QPropertyAnimation(xRotation, "angle"); - flipSmoothXRotation->setDuration(500); - flipSmoothXRotation->setEasingCurve(QEasingCurve::InOutQuad); - QPropertyAnimation *flipSmoothYRotation = new QPropertyAnimation(yRotation, "angle"); - flipSmoothYRotation->setDuration(500); - flipSmoothYRotation->setEasingCurve(QEasingCurve::InOutQuad); - QPropertyAnimation *setBackItemVisibleAnim = new QPropertyAnimation(backItem, "visible"); - setBackItemVisibleAnim->setDuration(0); - QPropertyAnimation *setSelectionItemVisibleAnim = new QPropertyAnimation(selectionItem, "visible"); - setSelectionItemVisibleAnim->setDuration(0); - QPropertyAnimation *setFillAnim = new QPropertyAnimation(pad, "fill"); - setFillAnim->setDuration(0); - QSequentialAnimationGroup *setVisibleAnimation = new QSequentialAnimationGroup; - setVisibleAnimation->addPause(250); - setVisibleAnimation->addAnimation(setBackItemVisibleAnim); - setVisibleAnimation->addAnimation(setSelectionItemVisibleAnim); - setVisibleAnimation->addAnimation(setFillAnim); - QParallelAnimationGroup *flipAnimation = new QParallelAnimationGroup(this); + smoothFlipXRotation->setEasingCurve(QEasingCurve::InOutQuad); + smoothFlipYRotation->setEasingCurve(QEasingCurve::InOutQuad); + smoothFlipScale->setKeyValueAt(0, qVariantValue(1.0)); + smoothFlipScale->setKeyValueAt(0.5, qVariantValue(0.7)); + smoothFlipScale->setKeyValueAt(1, qVariantValue(1.0)); flipAnimation->addAnimation(smoothFlipRotation); - flipAnimation->addAnimation(smoothScale); - flipAnimation->addAnimation(flipSmoothXRotation); - flipAnimation->addAnimation(flipSmoothYRotation); - flipAnimation->addAnimation(setVisibleAnimation); + flipAnimation->addAnimation(smoothFlipScale); + flipAnimation->addAnimation(smoothFlipXRotation); + flipAnimation->addAnimation(smoothFlipYRotation); +//! [7] - QPropertyAnimation *smoothSplashMove = new QPropertyAnimation(splash, "y"); - smoothSplashMove->setEasingCurve(QEasingCurve::InQuad); - smoothSplashMove->setDuration(250); - QPropertyAnimation *smoothSplashOpacity = new QPropertyAnimation(splash, "opacity"); - smoothSplashOpacity->setDuration(250); +//! [8] + // Flip animation delayed property assignment + QSequentialAnimationGroup *setVariablesSequence = new QSequentialAnimationGroup; + QPropertyAnimation *setFillAnimation = new QPropertyAnimation(pad, "fill"); + QPropertyAnimation *setBackItemVisibleAnimation = new QPropertyAnimation(backItem, "visible"); + QPropertyAnimation *setSelectionItemVisibleAnimation = new QPropertyAnimation(selectionItem, "visible"); + setFillAnimation->setDuration(0); + setBackItemVisibleAnimation->setDuration(0); + setSelectionItemVisibleAnimation->setDuration(0); + setVariablesSequence->addPause(250); + setVariablesSequence->addAnimation(setBackItemVisibleAnimation); + setVariablesSequence->addAnimation(setSelectionItemVisibleAnimation); + setVariablesSequence->addAnimation(setFillAnimation); + flipAnimation->addAnimation(setVariablesSequence); +//! [8] +//! [9] // Build the state machine QStateMachine *stateMachine = new QStateMachine(this); QState *splashState = new QState(stateMachine); QState *frontState = new QState(stateMachine); QHistoryState *historyState = new QHistoryState(frontState); QState *backState = new QState(stateMachine); +//! [9] +//! [10] + frontState->assignProperty(pad, "fill", false); frontState->assignProperty(splash, "opacity", 0.0); - frontState->assignProperty(flipRotation, "angle", qVariantValue(0.0)); frontState->assignProperty(backItem, "visible", false); + frontState->assignProperty(flipRotation, "angle", qVariantValue(0.0)); frontState->assignProperty(selectionItem, "visible", true); - frontState->assignProperty(pad, "fill", false); - backState->assignProperty(flipRotation, "angle", qVariantValue(180.0)); + backState->assignProperty(pad, "fill", true); + backState->assignProperty(backItem, "visible", true); backState->assignProperty(xRotation, "angle", qVariantValue(0.0)); backState->assignProperty(yRotation, "angle", qVariantValue(0.0)); + backState->assignProperty(flipRotation, "angle", qVariantValue(180.0)); backState->assignProperty(selectionItem, "visible", false); - backState->assignProperty(backItem, "visible", true); - backState->assignProperty(pad, "fill", true); stateMachine->addDefaultAnimation(smoothXRotation); stateMachine->addDefaultAnimation(smoothYRotation); stateMachine->addDefaultAnimation(smoothXSelection); stateMachine->addDefaultAnimation(smoothYSelection); stateMachine->setInitialState(splashState); +//! [10] +//! [11] // Transitions QEventTransition *anyKeyTransition = new QEventTransition(this, QEvent::KeyPress, splashState); anyKeyTransition->setTargetState(frontState); anyKeyTransition->addAnimation(smoothSplashMove); anyKeyTransition->addAnimation(smoothSplashOpacity); +//! [11] - QKeyEventTransition *enterTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Enter, backState); +//! [12] + QKeyEventTransition *enterTransition = new QKeyEventTransition(this, QEvent::KeyPress, + Qt::Key_Enter, backState); + QKeyEventTransition *returnTransition = new QKeyEventTransition(this, QEvent::KeyPress, + Qt::Key_Return, backState); + QKeyEventTransition *backEnterTransition = new QKeyEventTransition(this, QEvent::KeyPress, + Qt::Key_Enter, frontState); + QKeyEventTransition *backReturnTransition = new QKeyEventTransition(this, QEvent::KeyPress, + Qt::Key_Return, frontState); enterTransition->setTargetState(historyState); - QKeyEventTransition *returnTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Return, backState); returnTransition->setTargetState(historyState); - QKeyEventTransition *backEnterTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Enter, frontState); backEnterTransition->setTargetState(backState); - QKeyEventTransition *backReturnTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Return, frontState); backReturnTransition->setTargetState(backState); enterTransition->addAnimation(flipAnimation); returnTransition->addAnimation(flipAnimation); backEnterTransition->addAnimation(flipAnimation); backReturnTransition->addAnimation(flipAnimation); +//! [12] - // Substates, one for each icon +//! [13] + // Create substates for each icon; store in temporary grid. int columns = size.width(); int rows = size.height(); QVector< QVector< QState * > > stateGrid; stateGrid.resize(rows); for (int y = 0; y < rows; ++y) { stateGrid[y].resize(columns); - for (int x = 0; x < columns; ++x) { - QState *state = new QState(frontState); - stateGrid[y][x] = state; - } + for (int x = 0; x < columns; ++x) + stateGrid[y][x] = new QState(frontState); } frontState->setInitialState(stateGrid[0][0]); selectionItem->setPos(pad->iconAt(0, 0)->pos()); +//! [13] +//! [14] // Enable key navigation using state transitions for (int y = 0; y < rows; ++y) { for (int x = 0; x < columns; ++x) { QState *state = stateGrid[y][x]; - QKeyEventTransition *rightTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Right, state); + QKeyEventTransition *rightTransition = new QKeyEventTransition(this, QEvent::KeyPress, + Qt::Key_Right, state); + QKeyEventTransition *leftTransition = new QKeyEventTransition(this, QEvent::KeyPress, + Qt::Key_Left, state); + QKeyEventTransition *downTransition = new QKeyEventTransition(this, QEvent::KeyPress, + Qt::Key_Down, state); + QKeyEventTransition *upTransition = new QKeyEventTransition(this, QEvent::KeyPress, + Qt::Key_Up, state); rightTransition->setTargetState(stateGrid[y][(x + 1) % columns]); - QKeyEventTransition *leftTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Left, state); leftTransition->setTargetState(stateGrid[y][((x - 1) + columns) % columns]); - QKeyEventTransition *downTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Down, state); downTransition->setTargetState(stateGrid[(y + 1) % rows][x]); - QKeyEventTransition *upTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Up, state); upTransition->setTargetState(stateGrid[((y - 1) + rows) % rows][x]); - +//! [14] +//! [15] RoundRectItem *icon = pad->iconAt(x, y); state->assignProperty(xRotation, "angle", -icon->x() / 6.0); state->assignProperty(yRotation, "angle", icon->y() / 6.0); @@ -219,47 +257,51 @@ PadNavigator::PadNavigator(const QSize &size, QWidget *parent) frontState->assignProperty(icon, "visible", true); backState->assignProperty(icon, "visible", false); - QPropertyAnimation *setVisibleAnim = new QPropertyAnimation(icon, "visible"); - setVisibleAnim->setDuration(0); - setVisibleAnimation->addAnimation(setVisibleAnim); + QPropertyAnimation *setIconVisibleAnimation = new QPropertyAnimation(icon, "visible"); + setIconVisibleAnimation->setDuration(0); + setVariablesSequence->addAnimation(setIconVisibleAnimation); } } +//! [15] - // Setup scene +//! [16] + // Scene QGraphicsScene *scene = new QGraphicsScene(this); scene->setBackgroundBrush(QPixmap(":/images/blue_angle_swirl.jpg")); scene->setItemIndexMethod(QGraphicsScene::NoIndex); scene->addItem(pad); scene->setSceneRect(scene->itemsBoundingRect()); setScene(scene); +//! [16] - // Adjust splash item - splash->setPos(-splash->boundingRect().width() / 2, scene->sceneRect().top()); +//! [17] + // Adjust splash item to scene contents + const QRectF sbr = splash->boundingRect(); + splash->setPos(-sbr.width() / 2, scene->sceneRect().top() - 2); frontState->assignProperty(splash, "y", splash->y() - 100.0); scene->addItem(splash); +//! [17] - // Setup view +//! [18] + // View setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setMinimumSize(50, 50); setViewportUpdateMode(FullViewportUpdate); setCacheMode(CacheBackground); - setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform - | QPainter::TextAntialiasing); + setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing); #ifndef QT_NO_OPENGL setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); #endif stateMachine->start(); +//! [18] } -PadNavigator::~PadNavigator() -{ - delete form; -} - +//! [19] void PadNavigator::resizeEvent(QResizeEvent *event) { QGraphicsView::resizeEvent(event); fitInView(scene()->sceneRect(), Qt::KeepAspectRatio); } +//! [19] diff --git a/examples/graphicsview/padnavigator/padnavigator.h b/examples/graphicsview/padnavigator/padnavigator.h index c79a13c..03a1ea2 100644 --- a/examples/graphicsview/padnavigator/padnavigator.h +++ b/examples/graphicsview/padnavigator/padnavigator.h @@ -43,23 +43,25 @@ #define PADNAVIGATOR_H #include +#include "ui_form.h" class QState; class QStateMachine; class Ui_Form; +//! [0] class PadNavigator : public QGraphicsView { Q_OBJECT public: explicit PadNavigator(const QSize &size, QWidget *parent = 0); - ~PadNavigator(); protected: void resizeEvent(QResizeEvent *event); private: - Ui_Form *form; + Ui_Form form; }; +//! [0] #endif // PADNAVIGATOR_H diff --git a/examples/graphicsview/padnavigator/roundrectitem.cpp b/examples/graphicsview/padnavigator/roundrectitem.cpp index 2141e9a..7a0b279 100644 --- a/examples/graphicsview/padnavigator/roundrectitem.cpp +++ b/examples/graphicsview/padnavigator/roundrectitem.cpp @@ -43,34 +43,39 @@ #include +//! [0] RoundRectItem::RoundRectItem(const QRectF &bounds, const QColor &color, QGraphicsItem *parent) - : QGraphicsObject(parent), fillRect(false), color(color), bounds(bounds) + : QGraphicsObject(parent), fillRect(false), bounds(bounds) { gradient.setStart(bounds.topLeft()); gradient.setFinalStop(bounds.bottomRight()); gradient.setColorAt(0, color); gradient.setColorAt(1, color.dark(200)); - setCacheMode(ItemCoordinateCache); } +//! [0] +//! [1] QPixmap RoundRectItem::pixmap() const { return pix; } - void RoundRectItem::setPixmap(const QPixmap &pixmap) { pix = pixmap; update(); } +//! [1] +//! [2] QRectF RoundRectItem::boundingRect() const { return bounds.adjusted(0, 0, 2, 2); } +//! [2] +//! [3] void RoundRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { @@ -79,25 +84,31 @@ void RoundRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt painter->setPen(Qt::NoPen); painter->setBrush(QColor(0, 0, 0, 64)); painter->drawRoundRect(bounds.translated(2, 2)); +//! [3] +//! [4] if (fillRect) painter->setBrush(QApplication::palette().brush(QPalette::Window)); else painter->setBrush(gradient); painter->setPen(QPen(Qt::black, 1)); painter->drawRoundRect(bounds); +//! [4] +//! [5] if (!pix.isNull()) { painter->scale(1.95, 1.95); painter->drawPixmap(-pix.width() / 2, -pix.height() / 2, pix); } } +//! [5] +//! [6] bool RoundRectItem::fill() const { return fillRect; } - void RoundRectItem::setFill(bool fill) { fillRect = fill; update(); } +//! [6] diff --git a/examples/graphicsview/padnavigator/roundrectitem.h b/examples/graphicsview/padnavigator/roundrectitem.h index ae5fb4c..bc58cec 100644 --- a/examples/graphicsview/padnavigator/roundrectitem.h +++ b/examples/graphicsview/padnavigator/roundrectitem.h @@ -45,6 +45,7 @@ #include #include +//! [0] class RoundRectItem : public QGraphicsObject { Q_OBJECT @@ -61,13 +62,15 @@ public: bool fill() const; void setFill(bool fill); +//! [0] +//! [1] private: QPixmap pix; bool fillRect; - QColor color; QRectF bounds; QLinearGradient gradient; }; +//! [1] #endif // ROUNDRECTITEM_H diff --git a/examples/graphicsview/padnavigator/splashitem.cpp b/examples/graphicsview/padnavigator/splashitem.cpp index e609656..cd7074a 100644 --- a/examples/graphicsview/padnavigator/splashitem.cpp +++ b/examples/graphicsview/padnavigator/splashitem.cpp @@ -43,20 +43,25 @@ #include -SplashItem::SplashItem(QGraphicsItem *parent) : - QGraphicsObject(parent) +//! [0] +SplashItem::SplashItem(QGraphicsItem *parent) + : QGraphicsObject(parent) { text = tr("Welcome to the Pad Navigator Example. You can use the" " keyboard arrows to navigate the icons, and press enter" " to activate an item. Press any key to begin."); setCacheMode(DeviceCoordinateCache); } +//! [0] +//! [1] QRectF SplashItem::boundingRect() const { return QRectF(0, 0, 400, 175); } +//! [1] +//! [2] void SplashItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { @@ -76,3 +81,4 @@ void SplashItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option painter->setFont(font); painter->drawText(textRect, flags, text); } +//! [2] diff --git a/examples/graphicsview/padnavigator/splashitem.h b/examples/graphicsview/padnavigator/splashitem.h index 9d57653..98c4a1f 100644 --- a/examples/graphicsview/padnavigator/splashitem.h +++ b/examples/graphicsview/padnavigator/splashitem.h @@ -44,6 +44,7 @@ #include +//! [0] class SplashItem : public QGraphicsObject { Q_OBJECT @@ -56,5 +57,6 @@ public: private: QString text; }; +//! [0] #endif // SPLASHITEM_H -- cgit v0.12 From 0fd9d9ca457aa3e400188214f79830cd853e6348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Wed, 12 May 2010 17:10:58 +0200 Subject: Remove an unnecessary assert. Reviewed-by: Kim --- src/opengl/qgl.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index a3c1bac..7c457de 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1723,7 +1723,6 @@ QGLTextureCache::QGLTextureCache() QGLTextureCache::~QGLTextureCache() { - Q_ASSERT(size() == 0); QImagePixmapCleanupHooks::instance()->removePixmapDataModificationHook(cleanupTexturesForPixampData); QImagePixmapCleanupHooks::instance()->removePixmapDataDestructionHook(cleanupBeforePixmapDestruction); QImagePixmapCleanupHooks::instance()->removeImageHook(cleanupTexturesForCacheKey); @@ -2888,7 +2887,7 @@ void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum text glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_WIDTH, &textureWidth); glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_HEIGHT, &textureHeight); - if (d_ptr->active_engine && + if (d_ptr->active_engine && d_ptr->active_engine->type() == QPaintEngine::OpenGL2) { QGL2PaintEngineEx *eng = static_cast(d_ptr->active_engine); if (!eng->isNativePaintingActive()) { -- cgit v0.12 From 770a2428357f030d4efad8c64ceb381ce50c9fb9 Mon Sep 17 00:00:00 2001 From: Kim Motoyoshi Kalland Date: Wed, 12 May 2010 17:36:04 +0200 Subject: Compile fix on Windows. Reviewed-by: Trond --- src/gui/painting/qstroker_p.h | 2 +- src/gui/painting/qtransform.cpp | 2 +- src/opengl/qpaintengine_opengl.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qstroker_p.h b/src/gui/painting/qstroker_p.h index 0f133ef..d646135 100644 --- a/src/gui/painting/qstroker_p.h +++ b/src/gui/painting/qstroker_p.h @@ -125,7 +125,7 @@ typedef void (*qStrokerCubicToHook)(qfixed c1x, qfixed c1y, void *data); // qtransform.cpp -extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); +Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); class Q_GUI_EXPORT QStrokerOps { diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index c72a08e..aaa241f 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1545,7 +1545,7 @@ static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transfor return true; } -bool qt_scaleForTransform(const QTransform &transform, qreal *scale); +Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); static inline bool cubicTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, bool needsMoveTo) { diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index d2b0d4f..08a50cb 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -3950,7 +3950,7 @@ void QOpenGLPaintEnginePrivate::strokeLines(const QPainterPath &path) enableClipping(); } -extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp +Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp void QOpenGLPaintEnginePrivate::strokePath(const QPainterPath &path, bool use_cache) { -- cgit v0.12