src/hbcore/primitives/hbmarqueeitem.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
equal deleted inserted replaced
-1:000000000000 0:16d8024aca5e
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (developer.feedback@nokia.com)
       
     6 **
       
     7 ** This file is part of the HbCore module of the UI Extensions for Mobile.
       
     8 **
       
     9 ** GNU Lesser General Public License Usage
       
    10 ** This file may be used under the terms of the GNU Lesser General Public
       
    11 ** License version 2.1 as published by the Free Software Foundation and
       
    12 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
       
    13 ** Please review the following information to ensure the GNU Lesser General
       
    14 ** Public License version 2.1 requirements will be met:
       
    15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    16 **
       
    17 ** In addition, as a special exception, Nokia gives you certain additional
       
    18 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    20 **
       
    21 ** If you have questions regarding the use of this file, please contact
       
    22 ** Nokia at developer.feedback@nokia.com.
       
    23 **
       
    24 ****************************************************************************/
       
    25 #include "hbmarqueeitem.h"
       
    26 #include "hbmarqueeitem_p.h"
       
    27 #include "hbwidgetbase_p.h"
       
    28 #include "hbtextutils_p.h"
       
    29 #include "hbevent.h"
       
    30 
       
    31 #ifdef HB_TEXT_MEASUREMENT_UTILITY
       
    32 #include "hbtextmeasurementutility_p.h"
       
    33 #include "hbfeaturemanager_p.h"
       
    34 #endif //HB_TEXT_MEASUREMENT_UTILITY
       
    35 
       
    36 #include "hbdeviceprofile.h"
       
    37 #include "hbcolorscheme.h"
       
    38 #include "hbnamespace_p.h"
       
    39 
       
    40 #include <qmath.h>
       
    41 #include <QPainter>
       
    42 #include <QPropertyAnimation>
       
    43 
       
    44 //#define HB_DEBUG_MARQUEE_DRAW_RECTS
       
    45 
       
    46 namespace {
       
    47     // The bigger the value the slower the animation
       
    48     static const qreal ANIMATION_SPEED_FACTOR = 2.5;
       
    49     static const int ANIMATION_LEAD_TIME = 500;
       
    50     static const int ANIMATION_IDENT_BY_PIXEL = 5;
       
    51 
       
    52     static const QString DEFAULT_COLORGROUP = "qtc_view_normal";
       
    53 }
       
    54 
       
    55 
       
    56 
       
    57 HbMarqueeContent::HbMarqueeContent(HbMarqueeItem *parent) :
       
    58     QGraphicsObject(parent),
       
    59     parent(parent),
       
    60     mTextDirection(Qt::LeftToRight),
       
    61     mTextWidth(0),
       
    62     mAlpha(0),
       
    63     mFadeLength(0)
       
    64 {
       
    65     setCacheMode(QGraphicsItem::DeviceCoordinateCache);
       
    66 }
       
    67 
       
    68 
       
    69 QRectF HbMarqueeContent::boundingRect() const
       
    70 {
       
    71     return mBoundingRect;
       
    72 }
       
    73 
       
    74 QPen HbMarqueeContent::pen()
       
    75 {
       
    76     QColor fullColor = parent->textColor();
       
    77     QPen pen(fullColor);
       
    78 
       
    79     if(parent->contentsRect().width() < mTextWidth) {
       
    80         QColor fadeColor = fullColor;
       
    81         fadeColor.setAlpha(alpha());
       
    82 
       
    83         QLinearGradient gradient;
       
    84         gradient.setColorAt(0.0,fullColor);
       
    85         gradient.setColorAt(1.0,fadeColor);
       
    86 
       
    87         gradient.setStart(gradientStart);
       
    88         gradient.setFinalStop(gradientStop);
       
    89         pen.setBrush(QBrush(gradient));
       
    90     }
       
    91     return pen;
       
    92 }
       
    93 
       
    94 void HbMarqueeContent::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
       
    95 {
       
    96     Q_UNUSED(option);
       
    97     Q_UNUSED(widget);
       
    98 
       
    99     painter->setPen(pen());
       
   100 
       
   101     Qt::LayoutDirection direction = painter->layoutDirection();
       
   102     painter->setLayoutDirection ( mTextDirection );
       
   103     painter->setFont(parent->font());
       
   104     painter->drawText(boundingRect(), Qt::TextDontClip, mText);
       
   105 
       
   106 #ifdef HB_DEBUG_MARQUEE_DRAW_RECTS
       
   107     painter->setPen(Qt::green);
       
   108     painter->drawRect(boundingRect());
       
   109     painter->setOpacity(0.3);
       
   110 #endif
       
   111     painter->setLayoutDirection ( direction );
       
   112 }
       
   113 
       
   114 
       
   115 void HbMarqueeContent::updateTextMetaData()
       
   116 {
       
   117     QFontMetricsF metrics(parent->font());
       
   118 
       
   119     //calculate bounding rect
       
   120     prepareGeometryChange();
       
   121 
       
   122     mBoundingRect = metrics.boundingRect(mText);
       
   123     mBoundingRect.moveTopLeft(QPointF(0,0));
       
   124 
       
   125     // text direction
       
   126     bool rightToLeft = HbTextUtils::ImplicitDirectionalityIsRightToLeft(
       
   127         mText.utf16(), mText.length(), 0 );
       
   128     mTextDirection = rightToLeft ? Qt::RightToLeft : Qt::LeftToRight;
       
   129 
       
   130     // Update text width
       
   131     mTextWidth = mBoundingRect.width();
       
   132 
       
   133     // Update fade length from device profile
       
   134     mFadeLength = HbDeviceProfile::profile(this).unitValue()*HbPrivate::TextTruncationFadeWidth;
       
   135 
       
   136 }
       
   137 
       
   138 
       
   139 void HbMarqueeContent::setAlpha(int alpha)
       
   140 {
       
   141     mAlpha = alpha;
       
   142     update();
       
   143 }
       
   144 
       
   145 int HbMarqueeContent::alpha() const
       
   146 {
       
   147     return mAlpha;
       
   148 }
       
   149 
       
   150 HbMarqueeItemPrivate::HbMarqueeItemPrivate() :
       
   151     content(0),
       
   152     mAnimationPending(false)
       
   153     
       
   154 {
       
   155 }
       
   156 
       
   157 void HbMarqueeItemPrivate::init()
       
   158 {
       
   159     Q_Q(HbMarqueeItem);
       
   160     content = new HbMarqueeContent(q);
       
   161 
       
   162     q->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
       
   163     QObject::connect(&mAnimGroup, SIGNAL(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State)) ,q,SLOT(_q_stateChanged()));
       
   164 
       
   165 #ifdef HB_TEXT_MEASUREMENT_UTILITY
       
   166     if ( HbFeatureManager::instance()->featureStatus( HbFeatureManager::TextMeasurement ) ) {
       
   167         q->setProperty( HbTextMeasurementUtilityNameSpace::textMaxLines, 1 );
       
   168     }
       
   169 #endif
       
   170 }
       
   171 
       
   172 
       
   173 void HbMarqueeItemPrivate::updateTextMetaData()
       
   174 {
       
   175     Q_Q(HbMarqueeItem);
       
   176 
       
   177     q->update();
       
   178     q->updateGeometry();
       
   179     content->updateTextMetaData();
       
   180     initContentPosition();
       
   181     initAnimations();
       
   182     content->update();
       
   183 }
       
   184 
       
   185 /*
       
   186   Initializes the position of the text so that it can be drawn to the screen
       
   187   in the initial position, either elided or not
       
   188 */
       
   189 void HbMarqueeItemPrivate::initContentPosition()
       
   190 {
       
   191     Q_Q(HbMarqueeItem);
       
   192 
       
   193     QRectF contentRect = content->boundingRect();
       
   194     QRectF rect = q->contentsRect();
       
   195     contentRect.moveCenter(rect.center());
       
   196 
       
   197     if (q->layoutDirection() == Qt::RightToLeft) {
       
   198         contentRect.moveRight(rect.right());
       
   199     } else {
       
   200         contentRect.moveLeft(rect.left());
       
   201     }
       
   202 
       
   203     if(rect.width() < content->mTextWidth) {
       
   204         if (content->mTextDirection == Qt::RightToLeft) {
       
   205             contentRect.moveRight(rect.right());
       
   206 
       
   207         } else {
       
   208             contentRect.moveLeft(rect.left());
       
   209         }
       
   210     }
       
   211     content->setPos(contentRect.topLeft());
       
   212 
       
   213     // Calculate the gradient point only after the content was positioned
       
   214     initGradient();
       
   215 
       
   216 }
       
   217 
       
   218 void HbMarqueeItemPrivate::initGradient()
       
   219 {
       
   220     Q_Q(HbMarqueeItem);
       
   221     QRectF rect = q->contentsRect();
       
   222 
       
   223     if(rect.width() < content->mTextWidth) {
       
   224         if (content->mTextDirection == Qt::RightToLeft) {
       
   225             content->gradientStop = q->mapToItem(content, rect.topRight());
       
   226             content->gradientStop.rx() -= rect.width();
       
   227             content->gradientStart = content->gradientStop;
       
   228             content->gradientStart.rx() += content->mFadeLength;
       
   229 
       
   230         } else {
       
   231             content->gradientStop = q->mapToItem(content,rect.topLeft());
       
   232             content->gradientStop.rx() += rect.width();
       
   233             content->gradientStart = content->gradientStop;
       
   234             content->gradientStart.rx() -= content->mFadeLength;
       
   235         }
       
   236         content->setAlpha(0);
       
   237     }
       
   238 }
       
   239 
       
   240 void HbMarqueeItemPrivate::initAnimations()
       
   241 {
       
   242     Q_Q(HbMarqueeItem);
       
   243 
       
   244     bool oldAnimationPending = mAnimationPending;
       
   245     mAnimGroup.clear();
       
   246     mAnimationPending = oldAnimationPending;
       
   247 
       
   248     if (q->contentsRect().width() < content->mTextWidth) {
       
   249 
       
   250         // get pixel per millimeter value to ensure same animation speed on each device
       
   251         qreal ppmValue = HbDeviceProfile::profile(q).ppmValue();
       
   252 
       
   253         // Calculate the offset for scrolling
       
   254         qreal scrollOffsetX = content->mTextWidth+ANIMATION_IDENT_BY_PIXEL - q->contentsRect().width();
       
   255 
       
   256         // animation duration depends on the length of the scrolled text and is not linear
       
   257         int duration = (int)((qSqrt(scrollOffsetX)*1000*ANIMATION_SPEED_FACTOR)/ppmValue);
       
   258 
       
   259         if (content->mTextDirection != Qt::LeftToRight) {
       
   260             scrollOffsetX = -scrollOffsetX;
       
   261         }
       
   262 
       
   263         QPointF scrolledOutPos(content->pos().x() - scrollOffsetX, content->pos().y());
       
   264 
       
   265         mAnimGroup.addPause(ANIMATION_LEAD_TIME);
       
   266 
       
   267         QPropertyAnimation *anim = 0;
       
   268 
       
   269         anim = new QPropertyAnimation;
       
   270         anim->setEasingCurve(QEasingCurve::Linear);
       
   271         anim->setTargetObject(content);
       
   272         anim->setPropertyName("alpha");
       
   273         anim->setStartValue(0);
       
   274         anim->setEndValue(0xFF);
       
   275         anim->setDuration(1000);
       
   276         mAnimGroup.addAnimation(anim);
       
   277 
       
   278         anim = new QPropertyAnimation;
       
   279         anim->setEasingCurve(QEasingCurve::SineCurve);
       
   280         anim->setTargetObject(content);
       
   281         anim->setPropertyName("pos");
       
   282         anim->setStartValue(content->pos());
       
   283         anim->setEndValue(scrolledOutPos);
       
   284         anim->setDuration(duration);
       
   285         mAnimGroup.addAnimation(anim);
       
   286 
       
   287         anim = new QPropertyAnimation;
       
   288         anim->setEasingCurve(QEasingCurve::Linear);
       
   289         anim->setTargetObject(content);
       
   290         anim->setPropertyName("alpha");
       
   291         anim->setEndValue(0);
       
   292         anim->setDuration(1000);
       
   293         mAnimGroup.addAnimation(anim);
       
   294 
       
   295         if(mAnimationPending) {
       
   296             q->startAnimation();
       
   297         }
       
   298     }
       
   299 }
       
   300 
       
   301 
       
   302 void HbMarqueeItemPrivate::_q_stateChanged()
       
   303 {
       
   304     Q_Q(HbMarqueeItem);
       
   305     if (mAnimGroup.state() == QAbstractAnimation::Running) {
       
   306         emit q->animationStarted();
       
   307     } else if (mAnimGroup.state() == QAbstractAnimation::Stopped) {
       
   308         initContentPosition();
       
   309         mAnimationPending = false;
       
   310         emit q->animationStopped();
       
   311     } else {
       
   312         // Other states are irrelevant
       
   313     }
       
   314 }
       
   315 
       
   316 /*!
       
   317   @alpha
       
   318   @hbcore
       
   319  \class HbMarqueeItem
       
   320  \brief HbMarqueeItem is a lightweight item for showing a single line marqueed text.
       
   321 
       
   322 
       
   323  This is mainly used as a primitive in widgets.
       
   324  It derives from HbWidgetBase so it can be layouted.
       
   325 
       
   326  */
       
   327 
       
   328 /*!
       
   329  Constructor for the class.
       
   330  */
       
   331 
       
   332 HbMarqueeItem::HbMarqueeItem(QGraphicsItem *parent) :
       
   333     HbWidgetBase(*new HbMarqueeItemPrivate, parent)
       
   334 {
       
   335     Q_D(HbMarqueeItem);
       
   336     d->init();
       
   337 }
       
   338 
       
   339 /*!
       
   340  Text can be set with \a text attribute.
       
   341  */
       
   342 HbMarqueeItem::HbMarqueeItem(const QString &text, QGraphicsItem *parent) :
       
   343     HbWidgetBase(*new HbMarqueeItemPrivate, parent)
       
   344 {
       
   345     Q_D(HbMarqueeItem);
       
   346     d->init();
       
   347     setText(text);
       
   348 }
       
   349 
       
   350 HbMarqueeItem::HbMarqueeItem(HbMarqueeItemPrivate &dd, QGraphicsItem *parent) :
       
   351     HbWidgetBase(dd, parent)
       
   352 {
       
   353     Q_D(HbMarqueeItem);
       
   354     d->init();
       
   355 }
       
   356 
       
   357 /*!
       
   358     Destructor for the class.
       
   359  */
       
   360 HbMarqueeItem::~HbMarqueeItem()
       
   361 {
       
   362 
       
   363 }
       
   364 
       
   365 /*!
       
   366     Returns the text
       
   367 
       
   368     \sa HbMarqueeItem::setText()
       
   369  */
       
   370 QString HbMarqueeItem::text () const
       
   371 {
       
   372     Q_D( const HbMarqueeItem );
       
   373     return d->content->mText;
       
   374 }
       
   375 
       
   376 
       
   377 /*!
       
   378     Sets the text into \a text.
       
   379  */
       
   380 void HbMarqueeItem::setText(const QString &text)
       
   381 {
       
   382     Q_D(HbMarqueeItem);
       
   383 
       
   384     QString txt(text);
       
   385 
       
   386 #ifdef HB_TEXT_MEASUREMENT_UTILITY
       
   387     if (HbFeatureManager::instance()->featureStatus(HbFeatureManager::TextMeasurement)) {
       
   388         if (text.endsWith(QChar(LOC_TEST_END))) {
       
   389             int index = text.indexOf(QChar(LOC_TEST_START));
       
   390             setProperty(HbTextMeasurementUtilityNameSpace::textIdPropertyName, 
       
   391                 text.mid(index + 1, text.indexOf(QChar(LOC_TEST_END)) - index - 1));
       
   392             //setProperty( HbTextMeasurementUtilityNameSpace::textMaxLines, 1);
       
   393             txt = text.left(index);
       
   394         } else {
       
   395             setProperty(HbTextMeasurementUtilityNameSpace::textIdPropertyName,  QVariant::Invalid);
       
   396         }
       
   397     }
       
   398 #endif // HB_TEXT_MEASUREMENT_UTILITY
       
   399 
       
   400     if (d->content->mText != txt) {
       
   401         d->content->mText = txt;
       
   402         d->updateTextMetaData();
       
   403         d->content->update();
       
   404     }
       
   405 }
       
   406 
       
   407 /*!
       
   408     Returns if the text is currently animating.
       
   409  */
       
   410 bool HbMarqueeItem::isAnimating() const
       
   411 {
       
   412     Q_D(const HbMarqueeItem);
       
   413     return (d->mAnimGroup.state()==QAbstractAnimation::Running);
       
   414 }
       
   415 
       
   416 /*!
       
   417     Starts or restarts the animation of the text.
       
   418  */
       
   419 void HbMarqueeItem::startAnimation()
       
   420 {
       
   421     Q_D(HbMarqueeItem);
       
   422     if (isVisible()) {
       
   423         d->mAnimGroup.start();
       
   424     }
       
   425     d->mAnimationPending = true;
       
   426 }
       
   427 
       
   428 /*!
       
   429     Stops the animation of the text if it is ongoing.
       
   430  */
       
   431 void HbMarqueeItem::stopAnimation()
       
   432 {
       
   433     Q_D(HbMarqueeItem);
       
   434     d->mAnimGroup.stop();
       
   435 }
       
   436 
       
   437 /*!
       
   438     Returns the loop count of the animation.
       
   439 
       
   440     \sa setLoopCount
       
   441  */
       
   442 int HbMarqueeItem::loopCount() const
       
   443 {
       
   444     Q_D(const HbMarqueeItem);
       
   445     return d->mAnimGroup.loopCount();
       
   446 }
       
   447 
       
   448 /*!
       
   449     Sets the loop count of the animation.
       
   450     The loop count determines how many times the animation is repeated
       
   451     after the animation started.
       
   452     Default value: 1
       
   453     Value -1 makes the animation continues and only stops when stopAnimation is called
       
   454 
       
   455     \sa loopCount
       
   456  */
       
   457 void HbMarqueeItem::setLoopCount(int count)
       
   458 {
       
   459     Q_D(HbMarqueeItem);
       
   460     d->mAnimGroup.setLoopCount(count);
       
   461 }
       
   462 
       
   463 /*!
       
   464     \reimp
       
   465  */
       
   466 QSizeF HbMarqueeItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
       
   467 {
       
   468     Q_D(const HbMarqueeItem);
       
   469 
       
   470     QSizeF size;
       
   471 
       
   472     switch(which) {
       
   473     case Qt::MinimumSize: {
       
   474             if (d->content->mText.isEmpty()) {
       
   475                 return QSizeF(0.f, 0.f);
       
   476             }
       
   477 
       
   478             size = d->content->boundingRect().size();
       
   479             size.setWidth(qMin( size.width() , size.height()));
       
   480             size.setHeight(size.height());
       
   481 
       
   482             break;
       
   483         }
       
   484 
       
   485     case Qt::PreferredSize: {
       
   486             size = d->content->boundingRect().size();
       
   487             break;
       
   488         }
       
   489 
       
   490     default:
       
   491         size = HbWidgetBase::sizeHint(which, constraint);
       
   492     }
       
   493 
       
   494     return size;
       
   495 }
       
   496 
       
   497 
       
   498  /*!
       
   499     \reimp
       
   500  */
       
   501 void HbMarqueeItem::changeEvent(QEvent *event)
       
   502 {
       
   503     Q_D(HbMarqueeItem);
       
   504 
       
   505     if(event->type() == HbEvent::FontChange ||
       
   506        event->type() == HbEvent::LayoutDirectionChange) {
       
   507         d->updateTextMetaData();
       
   508     }
       
   509     if (event->type() == HbEvent::ThemeChanged) {
       
   510         d->mDefaultColor = QColor();
       
   511         if(!d->mColor.isValid()) {
       
   512            update();
       
   513            d->content->update();
       
   514         }
       
   515     }
       
   516     HbWidgetBase::changeEvent(event);
       
   517 }
       
   518 
       
   519 /*!
       
   520     \reimp
       
   521  */
       
   522 void HbMarqueeItem::resizeEvent(QGraphicsSceneResizeEvent *event)
       
   523 {
       
   524     Q_D(HbMarqueeItem);
       
   525     HbWidgetBase::resizeEvent(event);
       
   526     d->updateTextMetaData();
       
   527 }
       
   528 
       
   529 
       
   530 /*!
       
   531     \reimp
       
   532  */
       
   533 QVariant HbMarqueeItem::itemChange(GraphicsItemChange change, const QVariant &value)
       
   534 {
       
   535     Q_D(HbMarqueeItem);
       
   536 
       
   537     if (change == QGraphicsItem::ItemVisibleHasChanged) {
       
   538         if (!value.toBool()) {
       
   539             bool oldAnimationPending = d->mAnimationPending;
       
   540             stopAnimation();
       
   541             d->mAnimationPending = oldAnimationPending;
       
   542         } else if (d->mAnimationPending) {
       
   543             startAnimation();
       
   544         }
       
   545     }
       
   546     return HbWidgetBase::itemChange(change, value);
       
   547 }
       
   548 
       
   549 /*!
       
   550     Sets the text color into \a color.
       
   551     If invalid color is used color from theme will be used.
       
   552 
       
   553     \sa HbTextItem::textColor()
       
   554  */
       
   555 void HbMarqueeItem::setTextColor(const QColor &color)
       
   556 {
       
   557     Q_D(HbMarqueeItem);
       
   558     d->setApiProtectionFlag(HbWidgetBasePrivate::AC_TextColor, true);
       
   559     if (d->mColor != color) {
       
   560         d->mColor = color;
       
   561         update();
       
   562         d->content->update();
       
   563     }
       
   564 }
       
   565 
       
   566 /*!
       
   567     Returns the text color used for paiting text.
       
   568     If no color was set it returns color based on theme.
       
   569 
       
   570     \sa HbTextItem::setTextColor()
       
   571  */
       
   572 QColor HbMarqueeItem::textColor() const
       
   573 {
       
   574     Q_D( const HbMarqueeItem );
       
   575 
       
   576     if (d->mColor.isValid()) { // Means user has set text color
       
   577         return d->mColor;
       
   578     }
       
   579     if (!d->mDefaultColor.isValid()) {
       
   580         d->mDefaultColor = HbColorScheme::color(DEFAULT_COLORGROUP);
       
   581     }
       
   582     return d->mDefaultColor;
       
   583 }
       
   584 
       
   585 
       
   586 #include "moc_hbmarqueeitem.cpp"
       
   587 // end of file