diff options
author | Thomas Moenicke <thomas.moenicke@nokia.com> | 2010-07-19 13:18:24 +0300 |
---|---|---|
committer | Sergiy Dubovik <sergiy.dubovik@nokia.com> | 2010-07-27 14:04:49 +0300 |
commit | de592229dfc4a627e0d0ef328c56b108c1fc830c (patch) | |
tree | 9ba7715caeb5c743a7d74eecec04c9b44e4b84b7 | |
parent | 9bfb1a416a9a63bc1eb0c72f6b17bca4a9e84c15 (diff) |
Changes: improving progress bar speed using composition mode, using a mask image defined in SVG
RevBy: Sergiy
Details: see also meegotouch-theme changes
-rw-r--r-- | demos/widgetsgallery/progressbarpage.cpp | 4 | ||||
-rw-r--r-- | src/views/mprogressindicatorbarview.cpp | 235 | ||||
-rw-r--r-- | src/views/mprogressindicatorbarview_p.h | 31 | ||||
-rw-r--r-- | src/views/style/mprogressindicatorstyle.h | 18 |
4 files changed, 276 insertions, 12 deletions
diff --git a/demos/widgetsgallery/progressbarpage.cpp b/demos/widgetsgallery/progressbarpage.cpp index 347914df..de34b1e2 100644 --- a/demos/widgetsgallery/progressbarpage.cpp +++ b/demos/widgetsgallery/progressbarpage.cpp @@ -55,7 +55,7 @@ void ProgressBarPage::createContent() bar1 = new MProgressIndicator(centralWidget(), MProgressIndicator::barType); // Since range's type is int, we want a fairly large number here, to get a smooth animation - bar1->setRange(0, 99999); + bar1->setRange(0, 400); bar1->setValue(0); containerPolicy->addItem(bar1); @@ -72,7 +72,7 @@ void ProgressBarPage::createContent() animation->setLoopCount(-1); // start and end value should match bar1's range animation->setStartValue(0); - animation->setEndValue(99999); + animation->setEndValue(400); // 10 ms to fill the bar animation->setDuration(10000); animation->start(); diff --git a/src/views/mprogressindicatorbarview.cpp b/src/views/mprogressindicatorbarview.cpp index 5e4d5fdb..05a4006d 100644 --- a/src/views/mprogressindicatorbarview.cpp +++ b/src/views/mprogressindicatorbarview.cpp @@ -40,11 +40,15 @@ MProgressIndicatorBarViewPrivate::MProgressIndicatorBarViewPrivate() animation(0), width(0) { + backgroundPainter = new QPainter; + scalableBarImage = new MScalableImage; } MProgressIndicatorBarViewPrivate::~MProgressIndicatorBarViewPrivate() { + delete backgroundPainter; + delete scalableBarImage; } void MProgressIndicatorBarViewPrivate::setPosition(qreal pos) @@ -73,6 +77,57 @@ void MProgressIndicatorBarViewPrivate::animate(bool animate) } } +void MProgressIndicatorBarViewPrivate::createMaskOnGeometry() +{ + Q_Q(MProgressIndicatorBarView); + + const int height = q->rect().height(); + const QPoint topLeft(0,0); + QPainter p; + + /* + leftEnd barMask rightEnd + +-----+-------+---+--------+-----+ + | | |///| | | + | | |///| | | + | | |///| | | + +-----+-------+---+--------+-----+ + */ + + QPixmap canvas(q->rect().width(),height); + canvas.fill(Qt::transparent); + + leftEndMask = QPixmap(leftWidth,height); + leftEndMask.fill(Qt::transparent); + + rightEndMask = QPixmap(rightWidth,height); + rightEndMask.fill(Qt::transparent); + + // first scale up and draw the entire mask image + p.begin( &canvas ); + q->style()->maskImage()->draw(q->rect().toRect(), &p); + p.end(); + + // then cut out left end + p.begin(&leftEndMask); + p.drawPixmap( QRect(topLeft,leftEndMask.size()), canvas, QRect(topLeft,QSize(leftWidth,height)) ); + p.end(); + + // and cut out right end + p.begin(&rightEndMask); + p.drawPixmap( QRect(topLeft,rightEndMask.size()), canvas, QRect(QPoint(q->rect().toRect().width()-rightWidth,0),QSize(rightWidth,height)) ); + p.end(); + + barMask = QPixmap( QSize(q->style()->fillImage()->pixmap()->width(),height) ); + barMask.fill(Qt::transparent); + + // alpha blending is more correct in the middle + const QPoint centerTop( q->rect().center().x() - barMask.size().width()/2, q->rect().y() ); + p.begin(&barMask); + p.drawPixmap( QRect(QPoint(0,0),barMask.size()), canvas, QRect(centerTop, barMask.size()) ); + p.end(); +} + MProgressIndicatorBarView::MProgressIndicatorBarView(MProgressIndicator *controller) : MWidgetView(controller), d_ptr(new MProgressIndicatorBarViewPrivate) @@ -102,12 +157,46 @@ MProgressIndicatorBarView::~MProgressIndicatorBarView() delete d_ptr; } +void MProgressIndicatorBarViewPrivate::updateBarPosition() +{ + Q_Q(MProgressIndicatorBarView); + + bool reverse = qApp->isRightToLeft(); + QRect r(q->rect().toRect()); + const qreal offset = (qreal)(q->model()->value() - q->model()->minimum()) / (qreal)(q->model()->maximum() - q->model()->minimum()); + + if (offset > 0) { + if (!reverse) + r.moveRight(offset * r.width()); + else + r.moveLeft((1 - offset) * r.width()); + + if (q->style()->fillImage()) + backgroundPainter->drawPixmap( r,barBody ); + } +} + void MProgressIndicatorBarView::updateData(const QList<const char *>& modifications) { MWidgetView::updateData(modifications); Q_D(MProgressIndicatorBarView); + if(d->barBody.isNull()) { + d->figureOutSizes(); + d->createMaskOnGeometry(); + d->resetBarComposition(); + d->setupBarBody(); + } + + if( d->previousValue > model()->value() ) { + d->resetBarComposition(); + } + + d->previousValue = model()->value(); + + d->updateBarPosition(); + foreach(const char * member, modifications) { if (member == MProgressIndicatorModel::UnknownDuration) { if (model()->unknownDuration()) { @@ -132,6 +221,122 @@ void MProgressIndicatorBarView::setupModel() update(); } +void MProgressIndicatorBarViewPrivate::figureOutSizes() +{ + Q_Q(MProgressIndicatorBarView); + + q->style()->maskImage()->borders(&leftWidth,&rightWidth,&top,&bottom); + + rightEndRect = QRectF( QPointF(0.0,0.0), QSizeF( + rightWidth, + q->rect().height() ) ); + + leftEndRect = QRectF( QPointF(0.0,0.0), QSizeF( + leftWidth, + q->rect().height() ) ); +} + +void MProgressIndicatorBarViewPrivate::setupBarBody() +{ + Q_Q(MProgressIndicatorBarView); + + barBody = QPixmap( q->rect().size().toSize() ); + barBody.fill(Qt::transparent); + + q->style()->maskImage()->borders(&leftWidth,&rightWidth,&top,&bottom); + + // draw the mask + QPainter painter(&barBody); + painter.drawPixmap(q->rect().toRect(), barMask); + painter.end(); + + // paint the filling onto the mask, in slices + painter.begin(&barBody); + painter.setCompositionMode(QPainter::CompositionMode_SourceIn); + const QRect sourceRect( QPoint(0,0), q->style()->fillImage()->pixmap()->size() ); + const int step = sourceRect.width(); + for(int i=0;i<q->rect().width();i+=step) { + const QRectF nextRect(i,0,step,q->rect().height()); + if(q->style()->fillImageTiled()) + painter.drawTiledPixmap( nextRect, *q->style()->fillImage()->pixmap()); + else // stretched + painter.drawPixmap( nextRect, *q->style()->fillImage()->pixmap(), sourceRect); + } + painter.end(); + + // draw the right end + rightEndImage = QImage( rightEndRect.size().toSize(), QImage::Format_ARGB32 ); +qCritical() << q->style()->fillImageTiled(); + painter.begin(&rightEndImage); + if(q->style()->fillImageTiled()) + painter.drawTiledPixmap( rightEndRect.toRect(), *q->style()->fillImage()->pixmap() ); + else // stretched + q->style()->fillImage()->draw( rightEndRect.toRect(), &painter ); + painter.end(); + + painter.begin(&rightEndImage); + painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); + painter.drawPixmap( rightEndRect.toRect(), rightEndMask ); + painter.end(); + + rightEnd = QPixmap::fromImage( rightEndImage ); + + // draw the left end + leftEndImage = QImage( leftEndRect.size().toSize(), QImage::Format_ARGB32 ); + + painter.begin(&leftEndImage); + q->style()->fillImage()->draw( leftEndRect.toRect(), &painter ); + painter.end(); + + painter.begin(&leftEndImage); + painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); + painter.drawPixmap( leftEndRect.toRect(), leftEndMask ); + painter.end(); + + leftEnd = QPixmap::fromImage(leftEndImage); +} + +void MProgressIndicatorBarViewPrivate::compositeBarForUnknownDuration() +{ + Q_Q(MProgressIndicatorBarView); + + QPainter painter; + + const qreal bodyWidth = 100.0; + QRectF udLeftEndRect( QPointF(0,0), leftEndRect.size() ); + QRectF udBodyRect( udLeftEndRect.topRight(), QSizeF(bodyWidth, q->rect().height()) ); + QRectF udRightEndRect( udBodyRect.topRight(), rightEndRect.size() ); + + QRectF udBarRect( 0,0, leftWidth + bodyWidth + rightWidth, q->rect().height() ); + + QPixmap* activeImagePixmap = new QPixmap( udBarRect.size().toSize() ); + activeImagePixmap->fill(Qt::transparent); + + painter.begin(activeImagePixmap); + painter.drawImage( udLeftEndRect, leftEndImage ); + painter.drawPixmap( udBodyRect.toRect(), barBody ); + painter.drawImage( udRightEndRect, rightEndImage ); + painter.end(); + + scalableBarImage = new MScalableImage( activeImagePixmap, leftWidth, rightWidth, top, bottom ); +} + +void MProgressIndicatorBarViewPrivate::resetBarComposition() +{ + Q_Q(MProgressIndicatorBarView); + + if( backgroundPainter->isActive() ) + backgroundPainter->end(); + + barComposition = QPixmap(q->rect().size().toSize()); + barComposition.fill(Qt::transparent); + + if(backgroundPainter->begin(&barComposition)) { + q->style()->inactiveImage()->draw( q->rect().toRect(), backgroundPainter ); + backgroundPainter->setCompositionMode( QPainter::CompositionMode_SourceAtop ); + } +} + void MProgressIndicatorBarView::drawContents(QPainter *painter, const QStyleOptionGraphicsItem *option) const { Q_UNUSED(option); @@ -152,15 +357,17 @@ void MProgressIndicatorBarView::drawContents(QPainter *painter, const QStyleOpti qreal offset = (qreal)(model()->value() - model()->minimum()) / (qreal)(model()->maximum() - model()->minimum()); if (offset > 0) { if (!reverse) { - r.setRight(offset * r.width()); - if (r.width() < minimumScalableWidth) - r.setRight(r.left() + minimumScalableWidth); + r.moveRight(offset * r.width()); } else { - r.setLeft((1.0 - offset) * r.width()); - if (r.width() < minimumScalableWidth) - r.setLeft(r.right() - minimumScalableWidth); + r.moveLeft((1 - offset) * r.width()); + } + + if (style()->fillImage()) { + painter->drawPixmap( 0,0, d->barComposition ); + const int shift_left_to_avoid_flickering = 0; + const QRect rightEndRect(QPoint(r.topRight().x()-shift_left_to_avoid_flickering,0),d->rightEndRect.size().toSize()); + painter->drawPixmap( rightEndRect, d->rightEnd ); } - style()->activeImage()->draw(r, painter); } } else { qreal distance = d->position * (qreal) r.width(); @@ -179,9 +386,9 @@ void MProgressIndicatorBarView::drawContents(QPainter *painter, const QStyleOpti } if (r.width() >= minimumScalableWidth) - style()->activeImage()->draw(r, painter); + d->scalableBarImage->draw( r, painter ); if (r2.width() >= minimumScalableWidth) - style()->activeImage()->draw(r2, painter); + d->scalableBarImage->draw( r2, painter ); } else { // one draw call @@ -196,7 +403,7 @@ void MProgressIndicatorBarView::drawContents(QPainter *painter, const QStyleOpti if (r.width() < minimumScalableWidth) r.setLeft(r.right() - minimumScalableWidth); } - style()->activeImage()->draw(r, painter); + d->scalableBarImage->draw( r, painter ); } } } @@ -235,6 +442,14 @@ void MProgressIndicatorBarView::resizeEvent(QGraphicsSceneResizeEvent *event) d->width = rect().width(); d->animation->setDuration(d->width * 1000 / style()->speed()); } + + if(model()->unknownDuration()) { + d->figureOutSizes(); + d->createMaskOnGeometry(); + d->resetBarComposition(); + d->setupBarBody(); + d->compositeBarForUnknownDuration(); + } } // bind controller widget and view widget together by registration macro diff --git a/src/views/mprogressindicatorbarview_p.h b/src/views/mprogressindicatorbarview_p.h index 6739ab5a..cf0e8e13 100644 --- a/src/views/mprogressindicatorbarview_p.h +++ b/src/views/mprogressindicatorbarview_p.h @@ -33,6 +33,15 @@ class MProgressIndicatorBarViewPrivate : public QObject Q_OBJECT Q_DECLARE_PUBLIC(MProgressIndicatorBarView) + QImage leftEndImage; + QImage rightEndImage; + QPixmap rightEndMask; + QPixmap leftEndMask; + + QPixmap barMask; + + int leftWidth, rightWidth, top, bottom; + protected: MProgressIndicatorBarView *q_ptr; @@ -40,6 +49,14 @@ public: MProgressIndicatorBarViewPrivate(); ~MProgressIndicatorBarViewPrivate(); + void resetBarComposition(); + void setupBarBody(); + void updateBarPosition(); + void createMaskOnGeometry(); + + void compositeBarForUnknownDuration(); + void figureOutSizes(); + Q_PROPERTY(qreal position READ getPosition WRITE setPosition) qreal getPosition(); @@ -56,6 +73,20 @@ public: QPropertyAnimation *animation; int width; + QPixmap barBody; + + QPixmap rightEnd; + QPixmap leftEnd; + + QRectF rightEndRect; + QRectF leftEndRect; + + QPixmap barComposition; + QPainter* backgroundPainter; + int previousValue; + + MScalableImage* scalableBarImage; + #ifdef M_UNIT_TEST M_UNIT_TEST; #endif diff --git a/src/views/style/mprogressindicatorstyle.h b/src/views/style/mprogressindicatorstyle.h index 0c34a1ec..84dd0b1a 100644 --- a/src/views/style/mprogressindicatorstyle.h +++ b/src/views/style/mprogressindicatorstyle.h @@ -69,6 +69,24 @@ class M_EXPORT MProgressIndicatorStyle : public MWidgetStyle \brief Distance between circle elements as a multiplier to element size. */ M_STYLE_ATTRIBUTE(qreal, elementDistance, ElementDistance) + + /*! + \property MProgressIndicatorCandybarStyle::fillImage + \brief Mask for the progress image. + */ + M_STYLE_PTR_ATTRIBUTE(MScalableImage*, fillImage, FillImage) + + /*! + \property MProgressIndicator::maskImage + \brief mask of the progress image. + */ + M_STYLE_PTR_ATTRIBUTE(MScalableImage*, maskImage, MaskImage) + + /*! + \property MProgressIndicator::fillImageTiled + \brief stretched or tiled. + */ + M_STYLE_ATTRIBUTE(bool, fillImageTiled, FillImageTiled) }; /*! |