src/hbwidgets/sliders/hbprogresssliderhandle_p.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 17 Sep 2010 08:32:10 +0300
changeset 28 b7da29130b0e
parent 23 e6ad4ef83b23
permissions -rw-r--r--
Revision: 201035 Kit: 201037

/****************************************************************************
**
** 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 "hbprogresssliderhandle_p.h"
#include "hbstyle_p.h"
#include <hbtooltip.h>
#include <hbstyleoptionprogresssliderhandle_p.h>
#include <hbextendedlocale.h>
#include <QGraphicsSceneMouseEvent>

#define HBPROGRESSSLIDERHANDLE_TRACES
#ifdef HBPROGRESSSLIDERHANDLE_TRACES
#include <QtDebug>
#endif

#include <hbwidgetfeedback.h>

#ifdef HB_EFFECTS
#include "hbeffect.h"
#include "hbeffectinternal_p.h"
#define HB_PRGRESSSLIDERHANDLE_ITEM_TYPE "HB_PROGRESSSLIDERHANDLE"
#endif

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

#define   HandleMargin 0

/*!
    \reimp
    \fn int HbProgressSliderHandle::type() const
 */

HbProgressSliderHandle::HbProgressSliderHandle(HbHandleParent *parent) 
    :HbWidget(parent->parentGraphicsItem()),
    q(parent),
    mHandleIcon()
{
    mFlags = 0;
    mFlags |= TextVisible;

    mHandleIconItem = HbStylePrivate::createPrimitive(HbStylePrivate::P_ProgressSliderHandle_icon,this);
    HbStyle::setItemName(mHandleIconItem , "icon");

    mTouchItem = HbStylePrivate::createPrimitive(HbStylePrivate::P_ProgressSliderHandle_toucharea, this); 
    HbStyle::setItemName(mTouchItem , "toucharea");
    setProperty("state","normal");

#ifdef HB_EFFECTS
    HbEffectInternal::add(HB_PRGRESSSLIDERHANDLE_ITEM_TYPE,"progressslider_handlepress", "progressslider_handlepress");
    HbEffectInternal::add(HB_PRGRESSSLIDERHANDLE_ITEM_TYPE,"progressslider_handlerelease", "progressslider_handlerelease");
    HbEffectInternal::add(HB_PRGRESSSLIDERHANDLE_ITEM_TYPE,"progressslider_handleoutofbound", "progressslider_handleoutofbound");
#endif

#ifdef HB_GESTURE_FW
    grabGesture(Qt::TapGesture);
    grabGesture(Qt::PanGesture);

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

HbProgressSliderHandle::~HbProgressSliderHandle() 
{
}

void HbProgressSliderHandle::setHandleIcon(const HbIcon& icon)
{
    mHandleIcon= icon;

    HbStyleOptionProgressSliderHandle option;
    initStyleOption(&option);

    HbStylePrivate::updatePrimitive(mHandleIconItem, HbStylePrivate::P_ProgressSliderHandle_icon, &option);
}



void HbProgressSliderHandle::mousePressEvent(QGraphicsSceneMouseEvent *event) 
{
#ifndef HB_GESTURE_FW
    HbWidget::mousePressEvent(event);

#ifdef HB_EFFECTS
    HbEffect::start(this, HB_PRGRESSSLIDERHANDLE_ITEM_TYPE, "progressslider_handlepress");
#endif
    mFlags |= HbProgressSliderHandle::MousePressed;

    HbStyleOptionProgressSliderHandle option;
    initStyleOption(&option);
    option.pressedState = true;
    if (mHandleIconItem) {
        HbStylePrivate::updatePrimitive(mHandleIconItem, HbStylePrivate::P_ProgressSliderHandle_icon, &option);
    }

    mMousePressPos = event->scenePos();
    mItemPosAtPress = pos();
   
    HbWidgetFeedback::triggered(q->parentGraphicsWidget(), Hb::InstantPressed, Hb::ModifierSliderHandle);

    event->accept();
    q->emitSliderPressed();   

     if(q->textVisible()) {  // User called it 
         if(!q->toolTipText().isNull()) {
             HbToolTip::showText(q->toolTipText(),this, QRectF(mItemPosAtPress,QSize(0,0)),q->textAlignment());            
         }        
      }
      else {  // show default

         HbExtendedLocale locale;
         HbProgressSlider *slider = (HbProgressSlider*)q->parentGraphicsWidget();
         HbToolTip::showText(locale.toString(slider->sliderValue()),this, QRectF(mItemCurPos,QSize(0,0)),q->textAlignment());

     }
#else
    Q_UNUSED(event)
#endif 
}

void HbProgressSliderHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) 
{
#ifndef HB_GESTURE_FW
    HbWidget::mouseReleaseEvent(event);

    HbStyleOptionProgressSliderHandle option;
    initStyleOption(&option);
    option.pressedState = false;
    if (mHandleIconItem) {
        HbStylePrivate::updatePrimitive(mHandleIconItem, HbStylePrivate::P_ProgressSliderHandle_icon, &option);
    }

    if (isHandleMoving()) {
      HbWidgetFeedback::continuousStopped(q->parentGraphicsWidget(), Hb::ContinuousDragged);
    }
    HbWidgetFeedback::triggered(q->parentGraphicsWidget(), Hb::InstantReleased, Hb::ModifierSliderHandle);

#ifdef HB_EFFECTS
    HbEffect::start(this, HB_PRGRESSSLIDERHANDLE_ITEM_TYPE, "progressslider_handlerelease");
#endif
    mFlags &= ~HbProgressSliderHandle::MousePressed;
    mFlags &=~HandleMoving;
    event->accept();
    setHandlePosForValue(q->progressValue());   
    q->emitSliderReleased();
#else
    Q_UNUSED(event)
#endif 
}

void HbProgressSliderHandle::mouseMoveEvent ( QGraphicsSceneMouseEvent * event ) 
{
#ifndef HB_GESTURE_FW
    HbWidget::mouseMoveEvent(event);
    mFlags |=HandleMoving;
    QPointF scenePos = event->scenePos();
    if(q->orientation() == Qt::Horizontal){
             mItemCurPos = QPointF((event->scenePos().x() - mMousePressPos.x()) + mItemPosAtPress.x(), pos().y());
             HbWidgetFeedback::continuousTriggered(qobject_cast<HbWidget*>(q->parentGraphicsWidget()), Hb::ContinuousDragged);
             if(mItemCurPos.x()+boundingRect().width() < q->boundingRect().width()
                 && mItemCurPos.x()>HandleMargin){
                setPos(mItemCurPos);
             }
             else{
                processItemChange(mItemCurPos);
             }
        }

     if (!mTouchItem->boundingRect().contains(parentItem()->mapFromScene(scenePos))) {
        #ifdef HB_EFFECTS
            HbEffect::start(this, HB_PRGRESSSLIDERHANDLE_ITEM_TYPE, "progressslider_handleoutofbound");
        #endif
    }

    event->accept();

    q->emitSliderMoved(pointToValue(mItemCurPos));  
    
     if(q->textVisible()) {  // User called it 
         if(q->toolTipText().isNull()) {

             // Dont show any tooltip.
             
         }
         else { 

             HbToolTip::showText(q->toolTipText(),this, QRectF(mItemPosAtPress,QSize(0,0)),q->textAlignment());
            
         }        
      }
      else {  // show default

         HbExtendedLocale locale;
         HbProgressSlider *slider = (HbProgressSlider*)q->parentGraphicsWidget();
         HbToolTip::showText(locale.toString(slider->sliderValue()),this, QRectF(mItemCurPos,QSize(0,0)),q->textAlignment());

     }
#else
    Q_UNUSED(event)
#endif 
}

void HbProgressSliderHandle::handleTrackRelease(QGestureEvent *event)
{
    Q_UNUSED(event);
    setHandlePosForValue(q->progressValue());   
}

void HbProgressSliderHandle::handleTrackPress(QGestureEvent *event)
{
    HbTapGesture *gesture = static_cast<HbTapGesture *>(event->gesture(Qt::TapGesture));
    QPointF newPos = q->parentGraphicsItem()->mapFromScene(event->mapToGraphicsScene(gesture->position()));

    //QPointF newPos = q->parentGraphicsItem()->mapFromScene(event->scenePos());
    if((newPos.x() >=  q->boundingRect().x()) && (newPos.x() <=  q->boundingRect().width())) {   
        if(q->orientation() == Qt::Horizontal){
            mItemCurPos = QPointF(newPos.x() - boundingRect().width()/2, pos().y());
        }
        else{
            mItemCurPos = QPointF(pos().x(), newPos.y()-boundingRect().height()/2);
        }

        mItemCurPos = normalizedPos(mItemCurPos,false);
        setPos(mItemCurPos);
        processItemChange(mItemCurPos);
    }
}


/*!
  reimp

*/
void HbProgressSliderHandle::gestureEvent(QGestureEvent *event)
{ 
    if(HbTapGesture *tap = qobject_cast<HbTapGesture *>(event->gesture(Qt::TapGesture))) {
        switch(tap->state()) {
            case Qt::GestureStarted: {
                mMousePressPos = mapFromScene(event->mapToGraphicsScene(tap->position( )));                
                if(q->textVisible()) {  // User called it 
                    if(!q->toolTipText().isNull()) {
                        HbToolTip::showText(q->toolTipText(),this, QRectF(mMousePressPos,QSize(0,0)),q->textAlignment());            
                    }        
                }
                else {  // show default
                    HbExtendedLocale locale;
                    HbProgressSlider *slider = (HbProgressSlider*)q->parentGraphicsWidget();
                    HbToolTip::showText(locale.toString(slider->sliderValue()),this, QRectF(mMousePressPos,QSize(0,0)),q->textAlignment());
                }
                #ifdef HB_EFFECTS
                    HbEffect::start(this, HB_PRGRESSSLIDERHANDLE_ITEM_TYPE, "progressslider_handlepress");
                #endif
                mFlags |= HbProgressSliderHandle::MousePressed;
                HbStyleOptionProgressSliderHandle option;
                initStyleOption(&option);
                option.pressedState = true;
                if (mHandleIconItem) {
                    HbStylePrivate::updatePrimitive(mHandleIconItem, HbStylePrivate::P_ProgressSliderHandle_icon, &option);
                }
                mMousePressPos = mapFromScene(event->mapToGraphicsScene(tap->position( )));
                HbWidgetFeedback::triggered(q->parentGraphicsWidget(), Hb::InstantPressed, Hb::ModifierSliderHandle);
                event->accept();

                q->emitSliderPressed();  
            }
            break;
            case Qt::GestureFinished:{
                HbStyleOptionProgressSliderHandle option;
                initStyleOption(&option);
                option.pressedState = false;
                if (mHandleIconItem) {
                HbStylePrivate::updatePrimitive(mHandleIconItem, HbStylePrivate::P_ProgressSliderHandle_icon, &option);
                }
                if (isHandleMoving()) {
                    HbWidgetFeedback::continuousStopped(q->parentGraphicsWidget(), Hb::ContinuousDragged);
                }
                HbWidgetFeedback::triggered(q->parentGraphicsWidget(), Hb::InstantReleased, Hb::ModifierSliderHandle);
                #ifdef HB_EFFECTS
                HbEffect::start(this, HB_PRGRESSSLIDERHANDLE_ITEM_TYPE, "progressslider_handlerelease");
                #endif
                mFlags &= ~HbProgressSliderHandle::MousePressed;
                mFlags &=~HandleMoving;
                event->accept();
                setHandlePosForValue(q->progressValue());   
                q->emitSliderReleased();
            }
            break;
            default:
                break;                                  
        }
    }
    if (HbPanGesture *panGesture = qobject_cast<HbPanGesture*>(event->gesture(Qt::PanGesture))) {
        switch(panGesture->state( )) {
            case Qt::GestureStarted: 
            case Qt::GestureUpdated:{
                    mFlags |=HandleMoving;
                    QPointF scenePos =mapToParent( mapFromScene(panGesture->sceneOffset( )+panGesture->sceneStartPos( )));
                    if(scenePos.x() == oldCord.x()) {
                        return;
                    }
                    oldCord = scenePos;
                    //if(q->orientation() == Qt::Horizontal){
                        mItemCurPos = QPointF((scenePos.x() - mMousePressPos.x()), pos().y());
                        HbWidgetFeedback::continuousTriggered(qobject_cast<HbWidget*>(q->parentGraphicsWidget()), Hb::ContinuousDragged);
                        if(mItemCurPos.x()+boundingRect().width() < q->boundingRect().width() && mItemCurPos.x()>q->boundingRect().topLeft().x() ){
                        setPos(mItemCurPos);
                    //}
                    //else{
                    //    processItemChange(mItemCurPos);
                    //}
                }
                if (!mTouchItem->boundingRect().contains(parentItem()->mapFromScene(scenePos))) {
                    #ifdef HB_EFFECTS
                    HbEffect::start(this, HB_PRGRESSSLIDERHANDLE_ITEM_TYPE, "progressslider_handleoutofbound");
                    #endif
                }
                event->accept();
                if(q->textVisible()) {  // User called it 
                     if(q->toolTipText().isNull()) {
                         // Dont show any tooltip.                     
                     }
                     else { 
                         HbToolTip::showText(q->toolTipText(),this, QRectF(mItemCurPos,QSize(0,0)),q->textAlignment());                    
                     }        
                 }
                 else {  // show default
                     HbExtendedLocale locale;
                     HbProgressSlider *slider = (HbProgressSlider*)q->parentGraphicsWidget();
                     HbToolTip::showText(locale.toString(slider->sliderValue()),this, QRectF(mItemCurPos,QSize(0,0)),q->textAlignment());
                 } 
                 q->emitSliderMoved(pointToValue(mItemCurPos));
            }
            break;
            case Qt::GestureFinished:
            case Qt::GestureCanceled: {
                HbStyleOptionProgressSliderHandle option;
                option.pressedState = false;
                initStyleOption(&option);
                if (mHandleIconItem) {
                    HbStylePrivate::updatePrimitive(mHandleIconItem, HbStylePrivate::P_ProgressSliderHandle_icon, &option);
                }
                if (isHandleMoving()) {
                  HbWidgetFeedback::continuousStopped(q->parentGraphicsWidget(), Hb::ContinuousDragged);
                }
                else {
                    HbWidgetFeedback::triggered(q->parentGraphicsWidget(), Hb::InstantReleased, Hb::ModifierSliderHandle);
                }
                #ifdef HB_EFFECTS
                HbEffect::start(this, HB_PRGRESSSLIDERHANDLE_ITEM_TYPE, "progressslider_handlerelease");
                #endif
                mFlags &= ~HbProgressSliderHandle::MousePressed;
                mFlags &=~HandleMoving;
                event->accept();
                setHandlePosForValue(q->progressValue());   
                q->emitSliderReleased();
            }
            break;
            default:
                break;
        }
    }

}

int HbProgressSliderHandle::pointToValue(QPointF point) const
{
    QRectF rect = q->boundingRect();
    qreal effectiveWidth;
    point = normalizedPos(point,q->invertedAppearance());
    qreal givenPixel;
 
    effectiveWidth = rect.width() - boundingRect().width();
    givenPixel = point.x();
    
    qreal tickPerPixel = (qreal)(q->maximum()-q->minimum())/effectiveWidth;
    qreal tickForGivenPixel = givenPixel * tickPerPixel;
    tickForGivenPixel = qRound(tickForGivenPixel);

    int value;
    if(!q->invertedAppearance()) {
        value = q->minimum() + (int)tickForGivenPixel;
    } else {
        value = q->maximum() - (int)tickForGivenPixel;
    }

    if(value>q->maximum()) {
        return q->maximum();
    }
    else if(value<q->minimum()) {
        return q->minimum();
    }
    return value;
}

// converts value to handle coordinates
QPointF HbProgressSliderHandle::valueToHandlePos(int value) const
{
    QRectF r1 = q->boundingRect();
    QRectF r2 = boundingRect();

    qreal width;
    width = r1.width() - r2.width();
    if(q->maximum() != q->minimum()){
        qreal pixelpertick = width/(qreal)(q->maximum()-q->minimum());
        qreal noOfTicks = qreal(value - q->minimum());
        qreal xpos =  noOfTicks * pixelpertick;
        return QPointF(xpos, r1.top());
    }
    else{
        return QPointF(0,0);
    }
}

QPointF HbProgressSliderHandle::normalizedPos(const QPointF&  pos,bool inverted) const 
{
    Q_UNUSED(inverted);
    
    QPointF newPos = pos;
    
    if (newPos.x() < HandleMargin) {
            newPos.setX( HandleMargin );
    }

    if (newPos.x() > q->boundingRect().width() - boundingRect().width() - HandleMargin) {
            newPos.setX(q->boundingRect().width() - boundingRect().width() - HandleMargin);
    }
    
    return newPos;
}

bool HbProgressSliderHandle::isHandlePressed() const
{
    return mFlags.testFlag(HbProgressSliderHandle::MousePressed);
}


bool HbProgressSliderHandle::isHandleMoving() const
{
    return mFlags.testFlag(HbProgressSliderHandle::HandleMoving);
}

QVariant HbProgressSliderHandle::processItemChange(const QVariant &value)
{
        // value is the new position
        QPointF pt = value.toPointF();
        int newValue = pointToValue(pt);
        pt.setY(q->boundingRect().top());
        q->emitSliderMoved(newValue);
        QPointF newPos = pt;
        return normalizedPos(newPos,false);
}

void HbProgressSliderHandle::setHandlePosForValue(int progressValue)
{
    if(!mFlags.testFlag(HbProgressSliderHandle::MousePressed)){

        QPointF newPos = valueToHandlePos(progressValue);
        QPointF pos = normalizedPos(newPos,q->invertedAppearance());
        if(q->invertedAppearance()) {
                qreal xVal = q->boundingRect().width() - pos.x() - boundingRect().width();
                pos.setX(xVal);
        }
        qreal yPos = qreal (q->boundingRect().height()-boundingRect().height()) /2 ;
        setPos(pos.x(),yPos);
    }    
}


void  HbProgressSliderHandle::updatePrimitives()
{    
    HbStyleOptionProgressSliderHandle option;
    initStyleOption(&option);

    if (mHandleIconItem) {
        HbStylePrivate::updatePrimitive(mHandleIconItem, HbStylePrivate::P_ProgressSliderHandle_icon, &option);
    }

}

/*!
    Returns the pointer for \a primitive passed.
    Will return NULL if \a primitive passed is invalid
*/
QGraphicsItem* HbProgressSliderHandle::primitive(HbStyle::Primitive primitive) const
{
    switch (primitive) {
        case HbStylePrivate::P_ProgressSliderHandle_icon:
            return mHandleIconItem;
        case HbStylePrivate::P_ProgressSliderHandle_toucharea:
            return mTouchItem;
        default:
            return 0;
    }
}

/*!
    Initializes \a option with the values from this HbProgressSliderHandle. 
    This method is useful for subclasses when they need a HbStyleOptionProgressSliderHandle,
    but don't want to fill in all the information themselves.
 */
void HbProgressSliderHandle::initStyleOption(HbStyleOptionProgressSliderHandle *option) const
{
    HbWidget::initStyleOption(option);
    option->handleIcon = mHandleIcon;
    option->pressedState = false;
}
void HbProgressSliderHandle::setPressedState()
{
   HbStyleOptionProgressSliderHandle option;
   initStyleOption(&option);
   option.pressedState = true;
   if (mHandleIconItem) {
         HbStylePrivate::updatePrimitive(mHandleIconItem, HbStylePrivate::P_ProgressSliderHandle_icon, &option);
   }
}
void HbProgressSliderHandle::setReleasedState()
{
   HbStyleOptionProgressSliderHandle option;
   initStyleOption(&option);
   option.pressedState = false;
   if (mHandleIconItem) {
         HbStylePrivate::updatePrimitive(mHandleIconItem, HbStylePrivate::P_ProgressSliderHandle_icon, &option);
   }
}