src/hbwidgets/sliders/hbprogresssliderhandle_p.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 18 Aug 2010 10:05:37 +0300
changeset 21 4633027730f5
parent 6 c3690ec91ef8
child 23 e6ad4ef83b23
permissions -rw-r--r--
Revision: 201031 Kit: 201033

/****************************************************************************
**
** 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::gestureEvent(QGestureEvent *event)
{
    Q_UNUSED(event);
    // HbWidgetBase::gestureEvent() ignores, overriding to accept
}

void HbProgressSliderHandle::mousePressEvent(QGraphicsSceneMouseEvent *event) 
{
    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());

     }
}

void HbProgressSliderHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) 
{
    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();
}

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

void HbProgressSliderHandle::handleTrackPress(QGraphicsSceneMouseEvent * event)
{
    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);
    }
}

void HbProgressSliderHandle::mouseMoveEvent ( QGraphicsSceneMouseEvent * event ) 
{
    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());

     }
}

int HbProgressSliderHandle::pointToValue(QPointF point) const
{
    QRectF rect = q->boundingRect();
    qreal effectiveWidth;
    point = normalizedPos(point,q->invertedAppearance());
    qreal givenPixel;
    if(q->orientation() == Qt::Horizontal){
        effectiveWidth = rect.width() - boundingRect().width();
        givenPixel = point.x();
    }
    else{
        effectiveWidth = rect.height() - boundingRect().height();
        givenPixel = effectiveWidth-point.y();
    }

    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;
    if(q->orientation()== Qt::Horizontal){
        width = r1.width() - r2.width();
        
    }
    else{
        width = r1.height() - r2.height();
       
    }
    if(q->maximum() != q->minimum()){
        qreal pixelpertick = width/(qreal)(q->maximum()-q->minimum());
        qreal noOfTicks = qreal(value - q->minimum());
        qreal xpos =  noOfTicks * pixelpertick;
        if(q->orientation() == Qt::Horizontal){
            return QPointF(xpos, r1.top());
        }
        else{
            return QPointF(r1.left(),width-xpos);
        }
    }
    else{
        return QPointF(0,0);
    }
}

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

        if (newPos.x() > q->boundingRect().width() - boundingRect().width() - HandleMargin) {
            newPos.setX(q->boundingRect().width() - boundingRect().width() - HandleMargin);
        }
    }
    else{
        if (newPos.y() < HandleMargin) {
            newPos.setY( HandleMargin );
        }

        if (newPos.y() > q->boundingRect().height() - boundingRect().height() - HandleMargin) {
            newPos.setY(q->boundingRect().height() - boundingRect().height() - 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);
        if(q->orientation() == Qt::Horizontal){
            pt.setY(q->boundingRect().top());
        }
        else{
            pt.setX(q->boundingRect().left());
        }
        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()) {
            if(q->orientation() == Qt::Horizontal){
                qreal xVal = q->boundingRect().width() - pos.x() - boundingRect().width();
                pos.setX(xVal);
            }
            else{
                qreal yVal = q->boundingRect().height() - pos.y() - boundingRect().height();
                pos.setY(yVal);
            }
           
        }

        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;
}