telutils/dialpad/src/dialpad.cpp
branchRCL_3
changeset 19 7d48bed6ce0c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telutils/dialpad/src/dialpad.cpp	Tue Aug 31 15:45:17 2010 +0300
@@ -0,0 +1,489 @@
+/*!
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Dialpad popup
+*
+*/
+
+#include <QGraphicsLinearLayout>
+
+#include <hbframedrawer.h>
+#include <hbinstance.h>
+#include <hbeffect.h>
+#include <hbinstance.h>
+#include <hbmainwindow.h>
+#include <hbstyleloader.h>
+#include <hblineedit.h>
+#include <hbapplication.h>
+#include <hbswipegesture.h>
+#include <hbeffect.h>
+#include <hbevent.h>
+
+#include "dialpad.h"
+#include "dialpadinputfield.h"
+#include "dialpadkeypad.h"
+#include "dialpadbutton.h"
+#include "dialpadmultitaphandler.h"
+#include "dialpadbackground.h"
+#include "dialpadbutton.h"
+
+static const QLatin1String backgroundGraphics("qtg_fr_input_v_bg");
+static const QLatin1String backgroundGraphicsH("qtg_fr_input_h_bg");
+static const QLatin1String minimizeIcon("qtg_graf_input_v_swipe");
+static const QLatin1String minimizeIconH("qtg_graf_input_h_swipe");
+static const int DialpadCloseAnimDuration = 200; // ms
+static const int DialpadOpenAnimDuration = 200; // ms
+static const qreal DialpadComponentMargin = 0.75; // units
+static const qreal DialpadCloseHandleHeight = 2.23; // units
+static const qreal DialpadCloseHandleWidth = 18.8; // units
+static const qreal DialpadCallButtonHeight = 8.75; // units, same as numeric buttons
+static const qreal DialpadCallButtonHeightH = 7.25; // units
+
+static const QLatin1String handsetIcon("qtg_mono_call");
+static const QLatin1String vmbxIcon("qtg_mono_voice_mailbox");
+
+const QLatin1String DIALPAD_TO_PRT_FXML(":/dialpad_to_prt.fxml");
+const QLatin1String DIALPAD_TO_LSC_FXML(":/dialpad_to_lsc.fxml");
+const QLatin1String DIALPAD_TO_PRT_EVENT("prt_activated");
+const QLatin1String DIALPAD_TO_LSC_EVENT("lsc_activated");
+
+Dialpad::Dialpad() :
+    mMainWindow(*hbInstance->allMainWindows().at(0)),
+    mBackgroundItem(0),
+    mOpenTimeLine(DialpadOpenAnimDuration),
+    mCloseTimeLine(DialpadCloseAnimDuration),
+    mAnimationOngoing(false),
+    mOrientation(Qt::Vertical),
+    mIsOpen(false)
+{
+    // this constuctor is deprecated
+    initialize();
+}
+
+Dialpad::Dialpad(const HbMainWindow& mainWindow) :
+    mMainWindow(mainWindow),
+    mBackgroundItem(0),
+    mOpenTimeLine(DialpadOpenAnimDuration),
+    mCloseTimeLine(DialpadCloseAnimDuration),
+    mAnimationOngoing(false),
+    mOrientation(Qt::Vertical),
+    mIsOpen(false)
+{
+    initialize();
+}
+
+void Dialpad::initialize()
+{
+    setFocusPolicy(Qt::StrongFocus);
+    setFlag(QGraphicsItem::ItemIsFocusable,true);
+    setFlag(QGraphicsItem::ItemHasNoContents, false);
+
+    // create input field
+    mInputField = new DialpadInputField(this);
+
+    // create keypad
+    mKeypad = new DialpadKeypad(mMainWindow,*mInputField,this);
+
+    // layouting params
+    qreal unit = HbDeviceProfile::current().unitValue();
+    qreal margin = DialpadComponentMargin * unit;
+    mCloseHandleHeight = DialpadCloseHandleHeight * unit;
+    mCloseHandleWidth = DialpadCloseHandleWidth * unit;
+
+    mKeypad->callButton().setPreferredHeight(DialpadCallButtonHeight*unit);
+    mKeypad->callButton().setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+
+    // create popup background
+    mBackgroundDrawer = new HbFrameDrawer();
+    mIconDrawer = new HbFrameDrawer();
+
+    // popup layout
+    QGraphicsLinearLayout* popupLayout =
+        new QGraphicsLinearLayout(Qt::Vertical);
+    popupLayout->addItem(mInputField);
+    popupLayout->addItem(mKeypad);
+    popupLayout->addItem(&mKeypad->callButton());
+    popupLayout->setContentsMargins(margin, mCloseHandleHeight, margin, margin);
+    popupLayout->setSpacing(0);
+    popupLayout->setItemSpacing(0,margin);
+    setLayout(popupLayout);
+    setLayoutDirection(Qt::LeftToRight);
+
+    // asterisk multitap handler
+    mMultitap = new DialpadMultitapHandler(mInputField->editor(),this);
+    mInputField->editor().installEventFilter(mMultitap);
+
+    // close animation
+    mCloseTimeLine.setUpdateInterval(16);
+    mCloseTimeLine.setEasingCurve(QEasingCurve::InQuad);
+    connect(&mCloseTimeLine, SIGNAL(finished()),
+            SLOT(closeAnimFinished()));
+    connect(&mCloseTimeLine, SIGNAL(valueChanged(qreal)),
+            SLOT(closeAnimValueChanged(qreal)));
+
+    // open animation
+    mOpenTimeLine.setUpdateInterval(16);
+    mOpenTimeLine.setEasingCurve(QEasingCurve::OutQuad);
+    connect(&mOpenTimeLine, SIGNAL(finished()),
+            SLOT(openAnimFinished()));
+    connect(&mOpenTimeLine, SIGNAL(valueChanged(qreal)),
+            SLOT(openAnimValueChanged(qreal)));
+
+    // default values
+    setPos(0,0);
+    setPreferredSize(360,360);
+    setZValue(0x00004000); // Hb PopupZValueRangeStart
+    hide();
+    mMainWindow.scene()->addItem(this);
+
+    // custom button style
+    HbStyleLoader::registerFilePath(QLatin1String(":/dialpad.css"));
+    HbStyleLoader::registerFilePath(QLatin1String(":/dialpad_color.css"));
+
+    // grab gestures so that those are not passed to widgets behind dialpad
+    grabGesture(Qt::TapGesture);
+    grabGesture(Qt::TapAndHoldGesture);
+    grabGesture(Qt::PanGesture);
+    grabGesture(Qt::SwipeGesture);
+    grabGesture(Qt::PinchGesture);
+
+    // effects
+    HbEffect::add(this, DIALPAD_TO_PRT_FXML, DIALPAD_TO_PRT_EVENT);
+    HbEffect::add(this, DIALPAD_TO_LSC_FXML, DIALPAD_TO_LSC_EVENT);
+}
+
+Dialpad::~Dialpad()
+{
+    delete mBackgroundDrawer;
+    delete mIconDrawer;
+    delete mBackgroundItem;
+}
+
+void Dialpad::paint(
+    QPainter* painter,
+    const QStyleOptionGraphicsItem* option,
+    QWidget* widget)
+{
+    Q_UNUSED(option);
+    Q_UNUSED(widget);
+
+    // paint popup background
+    if ( mOrientation == Qt::Vertical ) {
+        mBackgroundDrawer->setFrameGraphicsName(backgroundGraphics);
+        mIconDrawer->setFrameGraphicsName(minimizeIcon);
+        mBackgroundDrawer->setFrameType(HbFrameDrawer::ThreePiecesVertical);
+        mBackgroundDrawer->setBorderWidths(0.0, mCloseHandleHeight, 0.0, 0.0);
+    } else {
+        mBackgroundDrawer->setFrameGraphicsName(backgroundGraphicsH);
+        mIconDrawer->setFrameGraphicsName(minimizeIconH);
+        mBackgroundDrawer->setFrameType(HbFrameDrawer::ThreePiecesHorizontal);
+        mBackgroundDrawer->setBorderWidths(mCloseHandleHeight, 0.0, 0.0, 0.0);
+    }
+
+    // draw background
+    QRectF rect = boundingRect();
+    mBackgroundDrawer->setFillWholeRect(true);
+    mBackgroundDrawer->paint(painter, rect);
+
+    // adjust rectangle to close bar position
+    if ( mOrientation == Qt::Vertical ) {
+        rect.setLeft((rect.width()- mCloseHandleWidth)/2);
+        rect.setWidth(mCloseHandleWidth);
+        rect.setHeight(mCloseHandleHeight);
+    } else {
+        rect.setTop((rect.height() - mCloseHandleWidth)/2);
+        rect.setWidth(mCloseHandleHeight);
+        rect.setHeight(mCloseHandleWidth);
+    }
+
+    mIconDrawer->setFrameType(HbFrameDrawer::OnePiece);
+    mIconDrawer->paint(painter, rect);
+}
+
+void Dialpad::changeEvent(QEvent *event)
+{
+    if (event->type() == QEvent::LayoutDirectionChange) {
+        mBackgroundDrawer->setLayoutDirection(layoutDirection());
+    } else if (event->type() == HbEvent::ThemeChanged) {
+        mBackgroundDrawer->themeChanged();
+        mIconDrawer->themeChanged();
+    }
+}
+
+bool Dialpad::isOpen() const
+{
+    return mIsOpen;
+}
+
+bool Dialpad::isCallButtonEnabled() const
+{
+    return mKeypad->callButton().isEnabled();
+}
+
+void Dialpad::openDialpad()
+{
+    mKeypad->resetButtons();
+    
+    if (mIsOpen) {
+        return;
+    }
+
+    connect(&mMainWindow,SIGNAL(aboutToChangeOrientation()),
+            SLOT(orientationChangeStarted()));
+    connect(&mMainWindow,SIGNAL(orientationChanged(Qt::Orientation)),
+            SLOT(orientationChangeFinished(Qt::Orientation)));
+
+    // set offset for open animation
+    int previousOrientation = mOrientation;
+    mOrientation = mMainWindow.orientation();
+
+    mPosition = pos();
+    if (mOrientation==Qt::Vertical) {
+        qreal height = geometry().height();
+        setPos(mPosition.x(),mPosition.y()+height);
+    } else {
+        qreal width = geometry().width();
+        setPos(mPosition.x()+width,mPosition.y());
+    }
+
+    if (mOrientation!=previousOrientation) {
+        updateLayout((Qt::Orientation)mOrientation);
+    }
+
+    show();
+
+    setFocusProxy(&mInputField->editor());
+    mInputField->editor().setFocus();
+
+    mOpenTimeLine.start();
+    mAnimationOngoing = true;
+    if (!mInputField->editor().text().isEmpty()) {
+        setCallButtonEnabled(true);
+    }
+    mIsOpen = true;
+
+    emit aboutToOpen();
+}
+
+void Dialpad::closeDialpad()
+{
+    close();
+
+    disconnect(&mMainWindow,SIGNAL(aboutToChangeOrientation()),
+               this, SLOT(orientationChangeStarted()));
+    disconnect(&mMainWindow,SIGNAL(orientationChanged(Qt::Orientation)),
+               this, SLOT(orientationChangeFinished(Qt::Orientation)));
+
+    if (mBackgroundItem) {
+        mBackgroundItem->hide();
+    }
+}    
+
+HbLineEdit& Dialpad::editor() const
+{
+    return mInputField->editor();
+}
+
+void Dialpad::setCallButtonEnabled(bool enabled)
+{
+    mKeypad->setCallButtonEnabled(enabled);
+}
+
+void Dialpad::setTapOutsideDismiss(bool dismiss)
+{
+    // set dismiss policy before opening dialpad
+    Q_ASSERT(!isVisible());
+
+    if (dismiss) {
+        mBackgroundItem = new DialpadBackground(*this);
+        mBackgroundItem->setZValue(zValue()-1);
+        mMainWindow.scene()->addItem(mBackgroundItem);
+        qreal chromeHeight = 0;
+        hbInstance->style()->parameter(QLatin1String("hb-param-widget-chrome-height"),
+                                       chromeHeight);
+        mTitleBarHeight = chromeHeight;
+    } else {
+        delete mBackgroundItem;
+        mBackgroundItem = 0;
+    }
+}
+
+void Dialpad::startCloseAnimation()
+{
+    if (!mAnimationOngoing) {
+        mCloseTimeLine.start();
+        mAnimationOngoing = true;
+   }
+}
+
+void Dialpad::showEvent(QShowEvent *event)
+{
+    HbWidget::showEvent(event);
+
+    if (mBackgroundItem) {
+        layoutBackgroundItem();
+        mBackgroundItem->show();
+    }
+}
+
+void Dialpad::hideEvent(QHideEvent *event)
+{
+    HbWidget::hideEvent(event);
+}
+
+void Dialpad::closeEvent(QCloseEvent * event)
+{
+    mIsOpen = false;
+    HbWidget::closeEvent(event);
+    emit aboutToClose();
+}
+
+void Dialpad::closeAnimValueChanged(qreal value)
+{
+    QPointF currentPos = pos();
+    QPointF newPos;
+
+    if (mOrientation==Qt::Vertical) {
+        qreal height = geometry().height();
+
+        newPos.setX(currentPos.x());
+        newPos.setY(mPosition.y()+(height*value));
+    } else {
+        qreal width = geometry().width();
+
+        newPos.setY(currentPos.y());
+        newPos.setX(mPosition.x()+(width*value));
+    }
+
+    setPos(newPos);
+}
+
+
+void Dialpad::closeAnimFinished()
+{
+    mAnimationOngoing = false;
+    closeDialpad();
+    setPos(mPosition);
+}
+
+void Dialpad::openAnimValueChanged(qreal value)
+{
+    QPointF currentPos = pos();
+    QPointF newPos;
+
+    if (mOrientation==Qt::Vertical) {
+        qreal height = geometry().height();
+
+        newPos.setX(currentPos.x());
+        newPos.setY(mPosition.y()+(height*(1-value)));
+    } else {
+        qreal width = geometry().width();
+
+        newPos.setY(currentPos.y());
+        newPos.setX(mPosition.x()+(width*(1-value)));
+    }
+
+    setPos(newPos);
+}
+
+void Dialpad::openAnimFinished()
+{
+    mAnimationOngoing = false;    
+    setPos(mPosition);      
+}
+
+void Dialpad::orientationChangeStarted()
+{
+    hide();
+}
+
+void Dialpad::orientationChangeFinished(Qt::Orientation current)
+{
+    updateLayout(current);
+
+    show();
+
+    // run orientation change effect
+    if (current==Qt::Horizontal) {
+        HbEffect::start(this, DIALPAD_TO_LSC_EVENT);
+    } else {
+        HbEffect::start(this, DIALPAD_TO_PRT_EVENT);
+    }
+
+    mOrientation = current;
+
+    mPosition = pos();
+
+    if (mBackgroundItem) {
+        layoutBackgroundItem();
+    }
+}
+
+void Dialpad::layoutBackgroundItem()
+{
+    Q_ASSERT(mBackgroundItem);
+    QRectF backgroundRect(mMainWindow.layoutRect());
+    backgroundRect.adjust(0,mTitleBarHeight,0,0);
+    mBackgroundItem->setRect(backgroundRect);
+}
+
+void Dialpad::updateLayout(Qt::Orientation orientation)
+{
+    Q_ASSERT(layout());
+
+    qreal unit = HbDeviceProfile::current().unitValue();
+    qreal margin = DialpadComponentMargin * unit;
+
+    QGraphicsLinearLayout* mainLayout =
+        static_cast<QGraphicsLinearLayout*>(layout());
+
+    // close handle location changes, update margin values
+    if (orientation==Qt::Vertical) {
+        mainLayout->setContentsMargins(margin,
+                                       mCloseHandleHeight,
+                                       margin,
+                                       margin);
+        mKeypad->callButton().setPreferredHeight(DialpadCallButtonHeight*unit);
+    } else {
+        mainLayout->setContentsMargins(mCloseHandleHeight,
+                                       margin,
+                                       margin,
+                                       margin);
+        mKeypad->callButton().setPreferredHeight(DialpadCallButtonHeightH*unit);
+    }
+}
+
+void Dialpad::gestureEvent(QGestureEvent *event)
+{
+    bool closeGesture(false);
+
+    if(HbSwipeGesture *gesture = qobject_cast<HbSwipeGesture*>(
+           event->gesture(Qt::SwipeGesture))) {
+        if (gesture->state() == Qt::GestureFinished) {
+            if ( mOrientation==Qt::Vertical &&
+                 gesture->sceneVerticalDirection() == QSwipeGesture::Down ) {
+                closeGesture = true;
+            } else if (mOrientation==Qt::Horizontal &&
+                gesture->sceneHorizontalDirection() == QSwipeGesture::Right) {
+                closeGesture = true;
+            }
+        }
+    }
+
+    if (closeGesture) {
+        startCloseAnimation();
+        event->accept();
+    } else {
+        event->ignore();
+    }
+}