src/hbwidgets/sliders/hbratingslider.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 14 May 2010 16:09:54 +0300
changeset 2 06ff229162e9
parent 1 f7ac710697a9
child 3 11d3954df52a
permissions -rw-r--r--
Revision: 201017 Kit: 201019

/****************************************************************************
**
** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (developer.feedback@nokia.com)
**
** This file is part of the HbWidgets module of the UI Extensions for Mobile.
**
** GNU Lesser General Public License Usage
** 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 developer.feedback@nokia.com.
**
****************************************************************************/


#include <hbratingslider.h>
#include "hbratingslider_p.h"
#include <hbtooltip.h>
#include <hbstyleoptionratingslider_p.h>
#include <QGraphicsItem>
#include <QGraphicsSceneMouseEvent>
#include <hbtoucharea.h>

#ifdef HB_GESTURE_FW
#include <hbtapgesture.h>
#include <hbpangesture.h>
#endif 

#ifdef HB_EFFECTS
#include <hbeffect.h>
#include "hbeffectinternal_p.h"
#define HB_RATINGSLIDER_ITEM_TYPE "HB_RATINGSLIDER"

#endif
#define MAX_NUMBER_OF_ICONS 10

HbRatingSliderPrivate::HbRatingSliderPrivate():
    mMousePressed(false),
    mLookupValues(0),
    mReadOnly(false),
    mNumberOfIcons(5),
    mStepCount(5),
    mCurrentValue(0),
    mFrame(0),
    mTrack(0),
    mLayoutItem(0),
    mUnratedIconName(""),
    mTouchArea(0),
    mRatedIconName("")
{    
}

HbRatingSliderPrivate::~HbRatingSliderPrivate()
{
    if(mLookupValues) {
        delete [] mLookupValues;
    }
}


void HbRatingSliderPrivate::init()
{
    Q_Q(HbRatingSlider);
    mLayoutItem = q->style()->createPrimitive(HbStyle::P_RatingSlider_layout,q);
    mFrame = q->style()->createPrimitive(HbStyle::P_RatingSlider_frame,mLayoutItem);
    mTrack = q->style()->createPrimitive(HbStyle::P_RatingSlider_track,mFrame);
    mTouchArea = q->style()->createPrimitive(HbStyle::P_RatingSlider_toucharea, q);

    q->updatePrimitives();

    #ifdef HB_EFFECTS
    HbEffectInternal::add(HB_RATINGSLIDER_ITEM_TYPE,"ratingslider_appear", "ratingslider_appear");
    HbEffectInternal::add(HB_RATINGSLIDER_ITEM_TYPE,"ratingslider_disappear", "ratingslider_disappear");
    #endif

    #ifdef HB_GESTURE_FW
    q->grabGesture(Qt::TapGesture);
    q->grabGesture(Qt::PanGesture);

    if(QGraphicsObject *touchArea = mTouchArea->toGraphicsObject()) {
        touchArea->grabGesture(Qt::TapGesture);
        touchArea->grabGesture(Qt::PanGesture);
    }
    #endif 

}

void HbRatingSliderPrivate::createLookupTable()
{
    if(mLookupValues) {
        delete [] mLookupValues;
        mLookupValues=0;
    }
    
    mLookupValues = new int[mStepCount];
    qreal width = mFrame->boundingRect().width();
    int bandWidth =(int) (width/mStepCount);
        
    for(int i=0;i < mStepCount;i++) {
        mLookupValues[i] = bandWidth*(i+1);
    }
}

int HbRatingSliderPrivate::calculateProgressValue(qreal pos)
{
    Q_Q(HbRatingSlider);
    
    int count=0;
    for(count=0;count< mStepCount ;count++) {
        if(pos <= mLookupValues[count])
                break;
    }
    if(q->layoutDirection() == Qt::RightToLeft) {
        
        count = mStepCount -count;
    }
    else {
        
        count++;
    }

    if (pos > mLookupValues[mStepCount-1]) {
        return -1;
    }
    
    return count;
    
}

/*!
    \class HbRatingSlider
    \brief A control for user to do rating.

    This is a general rating widget where user will be able to do different 
    ratings for things like Music ,Video etc. 

    By default there are 5 ratings ( 5 stars ). This can be configured also.
    The interval , number of icons etc can be configured.

    Apart from rating the this can used for showing cumulative rating also.

    example code example:
    \code
    HbRatingSlider *object = new HbRatingSlider(parent);
    \endcode

    The below  code can be used to show some rating e.g. 2.5/5
    by default the  stepcount =5
    
    \code
    HbRatingSlider *slider = new HbRatingSlider();
    slider->setStepCount(100); //5 *20//
    slider->setCurrentRating(50); //2.5*20 it shows 50 / 100 which is same as 2.5/5
    \endcode
    
    This will show as 2.5/5. Now if one the same ratingslider 
    if the Application wants to configure a rating slider with range 1-5
    on emitting the signal rating changed it can set to 
    slider->setStepCount(5);
    slider->setCurrentRating(0)
    
    When the rating is done it emits a signal called ratingDone and when rating is 
    changed by the user by draging the pointer ratingChanged signal is emitted.   
    
 */



/*!
    @beta
    Constructor of  RatingSlider.
    \param parent. Parent widget

*/

HbRatingSlider::HbRatingSlider(QGraphicsItem *parent) :
HbWidget(*new HbRatingSliderPrivate,parent)
{
    Q_D( HbRatingSlider );
    d->q_ptr = this;
    d->init();
}


/*!
    @beta
    Constructor of  RatingSlider.
    \param parent. Parent widget
*/
HbRatingSlider::HbRatingSlider(HbRatingSliderPrivate &dd,QGraphicsItem *parent) : 
    HbWidget( dd,parent)
{
    Q_D( HbRatingSlider );
    d->init();
}


/*!
    Destructor
*/

HbRatingSlider::~HbRatingSlider()
{
}

/*!
    @beta
    Sets the read only property. It disables the interaction with widget

    \param value true or false.

    \sa readOnly()
*/

void HbRatingSlider::setReadOnly(bool value)
{
    Q_D(HbRatingSlider);
    d->mReadOnly = value;
}

/*!    
    
    @beta  
    Sets the number of icons. In a Rating scenario you may have number of repeated icons. This API can be used to set 
    the number of icons required. For Example the default image is "*" and you have 5 stars. You can set the number of 
    stars  using this. By default this value is 5.

    \param number. A value between 1 and 10 

    \sa numberOfIcons()
*/

void HbRatingSlider::setNumberOfIcons(int number)
{
    Q_D(HbRatingSlider);
    if ( (number <= 0) || (number > MAX_NUMBER_OF_ICONS) ){
        return;
    }
    d->mNumberOfIcons = number;
    updatePrimitives();
    d->createLookupTable();
}


/*!        
    @beta  
    Returns the number of icons set.

    \sa setNumberOfIcons()
*/

int HbRatingSlider::numberOfIcons() const
{
    Q_D(const HbRatingSlider);
    return d->mNumberOfIcons;
}

/*!
    @beta
    Sets the step count for the rating slider. If the number of icons is 5 and step count is 10 then it is possible to have 10 ratings.
    one rating will be half star (by default). If the number of icons is 5 and step count is 5 then 5 ratings are possible. In this 
    case one rating will be one complete star. By default this value is 5.
    
    \param count. A value between 1 and 100. This can be considerd as the maximum rating possible. 

    \sa numberOfIcons()

*/
void HbRatingSlider::setStepCount(int count)
{
    Q_D(HbRatingSlider);
    if( (count <= 0) || (count > 100) ) {
        return;
    }
    d->mStepCount = count;
    d->createLookupTable();    
    
    HbStyleOptionRatingSlider option;
    initStyleOption(&option);
    if (d->mTrack) {
           style()->updatePrimitive(d->mTrack, HbStyle::P_RatingSlider_track, &option);
    }

}

/*!
    @beta
    Returns the step count.

*/    
int HbRatingSlider::stepCount() const
{
    Q_D(const HbRatingSlider);
    return d->mStepCount;
}

/*!
    @beta
    Returns the read only flag of the Rating slider
*/
bool HbRatingSlider::isReadOnly() const
{
    Q_D(const HbRatingSlider);
    return d->mReadOnly;
}

/*!
    @beta
    It sets the current rating value.
    \param count. A value between 1 and stepcount. 
    \sa currentRating()

*/
void  HbRatingSlider::setCurrentRating(int rating)
{
    Q_D(HbRatingSlider);
    if( rating >d->mStepCount ) {
        rating = d->mStepCount;
    }
    if( (rating == d->mCurrentValue) || (rating < 0) ) {
        return;
    }

    d->mCurrentValue = rating;
    
    HbStyleOptionRatingSlider option;
    initStyleOption(&option);
    if (d->mTrack) {
           style()->updatePrimitive(d->mTrack, HbStyle::P_RatingSlider_track, &option);
    }
}

/*!
    @beta
    Returns the the current rating value.
*/
int HbRatingSlider::currentRating() const
{
    Q_D(const HbRatingSlider);
    return d->mCurrentValue;
}

/*!
    @beta
    
    It sets the unrated graphics name.This is the graphics shown when rating slider is displayed.
    the grpahics can be a single star kind of or multi star image. If it is single star then use setNumberOfIcons for 
    setting number of stars.
    
    \param name. The graphics name along with the path. 
    \sa unRatedIconName()
*/
void HbRatingSlider::setUnRatedIconName(const QString name)
{
    Q_D(HbRatingSlider);
    if(d->mUnratedIconName != name) {
        d->mUnratedIconName =name;

        HbStyleOptionRatingSlider option;
        initStyleOption(&option);
        updatePrimitives();
    }
    
}

/*!
    @beta
    Returns the unrated graphics name .
*/
QString HbRatingSlider::unRatedIconName() const
{
    Q_D(const HbRatingSlider);
    return d->mUnratedIconName;

}

/*!
    @beta
    
    It sets the rated graphics name.This is the graphics shown when rating is on going.
    the grpahics can be a single star kind of or multi star image. If it is single star then use setNumberOfIcons for 
    setting number of stars.
    
    \param name. The graphics name along with the path. 
    \sa unRatedIconName()
*/
void HbRatingSlider::setRatedIconName(const QString name)
{
    Q_D(HbRatingSlider);
    if(d->mRatedIconName != name) {
        d->mRatedIconName = name;
        HbStyleOptionRatingSlider option;
        initStyleOption(&option);
        updatePrimitives();
    }
}

/*!
    @beta
    Returns the rated graphics name .
*/
QString HbRatingSlider::ratedIconName() const 
{
    Q_D(const HbRatingSlider);
    return d->mRatedIconName;
}

#ifndef HB_GESTURE_FW
/*!
    \reimp
*/
void HbRatingSlider::mousePressEvent(QGraphicsSceneMouseEvent *event) 
{
    
    Q_D(HbRatingSlider);
    if(d->mTouchArea->isUnderMouse()) {

        if(d->mReadOnly) {    
            event->ignore();
            return;
        }
        d->mMousePressed = true;
        event->accept();

    }

}
/*!
    \reimp
*/
void HbRatingSlider::mouseMoveEvent ( QGraphicsSceneMouseEvent * event ) 
{
    Q_D(HbRatingSlider);

    if(!d->mMousePressed) {
        return;
    }
    QPointF layoutItemPos = d->mLayoutItem->pos();
    QPointF frameItemPos = d->mFrame->pos();   
    qreal xVal = event->pos().x() - layoutItemPos.x()+ frameItemPos.x();
    if(d->mTouchArea->isUnderMouse()) {
            
        if(d->mReadOnly) {
            event->ignore();
            return;
        }
        
        if(xVal <0) {    
            setCurrentRating(0);
            return;
        }
        
        QRectF rect = d->mTouchArea->boundingRect();
        int rating=0;
        if(rect.contains(xVal,0 )) {
            rating = d->calculateProgressValue(xVal);
            if(toolTip() != QString()) {
                HbToolTip::showText(toolTip(),this);
            }    
            setCurrentRating(rating);
            emit ratingChanged (d->mCurrentValue);
            event->accept();
        }
        

    }
    else {
            setCurrentRating(0);
        }

}
/*!
    \reimp
*/
void HbRatingSlider::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) 
{
    Q_D(HbRatingSlider);
   
    QPointF layoutItemPos = d->mLayoutItem->pos();
    QPointF frameItemPos = d->mFrame->pos();

    qreal xVal = event->pos().x() - layoutItemPos.x()+ frameItemPos.x();
    if(d->mTouchArea->isUnderMouse()) {
            
        if(d->mReadOnly) {
            event->ignore();
            return;
        }
        
        if(xVal <0) {    
            setCurrentRating(0);
            return;
        }
        
        QRectF rect = d->mTouchArea->boundingRect();
        int rating=0;
        if(rect.contains(xVal,0 )) {
            rating = d->calculateProgressValue(xVal);
            if(toolTip() != QString()) {
                HbToolTip::showText(toolTip(),this);
            }    
            setCurrentRating(rating);
            if(d->mCurrentValue) {
                emit ratingDone (d->mCurrentValue);
            }
            event->accept();
            d->mMousePressed = false;
        }
    
    }        
}
#else
void HbRatingSlider::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event)
}
#endif

#ifdef HB_GESTURE_FW
void HbRatingSlider::gestureEvent(QGestureEvent *event)
{
    Q_D (HbRatingSlider);
    if(event->gesture(Qt::TapGesture)) {
            HbTapGesture *tap = qobject_cast<HbTapGesture *>(event->gesture(Qt::TapGesture));
            switch(tap->state()) {
            case Qt::GestureStarted:
                {
                qreal xVal = mapFromScene(event->mapToGraphicsScene(tap->position( ))).x();
                int rating = d->calculateProgressValue(xVal);
                if(rating == -1) {
                    return;
                }
                if(d->mReadOnly) {    
                    event->ignore();
                    return;
                }

                d->mMousePressed = true;
                event->accept();
                }
                break;
 
            case Qt::GestureFinished: // Reset state 
                {
            qreal xVal = mapFromScene(event->mapToGraphicsScene(tap->position( ))).x();
            QRectF rect = d->mTouchArea->boundingRect();
            int rating=0;
            if(rect.contains(xVal,0 )) {
                if(d->mReadOnly) {
                    event->ignore();
                    return;
                }

                if(!d->mMousePressed){
                    return;
                }

                if(xVal <0) {    
                    setCurrentRating(0);
                    emit ratingDone (d->mCurrentValue);
                    return;
                }

               rating = d->calculateProgressValue(xVal);
        
               if(toolTip() != QString()) {
                    HbToolTip::showText(toolTip(),this);
                }    
                setCurrentRating(rating);
                if(d->mCurrentValue) {
                    emit ratingDone (d->mCurrentValue);
                }
                event->accept();
                d->mMousePressed = false;
                }
            }
            break;
            default: break;
            } 
    }else if(event->gesture(Qt::PanGesture)) {
                HbPanGesture *pan = qobject_cast<HbPanGesture *>(event->gesture(Qt::PanGesture));
                switch(pan->state()) {
                    case Qt::GestureUpdated:
                        {
                        if(!d->mMousePressed) {
                            return;
                        }
                        qreal xVal = mapFromScene(event->mapToGraphicsScene( pan->startPos()+pan->offset())).x();
                            QRectF rect = d->mTouchArea->boundingRect();
                            int rating=0;
                            if(rect.contains(xVal,0 )) {
                                if(d->mReadOnly) {
                                event->ignore();
                                return;
                            }
                            
                            if(xVal <0) {    
                                setCurrentRating(0);
                                return;
                            }

                                rating = d->calculateProgressValue(xVal);
                                
                                if(toolTip() != QString()) {
                                    HbToolTip::showText(toolTip(),this);
                                }    
                                setCurrentRating(rating);
                                emit ratingChanged (d->mCurrentValue);
                                event->accept();
                            }
                            else {
                                setCurrentRating(0);
                            }
                        }
                        break;
                    case Qt::GestureFinished: // Reset state 
                    {                          
                         qreal xVal = mapFromScene(event->mapToGraphicsScene( pan->startPos()+pan->offset())).x();
                         QRectF rect = d->mTouchArea->boundingRect();
                         int rating=0;
                         if(rect.contains(xVal,0 )) {
                            if(d->mReadOnly) {
                               event->ignore();
                               return;
                             }
                        }

                        if(!d->mMousePressed) {
                             return;
                        }

                       if(xVal <0) {    
                          setCurrentRating(0);
                          emit ratingDone (d->mCurrentValue);
                          return;
                        }

                        rating = d->calculateProgressValue(xVal);
                        setCurrentRating(rating);
                        if(d->mCurrentValue) {
                           emit ratingDone (d->mCurrentValue);
                        }
                        d->mMousePressed = false;
                        event->accept();
                     }
                     default:
                     break;
                }
    }
}
#endif 

/*!
    \reimp
*/
void HbRatingSlider::setGeometry(const QRectF & rect)
{
    Q_D(HbRatingSlider);
    HbWidget::setGeometry(rect);
    updatePrimitives();
    d->createLookupTable();
}

void HbRatingSlider::initStyleOption(HbStyleOption *hboption) const
{
    Q_D( const HbRatingSlider );
     HbWidget::initStyleOption(hboption); 
    HbStyleOptionRatingSlider *option = 0;
    if ((option = qstyleoption_cast< HbStyleOptionRatingSlider *>(hboption)) != 0) {
        option->noOfStars = d->mNumberOfIcons;
        option->noOfIntervals = d->mStepCount;
        option->unRatedGraphicsName = d->mUnratedIconName;
        option->ratedGraphicsName = d->mRatedIconName;
        option->progressValue = d->mCurrentValue;
    }
}

/*!

    \deprecated HbRatingSlider::primitive(HbStyle::Primitive)
        is deprecated.

    Provides access to primitives of HbRatingSlider. 
    \param primitive is the type of the requested primitive. The available 
    primitives are P_RatingSlider_frame,P_RatingSlider_track and P_RatingSlider_layout.

*/
QGraphicsItem* HbRatingSlider::primitive(HbStyle::Primitive primitive) const
{
    Q_D(const HbRatingSlider);
    switch (primitive) {
        case HbStyle::P_RatingSlider_frame:
            return d->mFrame;
        case HbStyle::P_RatingSlider_track:
            return d->mTrack;  
        case HbStyle::P_RatingSlider_layout:
            return d->mLayoutItem;
         default:
            return 0;
    }
}

void HbRatingSlider::changeEvent(QEvent *event)
{
    HbWidget::changeEvent(event);
    switch (event->type()) {
    case QEvent::LayoutDirectionChange:
        updatePrimitives();
        break;
    default:
        break;
    }
}
void HbRatingSlider::updatePrimitives()
{
    Q_D(HbRatingSlider);
    HbStyleOptionRatingSlider option;
    initStyleOption(&option);
    if (d->mFrame) {
            style()->updatePrimitive(d->mFrame, HbStyle::P_RatingSlider_frame, &option);
    }
  
    if (d->mTrack) {
           style()->updatePrimitive(d->mTrack, HbStyle::P_RatingSlider_track, &option);
    }

    if (d->mTouchArea) {
        style()->updatePrimitive(d->mTouchArea, HbStyle::P_CheckBox_toucharea, &option);
    }
    
}

QVariant HbRatingSlider::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if(change == ItemVisibleHasChanged && value.toBool()){
        updatePrimitives();
    }
#ifdef HB_EFFECTS
    if(change == QGraphicsItem::ItemVisibleChange){
        if(value.toBool()) {

            HbEffect::start(this, HB_RATINGSLIDER_ITEM_TYPE, "ratingslider_appear");
        }
        else
        {
             HbEffect::start(this, HB_RATINGSLIDER_ITEM_TYPE, "ratingslider_disappear");
        }
    }

#endif//HB_EFFECTS

   return HbWidget::itemChange(change,value);
}