--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbinput/inputwidgets/hbinputbuttongroup.cpp Fri May 14 16:09:54 2010 +0300
@@ -0,0 +1,1764 @@
+/****************************************************************************
+**
+** 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 HbInput 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 <QPainter>
+#include <QTextLayout>
+#include <QGraphicsSceneMouseEvent>
+#include <QTouchEvent>
+#include <QTimer>
+#include <QGraphicsDropShadowEffect>
+
+#include <hbmainwindow.h>
+#include <hbaction.h>
+#include <hbevent.h>
+#include <hbcolorscheme.h>
+#include <hbdialog.h>
+#include <hbframeitem.h>
+#include <hbwidgetfeedback.h>
+#include <hbdeviceprofile.h>
+#include "hbframedrawerpool_p.h"
+
+#include "hbinputbuttongroup.h"
+#include "hbinputbuttongroup_p.h"
+#include "hbinputbutton.h"
+
+/// @cond
+
+const QString HbNormalBackground("qtg_fr_input_btn_keypad_normal");
+const QString HbNormalPressedBackground("qtg_fr_input_btn_keypad_pressed");
+const QString HbNormalInActiveBackground("qtg_fr_input_btn_keypad_disabled");
+const QString HbNormalLatchedBackground("qtg_fr_input_btn_keypad_latched");
+
+const QString HbFunctionBackground("qtg_fr_input_btn_function_normal");
+const QString HbFunctionPressedBackground("qtg_fr_input_btn_function_pressed");
+const QString HbFunctionInActiveBackground("qtg_fr_input_btn_function_disabled");
+const QString HbFunctionLatchedBackground("qtg_fr_input_btn_function_latched");
+
+const QString HbPreviewBackground("qtg_fr_character_preview");
+
+const QString HbNormalColor("qtc_input_button_normal");
+const QString HbNormalColorPressed("qtc_input_button_pressed");
+const QString HbNormalColorInActive("qtc_input_button_disabled");
+const QString HbNormalColorLatched("qtc_input_button_latched");
+
+const QString HbFunctionColor("qtc_input_function_normal");
+const QString HbFunctionColorPressed("qtc_input_function_pressed");
+const QString HbFunctionColorInActive("qtc_input_function_disabled");
+const QString HbFunctionColorLatched("qtc_input_function_latched");
+
+const QString HbButtonPreviewColor("qtc_input_preview_normal");
+const QString HbCharacterSelectionPreviewColor("qtc_input_button_accented_normal");
+
+const int HbLongPressTimeout = 600;
+const int HbAutoRepeatTimeout = 100;
+
+const int HbTextTypeCount = HbInputButton::ButtonTypeCount * HbInputButton::ButtonStateCount;
+const int HbTextLayoutCount = HbTextTypeCount * 3;
+
+const qreal HbTextSizeInUnits = 5.75;
+const qreal HbPrimaryTextSizeInUnits = 5.37;
+const qreal HbSecondaryTextSizeInUnits = 3.36;
+const qreal HbLabelTextSizeInUnits = 9;
+const qreal HbPrimaryIconSizeInUnits = 5;
+const qreal HbSecondaryIconSizeInUnits = 3.36;
+const qreal HbHorizontalMarginInUnits = 0.75;
+const qreal HbVerticalMarginInUnits = 1.14;
+const qreal HbPreviewWidthInUnits = 10;
+const qreal HbPreviewHeightInUnits = 16;
+const qreal HbPreviewMarginInUnits = 3;
+
+const qreal HbTouchAreaSizeInUnits = 8;
+
+HbInputButtonGroupPrivate::HbInputButtonGroupPrivate()
+ : mUnitValue(0), mGridSize(1, 1), mButtonBorderSize(1.0), mEnabled(true),
+ mButtonPreviewEnabled(false), mCharacterSelectionPreviewEnabled(false),
+ mMultiTouchEnabled(true), mCharacterSelectionPreview(0), mBackground(0)
+{
+ for (int i = 0; i < HbTextLayoutCount; ++i) {
+ mTextLayouts.append(0);
+ }
+
+ updateColorArray();
+}
+
+HbInputButtonGroupPrivate::~HbInputButtonGroupPrivate()
+{
+ foreach(HbFrameDrawer *drawer, mButtonDrawers) {
+ HbFrameDrawerPool::release(drawer);
+ }
+
+ foreach (HbInputButton *button, mButtonData) {
+ delete button;
+ }
+ mButtonData.clear();
+
+ foreach (QTextLayout *layout, mTextLayouts) {
+ delete layout;
+ }
+
+ foreach (QTimer *timer, mLongPressTimers) {
+ delete timer;
+ }
+
+ delete mCharacterSelectionPreview;
+
+ HbFrameDrawerPool::release(mBackground);
+}
+
+void HbInputButtonGroupPrivate::updateGraphics(const QSizeF &size)
+{
+ if (!size.width() && !size.height()) {
+ return;
+ }
+
+ qreal cellWidth = size.width() / mGridSize.width();
+ qreal cellHeight = size.height() / mGridSize.height();
+
+ for (int i = 0; i < mButtonData.count(); ++i) {
+ HbInputButton *item = mButtonData.at(i);
+
+ qreal width = cellWidth * item->size().width() - 2 * mButtonBorderSize;
+ qreal height = cellHeight * item->size().height() - 2 * mButtonBorderSize;
+ QSizeF frameSize = QSizeF(width, height);
+ HbFrameDrawer *drawer = 0;
+ QColor color;
+ if (mEnabled) {
+ drawer = HbFrameDrawerPool::get(buttonGraphics(item->type(), item->state()), HbFrameDrawer::NinePieces, frameSize);
+ color = mColors.at(item->type() * HbInputButton::ButtonStateCount + item->state());
+ } else {
+ drawer = HbFrameDrawerPool::get(buttonGraphics(item->type(), HbInputButton::ButtonStateDisabled), HbFrameDrawer::NinePieces, frameSize);
+ color = mColors.at(item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled);
+ }
+
+ if (i < mButtonDrawers.count()) {
+ if (drawer != mButtonDrawers.at(i)) {
+ HbFrameDrawerPool::release(mButtonDrawers.at(i));
+ mButtonDrawers.replace(i, drawer);
+ }
+ } else {
+ mButtonDrawers.append(drawer);
+ }
+
+ QList<HbIcon> icons = item->icons();
+ for (int i = 0; i < icons.count(); ++i) {
+ if (!icons.at(i).isNull()) {
+ icons[i].setColor(color);
+ }
+ }
+ item->setIcons(icons);
+ }
+
+ for (int i = mButtonDrawers.count() - 1; i >= mButtonData.count(); --i) {
+ HbFrameDrawerPool::release(mButtonDrawers.at(i));
+ mButtonDrawers.removeAt(i);
+ }
+}
+
+void HbInputButtonGroupPrivate::updateTextLayouts(const QSizeF &size)
+{
+ if (!size.width() && !size.height()) {
+ return;
+ }
+
+ QHash<int, QString> textContent;
+ for (int i = 0; i < HbTextLayoutCount; ++i) {
+ delete mTextLayouts[i];
+ mTextLayouts[i] = 0;
+ }
+
+ // Sort different button texts to correct text content based on the
+ // button type and state
+ for (int i = 0; i < mButtonData.count(); ++i) {
+ HbInputButton *item = mButtonData.at(i);
+
+ int index = item->type() * HbInputButton::ButtonStateCount + item->state();
+ if (!mEnabled) {
+ index = item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled;
+ }
+
+ if (!item->text(HbInputButton::ButtonTextIndexPrimary).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexPrimary).isNull()) {
+ int primaryIndex = index;
+ if (item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull() &&
+ item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+ primaryIndex += HbTextTypeCount;
+ }
+ textContent[primaryIndex] += item->text(HbInputButton::ButtonTextIndexPrimary);
+ textContent[primaryIndex] += QChar(QChar::LineSeparator);
+ }
+
+ index += HbTextTypeCount * 2;
+
+ if (!item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull()) {
+ textContent[index] += item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow);
+ textContent[index] += QChar(QChar::LineSeparator);
+ }
+
+ if (!item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+ textContent[index] += item->text(HbInputButton::ButtonTextIndexSecondarySecondRow);
+ textContent[index] += QChar(QChar::LineSeparator);
+ }
+ }
+
+ // Create text layouts for each text content
+ for (int index = 0; index < HbTextLayoutCount; ++index) {
+ if (textContent.contains(index)) {
+ int textIndex = index / HbTextTypeCount;
+ if (textIndex == 0) {
+ createPrimaryTextLayout(index, textContent, size);
+ } else if (textIndex == 1) {
+ createPrimarySingleTextLayout(index, textContent, size);
+ } else {
+ createSecondaryTextLayout(index, textContent, size);
+ }
+ }
+ }
+}
+
+void HbInputButtonGroupPrivate::updateCustomActions()
+{
+ for (int i = 0; i < mUsedCustomButtons.count(); ++i) {
+ if (i < mButtonData.count()) {
+ HbInputButton *item = mButtonData.at(mUsedCustomButtons.at(i));
+
+ item->setIcon(HbIcon(), HbInputButton::ButtonIconIndexPrimary);
+ item->setText(QString(), HbInputButton::ButtonTextIndexPrimary);
+ item->setText(QString(), HbInputButton::ButtonTextIndexSecondaryFirstRow);
+ item->setText(QString(), HbInputButton::ButtonTextIndexSecondarySecondRow);
+ item->setState(HbInputButton::ButtonStateReleased);
+ }
+ }
+ mUsedCustomButtons.clear();
+
+ for (int i = 0; i < mButtonData.count(); ++i) {
+ HbInputButton *item = mButtonData.at(i);
+
+ int actionIndex = item->keyCode() - HbInputButton::ButtonKeyCodeCustom;
+
+ if (actionIndex >= 0 && actionIndex < mCustomActions.count()) {
+ item->setIcon(mCustomActions.at(actionIndex)->icon(), HbInputButton::ButtonIconIndexPrimary);
+ if (!mCustomActions.at(actionIndex)->isEnabled()) {
+ item->setState(HbInputButton::ButtonStateDisabled);
+ }
+ mUsedCustomButtons.append(i);
+ }
+ }
+}
+
+void HbInputButtonGroupPrivate::updateButtonGrid(const QSizeF &size)
+{
+ mButtonGridPositions.clear();
+
+ if (!size.width() && !size.height()) {
+ return;
+ }
+
+ qreal cellWidth = size.width() / mGridSize.width();
+ qreal cellHeight = size.height() / mGridSize.height();
+
+ for (int i = 0; i < mButtonData.count(); ++i) {
+ HbInputButton *item = mButtonData.at(i);
+
+ for (int y = 0; y < item->size().height(); ++y) {
+ for (int x = 0; x < item->size().width(); ++x) {
+ QPair<int, int> position = QPair<int, int>(item->position().x() + x, item->position().y() + y);
+ mButtonGridPositions.insert(position, i);
+ }
+ }
+ QRectF rect = QRectF(item->position().x() * cellWidth, item->position().y() * cellHeight,
+ item->size().width() * cellWidth, item->size().height() * cellHeight);
+ item->setBoundingRect(rect);
+ }
+}
+
+void HbInputButtonGroupPrivate::updateColorArray()
+{
+ mColors.clear();
+ for (int i = 0; i < HbTextTypeCount; ++i) {
+ HbInputButton::HbInputButtonType type = static_cast<HbInputButton::HbInputButtonType>(i / HbInputButton::ButtonStateCount);
+ HbInputButton::HbInputButtonState state = static_cast<HbInputButton::HbInputButtonState>(i % HbInputButton::ButtonStateCount);
+ mColors.append(HbColorScheme::color(buttonColor(type, state)));
+ }
+}
+
+void HbInputButtonGroupPrivate::showButtonPreview(HbInputButton * const item)
+{
+ Q_Q(HbInputButtonGroup);
+
+ int index = mButtonData.indexOf(item);
+ if (mButtonPreviewEnabled && item->type() != HbInputButton::ButtonTypeFunction &&
+ !mButtonPreview.contains(index)) {
+ HbInputButtonGroup *group = new HbInputButtonGroup(QSize(1, 1), q);
+ mButtonPreview.insert(index, group);
+
+ QList<HbInputButton*> buttons;
+ HbInputButton *previewItem = new HbInputButton(item->text(HbInputButton::ButtonTextIndexPrimary).at(0).unicode(), QPoint(0, 0));
+ previewItem->setType(HbInputButton::ButtonTypeLabel);
+ previewItem->setText(item->text(HbInputButton::ButtonTextIndexPrimary), HbInputButton::ButtonTextIndexPrimary);
+ buttons.append(previewItem);
+ group->setButtons(buttons);
+
+ qreal cellWidth = q->boundingRect().width() / mGridSize.width();
+ qreal cellHeight = q->boundingRect().height() / mGridSize.height();
+
+ QFont font = HbFontSpec(HbFontSpec::Primary).font();
+ font.setPixelSize(fontSize(ButtonTextTypeLabel));
+ QFontMetricsF fontMetrics(font);
+ qreal textWidth = fontMetrics.width(item->text(HbInputButton::ButtonTextIndexPrimary));
+
+ qreal width = textWidth + HbPreviewMarginInUnits * mUnitValue;
+ if (width < HbPreviewWidthInUnits * mUnitValue) {
+ width = HbPreviewWidthInUnits * mUnitValue;
+ }
+ qreal height = HbPreviewHeightInUnits * mUnitValue;
+ qreal x = (item->position().x() + 0.5 * item->size().width()) * cellWidth - 0.5 * width;
+ if (x < 0) {
+ x = 0;
+ } else if (x + width > q->boundingRect().width()) {
+ x = q->boundingRect().width() - width;
+ }
+ qreal y = item->position().y() * cellHeight - height;
+ group->setGeometry(QRectF(x, y, width, height));
+ if (q->parentItem()) {
+ group->setZValue(q->parentItem()->zValue() + 1);
+ }
+
+ QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect;
+ effect->setBlurRadius(8);
+ group->setGraphicsEffect(effect);
+
+ group->setButtonBorderSize(0);
+ HbFrameDrawer *drawer = HbFrameDrawerPool::get(HbPreviewBackground, HbFrameDrawer::ThreePiecesHorizontal, QSizeF(width, height));
+ drawer->setFillWholeRect(true);
+ group->setBackground(drawer);
+ q->mainWindow()->scene()->addItem(group);
+ }
+}
+
+void HbInputButtonGroupPrivate::hideButtonPreview(HbInputButton * const item)
+{
+ int index = mButtonData.indexOf(item);
+ if (mButtonPreview.contains(index)) {
+ delete mButtonPreview.take(index);
+ }
+}
+
+void HbInputButtonGroupPrivate::showCharacterSelectionPreview(HbInputButton * const item)
+{
+ Q_Q(HbInputButtonGroup);
+
+ if (mCharacterSelectionPreviewEnabled && item->type() != HbInputButton::ButtonTypeFunction &&
+ item->mappedCharacters().count() > 1) {
+
+ mProbabilities.clear();
+ q->cancelButtonPress();
+
+ if (!mCharacterSelectionPreview) {
+ mCharacterSelectionPreview = new HbDialog();
+ mCharacterSelectionPreview->setModal(true);
+ mCharacterSelectionPreview->setBackgroundFaded(false);
+ mCharacterSelectionPreview->setTimeout(HbPopup::NoTimeout);
+ mCharacterSelectionPreview->setDismissPolicy(HbPopup::TapAnywhere);
+ mCharacterSelectionPreview->setFlag(QGraphicsItem::ItemIsPanel, true);
+ mCharacterSelectionPreview->setActive(false);
+ qreal margin = HbPreviewMarginInUnits * mUnitValue * 0.5;
+ mCharacterSelectionPreview->setContentsMargins(margin, 0, margin, 0);
+ QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect;
+ effect->setBlurRadius(8);
+ mCharacterSelectionPreview->setGraphicsEffect(effect);
+ }
+
+ HbInputButtonGroup *group = new HbInputButtonGroup(QSize(item->mappedCharacters().count(), 1));
+ QObject::connect(group, SIGNAL(buttonPressed(const QKeyEvent&)), q, SLOT(emitButtonPressed(const QKeyEvent&)));
+ QObject::connect(group, SIGNAL(buttonDoublePressed(const QKeyEvent&)), q, SLOT(emitButtonDoublePressed(const QKeyEvent&)));
+ QObject::connect(group, SIGNAL(buttonReleased(const QKeyEvent&)), q, SLOT(emitButtonReleased(const QKeyEvent&)));
+ QObject::connect(group, SIGNAL(buttonLongPressed(const QKeyEvent&)), q, SLOT(emitButtonLongPressed(const QKeyEvent&)));
+ QObject::connect(group, SIGNAL(pressedButtonChanged(const QKeyEvent&, const QKeyEvent&)), q, SLOT(emitPressedButtonChanged(const QKeyEvent&, const QKeyEvent&)));
+
+ qreal cellWidth = q->boundingRect().width() / mGridSize.width();
+ qreal cellHeight = q->boundingRect().height() / mGridSize.height();
+
+ QFont font = HbFontSpec(HbFontSpec::Primary).font();
+ font.setPixelSize(fontSize(ButtonTextTypeLabel));
+ QFontMetricsF fontMetrics(font);
+ qreal textWidth = fontMetrics.width(item->mappedCharacters());
+
+ qreal width = textWidth + HbPreviewMarginInUnits * mUnitValue * item->mappedCharacters().count();
+ qreal height = HbPreviewHeightInUnits * mUnitValue;
+ qreal x = q->scenePos().x() + (item->position().x() + 0.5 * item->size().width()) * cellWidth;
+ qreal y = q->scenePos().y() + item->position().y() * cellHeight;
+
+ QList<HbInputButton*> buttons;
+ for (int i = 0; i < item->mappedCharacters().count(); ++i) {
+ HbInputButton *previewItem = new HbInputButton(item->keyCode(), QPoint(i, 0));
+ previewItem->setType(HbInputButton::ButtonTypeLabel);
+ previewItem->setText(item->mappedCharacters().at(i), HbInputButton::ButtonTextIndexPrimary);
+ buttons.append(previewItem);
+ }
+ group->setButtons(buttons);
+ group->setButtonBorderSize(0);
+
+ mCharacterSelectionPreview->setPreferredSize(QSizeF(width, height));
+ mCharacterSelectionPreview->setPreferredPos(QPointF(x, y), HbPopup::BottomEdgeCenter);
+ mCharacterSelectionPreview->setContentWidget(group);
+
+ HbFrameDrawer *drawer = HbFrameDrawerPool::get(HbPreviewBackground, HbFrameDrawer::ThreePiecesHorizontal, QSizeF(width, height));
+ drawer->setFillWholeRect(true);
+ mCharacterSelectionPreview->setBackgroundItem(new HbFrameItem(drawer));
+
+ mCharacterSelectionPreview->show();
+ }
+}
+
+void HbInputButtonGroupPrivate::pressEvent(const QPointF &position, bool emitSignal)
+{
+ Q_Q(HbInputButtonGroup);
+
+ if (!(position.x() >= 0 && position.x() < q->boundingRect().width() &&
+ position.y() >= 0 && position.y() < q->boundingRect().height())) {
+ return;
+ }
+
+ int column = static_cast<int>(position.x() / (q->boundingRect().width() / mGridSize.width()));
+ int row = static_cast<int>(position.y() / (q->boundingRect().height() / mGridSize.height()));
+
+ int index = mButtonGridPositions.value(QPair<int, int>(column, row));
+
+ if (index >= 0 && index < mButtonData.count()) {
+ HbInputButton *item = mButtonData.at(index);
+
+ if ((item->state() != HbInputButton::ButtonStateReleased &&
+ item->state() != HbInputButton::ButtonStateLatched) ||
+ (mCharacterSelectionPreview && mCharacterSelectionPreview->isVisible())) {
+ if (item->state() == HbInputButton::ButtonStateDisabled) {
+ startLongPress(index);
+ }
+ return;
+ }
+
+ HbWidgetFeedback::triggered(q, Hb::InstantPressed);
+
+ item->setState(HbInputButton::ButtonStatePressed);
+ updateGraphics(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+ updateTextLayouts(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+ q->update();
+
+ showButtonPreview(item);
+
+ startLongPress(index);
+
+ if (!mUsedCustomButtons.contains(index)) {
+ if (emitSignal) {
+ QString text;
+ if (item->type() == HbInputButton::ButtonTypeLabel) {
+ text = item->text(HbInputButton::ButtonTextIndexPrimary);
+ }
+ QKeyEvent event(QEvent::KeyPress, item->keyCode(), Qt::NoModifier, text);
+ q->emitButtonPressed(event);
+ }
+ }
+ }
+}
+
+void HbInputButtonGroupPrivate::doublePressEvent(const QPointF &position, bool emitSignal)
+{
+ Q_Q(HbInputButtonGroup);
+
+ if (!(position.x() >= 0 && position.x() < q->boundingRect().width() &&
+ position.y() >= 0 && position.y() < q->boundingRect().height())) {
+ return;
+ }
+
+ int column = static_cast<int>(position.x() / (q->boundingRect().width() / mGridSize.width()));
+ int row = static_cast<int>(position.y() / (q->boundingRect().height() / mGridSize.height()));
+
+ int index = mButtonGridPositions.value(QPair<int, int>(column, row));
+
+ if (index >= 0 && index < mButtonData.count()) {
+ HbInputButton *item = mButtonData.at(index);
+
+ if ((item->state() != HbInputButton::ButtonStateReleased &&
+ item->state() != HbInputButton::ButtonStateLatched) ||
+ (mCharacterSelectionPreview && mCharacterSelectionPreview->isVisible())) {
+ if (item->state() == HbInputButton::ButtonStateDisabled) {
+ startLongPress(index);
+ }
+ return;
+ }
+
+ HbWidgetFeedback::triggered(q, Hb::InstantPressed);
+
+ item->setState(HbInputButton::ButtonStatePressed);
+ updateGraphics(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+ updateTextLayouts(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+ q->update();
+
+ showButtonPreview(item);
+
+ startLongPress(index);
+
+ if (!mUsedCustomButtons.contains(index)) {
+ if (emitSignal) {
+ QString text;
+ if (item->type() == HbInputButton::ButtonTypeLabel) {
+ text = item->text(HbInputButton::ButtonTextIndexPrimary);
+ }
+ QKeyEvent event(QEvent::KeyPress, item->keyCode(), Qt::NoModifier, text);
+ q->emitButtonDoublePressed(event);
+ }
+ }
+ }
+}
+
+void HbInputButtonGroupPrivate::moveEvent(const QPointF &oldPosition, const QPointF &newPosition)
+{
+ Q_Q(HbInputButtonGroup);
+
+ int oldColumn = static_cast<int>(oldPosition.x() / (q->boundingRect().width() / mGridSize.width()));
+ int oldRow = static_cast<int>(oldPosition.y() / (q->boundingRect().height() / mGridSize.height()));
+ int newColumn = static_cast<int>(newPosition.x() / (q->boundingRect().width() / mGridSize.width()));
+ int newRow = static_cast<int>(newPosition.y() / (q->boundingRect().height() / mGridSize.height()));
+
+ int oldIndex = mButtonGridPositions.value(QPair<int, int>(oldColumn, oldRow));
+ int newIndex = mButtonGridPositions.value(QPair<int, int>(newColumn, newRow));
+
+ if (newPosition.x() >= 0 && newPosition.x() < q->boundingRect().width() &&
+ newPosition.y() >= 0 && newPosition.y() < q->boundingRect().height() &&
+ oldPosition.x() >= 0 && oldPosition.x() < q->boundingRect().width() &&
+ oldPosition.y() >= 0 && oldPosition.y() < q->boundingRect().height()) {
+
+ if (oldIndex != newIndex) {
+ releaseEvent(oldPosition, false);
+ pressEvent(newPosition, false);
+
+ QString text;
+ HbInputButton *oldItem = mButtonData.at(oldIndex);
+ if (oldItem->type() == HbInputButton::ButtonTypeLabel) {
+ text = oldItem->text(HbInputButton::ButtonTextIndexPrimary);
+ }
+ QKeyEvent releaseEvent(QEvent::KeyRelease, oldItem->keyCode(), Qt::NoModifier, text);
+
+ HbInputButton *newItem = mButtonData.at(newIndex);
+ if (newItem->type() == HbInputButton::ButtonTypeLabel) {
+ text = newItem->text(HbInputButton::ButtonTextIndexPrimary);
+ }
+ QKeyEvent pressEvent(QEvent::KeyPress, newItem->keyCode(), Qt::NoModifier, text);
+
+ q->emitPressedButtonChanged(releaseEvent, pressEvent);
+ }
+ } else {
+ releaseEvent(oldPosition, false);
+ pressEvent(newPosition);
+ }
+}
+
+void HbInputButtonGroupPrivate::releaseEvent(const QPointF &position, bool emitSignal)
+{
+ Q_Q(HbInputButtonGroup);
+
+ if (!(position.x() >= 0 && position.x() < q->boundingRect().width() &&
+ position.y() >= 0 && position.y() < q->boundingRect().height())) {
+ return;
+ }
+
+ int column = static_cast<int>(position.x() / (q->boundingRect().width() / mGridSize.width()));
+ int row = static_cast<int>(position.y() / (q->boundingRect().height() / mGridSize.height()));
+
+ int index = mButtonGridPositions.value(QPair<int, int>(column, row));
+
+ if (index >= 0 && index < mButtonData.count()) {
+ HbInputButton *item = mButtonData.at(index);
+
+ cancelLongPress(index);
+
+ if (item->state() != HbInputButton::ButtonStatePressed) {
+ return;
+ }
+
+ HbWidgetFeedback::triggered(q, Hb::InstantReleased);
+
+ item->setState(HbInputButton::ButtonStateReleased);
+ updateGraphics(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+ updateTextLayouts(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+ q->update();
+
+ if (mCharacterSelectionPreview && mCharacterSelectionPreview->isVisible()) {
+ return;
+ }
+
+ hideButtonPreview(item);
+
+ if (emitSignal) {
+ HbWidgetFeedback::triggered(q, Hb::InstantClicked);
+ int actionIndex = item->keyCode() - HbInputButton::ButtonKeyCodeCustom;
+ if (actionIndex >= 0 && actionIndex < mCustomActions.count()) {
+ mCustomActions.at(actionIndex)->activate(QAction::Trigger);
+ } else {
+ calculateButtonProbabilities(position);
+
+ QString text;
+ if (item->type() == HbInputButton::ButtonTypeLabel) {
+ text = item->text(HbInputButton::ButtonTextIndexPrimary);
+ }
+ QKeyEvent event(QEvent::KeyRelease, item->keyCode(), Qt::NoModifier, text);
+ q->emitButtonReleased(event);
+ }
+ }
+ }
+}
+
+void HbInputButtonGroupPrivate::longPressEvent()
+{
+ Q_Q(HbInputButtonGroup);
+
+ int index = mLongPressButtons.at(0);
+ mLongPressButtons.removeAt(0);
+ QTimer *timer = mLongPressTimers.at(0);
+ mLongPressTimers.removeAt(0);
+
+ if (index >= 0 && index < mButtonData.count()) {
+ HbInputButton *item = mButtonData.at(index);
+
+ if (item->autoRepeat() &&
+ (item->state() == HbInputButton::ButtonStatePressed ||
+ item->state() == HbInputButton::ButtonStateLatched)) {
+ mLongPressButtons.append(index);
+ mLongPressTimers.append(timer);
+ timer->start(HbAutoRepeatTimeout);
+
+ HbWidgetFeedback::triggered(q, Hb::InstantKeyRepeated);
+
+ QString text;
+ if (item->type() == HbInputButton::ButtonTypeLabel) {
+ text = item->text(HbInputButton::ButtonTextIndexPrimary);
+ }
+ QKeyEvent releaeEvent(QEvent::KeyRelease, item->keyCode(), Qt::NoModifier, text, true);
+ q->emitButtonReleased(releaeEvent);
+ QKeyEvent pressEvent(QEvent::KeyPress, item->keyCode(), Qt::NoModifier, text, true);
+ q->emitButtonPressed(pressEvent);
+ } else {
+ if (mCharacterSelectionPreviewEnabled) {
+ showCharacterSelectionPreview(item);
+ }
+
+ HbWidgetFeedback::triggered(q, Hb::InstantLongPressed);
+
+ delete timer;
+
+ QString text;
+ if (item->type() == HbInputButton::ButtonTypeLabel) {
+ text = item->text(HbInputButton::ButtonTextIndexPrimary);
+ }
+ QKeyEvent event(QEvent::KeyPress, item->keyCode(), Qt::NoModifier, text, true);
+ q->emitButtonLongPressed(event);
+ }
+ }
+}
+
+void HbInputButtonGroupPrivate::calculateButtonProbabilities(const QPointF &position)
+{
+ Q_Q(HbInputButtonGroup);
+
+ mProbabilities.clear();
+
+ qreal cellWidth = q->boundingRect().width() / mGridSize.width();
+ qreal cellHeight = q->boundingRect().height() / mGridSize.height();
+
+ QRectF touchArea = QRectF(position.x() - 0.5 * cellWidth, position.y() - 0.5 * cellHeight,
+ HbTouchAreaSizeInUnits * mUnitValue, HbTouchAreaSizeInUnits * mUnitValue);
+
+ qreal probabilities = 0;
+ foreach (HbInputButton *button, mButtonData) {
+ QRectF intersection = button->boundingRect().intersected(touchArea);
+
+ if (intersection.isValid()) {
+ qreal probability = intersection.width() * intersection.height() / (touchArea.width() * touchArea.height());
+ probabilities += probability;
+
+ HbKeyPressProbability probableKey;
+ probableKey.keycode = button->keyCode();
+ probableKey.probability = probability;
+ mProbabilities.append(probableKey);
+ }
+ }
+
+ // Normalize
+ for (int i = 0; i < mProbabilities.count(); ++i) {
+ mProbabilities[i].probability /= probabilities;
+ }
+}
+
+void HbInputButtonGroupPrivate::createPrimarySingleTextLayout(int index, const QHash<int, QString> &textContent, const QSizeF &size)
+{
+ qreal cellWidth = size.width() / mGridSize.width();
+ qreal cellHeight = size.height() / mGridSize.height();
+
+ QFont font = HbFontSpec(HbFontSpec::Primary).font();
+
+ int typeIndex = index % HbTextTypeCount / HbInputButton::ButtonStateCount;
+ if (typeIndex == HbInputButton::ButtonTypeLabel) {
+ font.setPixelSize(fontSize(ButtonTextTypeLabel));
+ } else {
+ font.setPixelSize(fontSize(ButtonTextTypeSingle));
+ }
+
+ mTextLayouts[index] = new QTextLayout(textContent.value(index), font);
+ QFontMetricsF fontMetrics(font);
+
+ // Create text line for each button with primary text and correct type and state. Layout it
+ // to correct position
+ mTextLayouts.at(index)->beginLayout();
+ foreach (HbInputButton *item, mButtonData) {
+ int layoutIndex = item->type() * HbInputButton::ButtonStateCount + item->state() + HbTextTypeCount;
+ if (!mEnabled) {
+ layoutIndex = item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled + HbTextTypeCount;
+ }
+ if (index == layoutIndex && !item->text(HbInputButton::ButtonTextIndexPrimary).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexPrimary).isNull() &&
+ item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull() &&
+ item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+ qreal textWidth = fontMetrics.width(item->text(HbInputButton::ButtonTextIndexPrimary));
+ qreal textHeight = fontMetrics.height();
+
+ QTextLine line = mTextLayouts.at(index)->createLine();
+ line.setNumColumns(1);
+
+ if (typeIndex == HbInputButton::ButtonTypeLabel) {
+ layoutTextLine(ButtonTextTypeLabel, item, QSizeF(cellWidth, cellHeight), line, QSizeF(textWidth, textHeight));
+ } else {
+ layoutTextLine(ButtonTextTypeSingle, item, QSizeF(cellWidth, cellHeight), line, QSizeF(textWidth, textHeight));
+ }
+ }
+ }
+ mTextLayouts.at(index)->endLayout();
+ mTextLayouts.at(index)->setCacheEnabled(true);
+}
+
+void HbInputButtonGroupPrivate::createPrimaryTextLayout(int index, const QHash<int, QString> &textContent, const QSizeF &size)
+{
+ qreal cellWidth = size.width() / mGridSize.width();
+ qreal cellHeight = size.height() / mGridSize.height();
+
+ QFont font = HbFontSpec(HbFontSpec::Primary).font();
+ font.setPixelSize(fontSize(ButtonTextTypePrimary));
+
+ mTextLayouts[index] = new QTextLayout(textContent.value(index), font);
+ QFontMetricsF fontMetrics(font);
+
+ // Create text line for each button with primary text and correct type and state. Layout it
+ // to correct position
+ mTextLayouts.at(index)->beginLayout();
+ foreach (HbInputButton *item, mButtonData) {
+ int layoutIndex = item->type() * HbInputButton::ButtonStateCount + item->state();
+ if (!mEnabled) {
+ layoutIndex = item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled;
+ }
+ if (index == layoutIndex && !item->text(HbInputButton::ButtonTextIndexPrimary).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexPrimary).isNull() &&
+ !(item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull() &&
+ item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull())) {
+ qreal textWidth = fontMetrics.width(item->text(HbInputButton::ButtonTextIndexPrimary));
+ qreal textHeight = fontMetrics.height();
+
+ QTextLine line = mTextLayouts.at(index)->createLine();
+ line.setNumColumns(1);
+
+ layoutTextLine(ButtonTextTypePrimary, item, QSizeF(cellWidth, cellHeight), line, QSizeF(textWidth, textHeight));
+ }
+ }
+ mTextLayouts.at(index)->endLayout();
+ mTextLayouts.at(index)->setCacheEnabled(true);
+}
+
+void HbInputButtonGroupPrivate::createSecondaryTextLayout(int index, const QHash<int, QString> &textContent, const QSizeF &size)
+{
+ qreal cellWidth = size.width() / mGridSize.width();
+ qreal cellHeight = size.height() / mGridSize.height();
+
+ QFont font = HbFontSpec(HbFontSpec::Primary).font();
+ font.setPixelSize(fontSize(ButtonTextTypeSecondaryFirstRow));
+
+ mTextLayouts[index] = new QTextLayout(textContent.value(index), font);
+ QFontMetricsF fontMetrics(font);
+
+ // Create text line for each button with secondary first row or second row text and correct type and state.
+ // Layout it to correct position
+ mTextLayouts.at(index)->beginLayout();
+ foreach (HbInputButton *item, mButtonData) {
+ int layoutIndex = item->type() * HbInputButton::ButtonStateCount + item->state() + HbTextTypeCount * 2;
+ if (!mEnabled) {
+ layoutIndex = item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled + HbTextTypeCount * 2;
+ }
+ if (index == layoutIndex) {
+ if (!item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull()) {
+ qreal textWidth = fontMetrics.width(item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow));
+ qreal textHeight = fontMetrics.height();
+
+ QTextLine line = mTextLayouts.at(index)->createLine();
+ line.setNumColumns(1);
+
+ layoutTextLine(ButtonTextTypeSecondaryFirstRow, item, QSizeF(cellWidth, cellHeight), line, QSizeF(textWidth, textHeight));
+ }
+
+ if (!item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() &&
+ item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+ qreal textWidth = fontMetrics.width(item->text(HbInputButton::ButtonTextIndexSecondarySecondRow));
+ qreal textHeight = fontMetrics.height();
+
+ QTextLine line = mTextLayouts.at(index)->createLine();
+ line.setNumColumns(1);
+
+ layoutTextLine(ButtonTextTypeSecondarySecondRow, item, QSizeF(cellWidth, cellHeight), line, QSizeF(textWidth, textHeight));
+ }
+ }
+ }
+ mTextLayouts.at(index)->endLayout();
+ mTextLayouts.at(index)->setCacheEnabled(true);
+}
+
+void HbInputButtonGroupPrivate::layoutTextLine(HbInputButtonTextType textType, const HbInputButton *button, const QSizeF &cellSize,
+ QTextLine &textLine, const QSizeF &textSize)
+{
+ qreal textPositionX = 0.0;
+ qreal textPositionY = 0.0;
+ if (textType == ButtonTextTypeSingle ||
+ textType == ButtonTextTypeLabel) {
+ textPositionX = (button->position().x() + 0.5 * button->size().width()) * cellSize.width() - 0.5 * textSize.width();
+ textPositionY = (button->position().y() + 0.5 * button->size().height()) * cellSize.height() - 0.5 * textSize.height();
+ } else if (textType == ButtonTextTypePrimary) {
+ textPositionX = button->position().x() * cellSize.width() + HbHorizontalMarginInUnits * mUnitValue + mButtonBorderSize;
+ textPositionY = (button->position().y() + 0.5 * button->size().height()) * cellSize.height() - 0.5 * textSize.height();
+ } else if (textType == ButtonTextTypeSecondaryFirstRow) {
+ textPositionX = (button->position().x() + button->size().width()) * cellSize.width() -
+ textSize.width() - HbHorizontalMarginInUnits * mUnitValue - mButtonBorderSize;
+ textPositionY = (button->position().y() + button->size().height()) * cellSize.height() -
+ textSize.height() - HbVerticalMarginInUnits * mUnitValue - mButtonBorderSize;
+ } else if (textType == ButtonTextTypeSecondarySecondRow) {
+ textPositionX = (button->position().x() + button->size().width()) * cellSize.width() -
+ textSize.width() - HbHorizontalMarginInUnits * mUnitValue - mButtonBorderSize;
+ textPositionY = button->position().y() * cellSize.height() + HbVerticalMarginInUnits * mUnitValue + mButtonBorderSize;
+ }
+ textLine.setPosition(QPointF(textPositionX, textPositionY));
+}
+
+QString HbInputButtonGroupPrivate::buttonGraphics(HbInputButton::HbInputButtonType type, HbInputButton::HbInputButtonState state)
+{
+ if (type == HbInputButton::ButtonTypeNormal) {
+ if (state == HbInputButton::ButtonStateReleased) {
+ return HbNormalBackground;
+ } else if (state == HbInputButton::ButtonStatePressed) {
+ return HbNormalPressedBackground;
+ } else if (state == HbInputButton::ButtonStateLatched) {
+ return HbNormalLatchedBackground;
+ } else if (state == HbInputButton::ButtonStateDisabled) {
+ return HbNormalInActiveBackground;
+ }
+ } else if (type == HbInputButton::ButtonTypeFunction) {
+ if (state == HbInputButton::ButtonStateReleased) {
+ return HbFunctionBackground;
+ } else if (state == HbInputButton::ButtonStatePressed) {
+ return HbFunctionPressedBackground;
+ } else if (state == HbInputButton::ButtonStateLatched) {
+ return HbFunctionLatchedBackground;
+ } else if (state == HbInputButton::ButtonStateDisabled) {
+ return HbFunctionInActiveBackground;
+ }
+ }
+ return QString("");
+}
+
+QString HbInputButtonGroupPrivate::buttonColor(HbInputButton::HbInputButtonType type, HbInputButton::HbInputButtonState state)
+{
+ if (type == HbInputButton::ButtonTypeNormal) {
+ if (state == HbInputButton::ButtonStateReleased) {
+ return HbNormalColor;
+ } else if (state == HbInputButton::ButtonStatePressed) {
+ return HbNormalColorPressed;
+ } else if (state == HbInputButton::ButtonStateLatched) {
+ return HbNormalColorLatched;
+ } else if (state == HbInputButton::ButtonStateDisabled) {
+ return HbNormalColorInActive;
+ }
+ } else if (type == HbInputButton::ButtonTypeFunction) {
+ if (state == HbInputButton::ButtonStateReleased) {
+ return HbFunctionColor;
+ } else if (state == HbInputButton::ButtonStatePressed) {
+ return HbFunctionColorPressed;
+ } else if (state == HbInputButton::ButtonStateLatched) {
+ return HbFunctionColorLatched;
+ } else if (state == HbInputButton::ButtonStateDisabled) {
+ return HbFunctionColorInActive;
+ }
+ } else if (type == HbInputButton::ButtonTypeLabel) {
+ if (mButtonData.count() == 1) {
+ return HbButtonPreviewColor;
+ } else {
+ return HbCharacterSelectionPreviewColor;
+ }
+ }
+ return QString("");
+}
+
+qreal HbInputButtonGroupPrivate::fontSize(HbInputButtonTextType textType)
+{
+ if (textType == ButtonTextTypeSingle) {
+ return HbTextSizeInUnits * mUnitValue;
+ } else if (textType == ButtonTextTypePrimary) {
+ return HbPrimaryTextSizeInUnits * mUnitValue;
+ } else if (textType == ButtonTextTypeSecondaryFirstRow ||
+ textType == ButtonTextTypeSecondarySecondRow) {
+ return HbSecondaryTextSizeInUnits * mUnitValue;
+ } else if (textType == ButtonTextTypeLabel) {
+ return HbLabelTextSizeInUnits * mUnitValue;
+ }
+ return 0;
+}
+
+void HbInputButtonGroupPrivate::startLongPress(int index)
+{
+ Q_Q(HbInputButtonGroup);
+ if (!mUsedCustomButtons.contains(index)) {
+ mLongPressButtons.append(index);
+ mLongPressTimers.append(new QTimer());
+ mLongPressTimers.back()->setSingleShot(true);
+ QObject::connect(mLongPressTimers.back(), SIGNAL(timeout()), q, SLOT(longPressEvent()));
+ mLongPressTimers.back()->start(HbLongPressTimeout);
+ }
+}
+
+void HbInputButtonGroupPrivate::cancelLongPress(int index)
+{
+ if (mLongPressButtons.contains(index)) {
+ int listIndex = mLongPressButtons.indexOf(index);
+ delete mLongPressTimers.at(listIndex);
+ mLongPressTimers.removeAt(listIndex);
+ mLongPressButtons.removeAt(listIndex);
+ }
+}
+
+/// @endcond
+
+/*!
+Constructor
+*/
+HbInputButtonGroup::HbInputButtonGroup(QGraphicsItem *parent)
+ : HbWidget(*new HbInputButtonGroupPrivate, parent)
+{
+ Q_D(HbInputButtonGroup);
+
+ d->mUnitValue = HbDeviceProfile::profile(mainWindow()).unitValue();
+
+ setAcceptedMouseButtons(Qt::LeftButton);
+}
+
+/*!
+Constructor
+*/
+HbInputButtonGroup::HbInputButtonGroup(HbInputButtonGroupPrivate &dd, QGraphicsItem *parent)
+ : HbWidget(dd, parent)
+{
+ Q_D(HbInputButtonGroup);
+
+ d->mUnitValue = HbDeviceProfile::profile(mainWindow()).unitValue();
+
+ setAcceptedMouseButtons(Qt::LeftButton);
+}
+
+/*!
+Constructor
+*/
+HbInputButtonGroup::HbInputButtonGroup(const QSize &size, QGraphicsItem *parent)
+ : HbWidget(*new HbInputButtonGroupPrivate, parent)
+{
+ Q_D(HbInputButtonGroup);
+
+ d->mUnitValue = HbDeviceProfile::profile(mainWindow()).unitValue();
+
+ setAcceptedMouseButtons(Qt::LeftButton);
+
+ setGridSize(size);
+}
+
+/*!
+Constructor
+*/
+HbInputButtonGroup::HbInputButtonGroup(HbInputButtonGroupPrivate &dd, const QSize &size, QGraphicsItem *parent)
+ : HbWidget(dd, parent)
+{
+ Q_D(HbInputButtonGroup);
+
+ d->mUnitValue = HbDeviceProfile::profile(mainWindow()).unitValue();
+
+ setAcceptedMouseButtons(Qt::LeftButton);
+
+ setGridSize(size);
+}
+
+/*!
+Destructor
+*/
+HbInputButtonGroup::~HbInputButtonGroup()
+{
+}
+
+/*!
+Sets new grid size and updates button group content based on the new grid size.
+
+\sa gridSize
+*/
+void HbInputButtonGroup::setGridSize(const QSize &size)
+{
+ Q_D(HbInputButtonGroup);
+
+ d->mGridSize = size;
+ if (d->mGridSize.width() < 1) {
+ d->mGridSize.setWidth(1);
+ }
+ if (d->mGridSize.height() < 1) {
+ d->mGridSize.setHeight(1);
+ }
+
+ setButtonBorderSize(d->mButtonBorderSize);
+ d->updateButtonGrid(QSizeF(boundingRect().width(), boundingRect().height()));
+ d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+ d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+ update();
+}
+
+/*!
+Returns current grid size.
+
+\sa setGridSize
+*/
+QSize HbInputButtonGroup::gridSize() const
+{
+ Q_D(const HbInputButtonGroup);
+
+ return d->mGridSize;
+}
+
+/*!
+Sets the button data and updates button group based on the new data.
+Takes ownership of the button items. Button items that are not in the new list
+will be destroyed.
+
+\sa buttons
+\sa button
+*/
+void HbInputButtonGroup::setButtons(const QList<HbInputButton*> &data)
+{
+ Q_D(HbInputButtonGroup);
+
+ foreach (HbInputButton *button, d->mButtonData) {
+ if (!data.contains(button)) {
+ delete button;
+ }
+ }
+ d->mButtonData = data;
+
+ d->updateButtonGrid(QSizeF(boundingRect().width(), boundingRect().height()));
+ d->updateCustomActions();
+ d->updateColorArray();
+ d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+ d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+ update();
+}
+
+/*!
+Sets the button item and updates button group based on the new data.
+Takes ownership of the button item. Old button item in the given index will be destroyed.
+If null item is passed then the item from the given index will be removed.
+If index is out of bounds then the item is inserted to the end of button list.
+
+\sa buttons
+\sa button
+*/
+void HbInputButtonGroup::setButton(HbInputButton *data, int index)
+{
+ Q_D(HbInputButtonGroup);
+
+ if (index >= 0 && index < d->mButtonData.count()) {
+ if (data != d->mButtonData.at(index)) {
+ delete d->mButtonData.at(index);
+ }
+ if (data) {
+ d->mButtonData.replace(index, data);
+ } else {
+ d->mButtonData.removeAt(index);
+ }
+ } else {
+ d->mButtonData.append(data);
+ }
+ setButtons(d->mButtonData);
+}
+
+/*!
+Sets the button item and updates button group based on the new data.
+Takes ownership of the button item. Old button item in the given position will be destroyed.
+If null item is passed then the item from the given position will be removed.
+If the given position doesn't contain a button then the item is inserted to the end of button list.
+
+\sa buttons
+\sa button
+*/
+void HbInputButtonGroup::setButton(HbInputButton *data, int column, int row)
+{
+ Q_D(HbInputButtonGroup);
+
+ int index = d->mButtonGridPositions.value(QPair<int, int>(column, row));
+ setButton(data, index);
+}
+
+/*!
+Sets the button item and updates button group based on the new data.
+Takes ownership of the button item. Old button item with given key code will be destroyed.
+If null item is passed then the item with given key code will be removed.
+If group contains multiple buttons with same key code then the first one will be replaced.
+If there isn't any button with given key code then the button will be added to the end of button list.
+
+\sa buttons
+\sa button
+*/
+void HbInputButtonGroup::setButton(HbInputButton *data, HbInputButton::HbInputButtonKeyCode keyCode)
+{
+ Q_D(HbInputButtonGroup);
+
+ int index = 0;
+ for (; index < d->mButtonData.count(); ++index) {
+ HbInputButton *item = d->mButtonData.at(index);
+ if (item->keyCode() == keyCode) {
+ break;
+ }
+ }
+
+ setButton(data, index);
+}
+
+/*!
+Returns button data.
+Ownership of the returned button items is not transferred.
+
+\sa setButtons
+\sa setButton
+*/
+QList<HbInputButton*> HbInputButtonGroup::buttons() const
+{
+ Q_D(const HbInputButtonGroup);
+
+ return d->mButtonData;
+}
+
+/*!
+Returns button item.
+Ownership of the returned button item is not transferred.
+
+\sa setButtons
+\sa setButton
+*/
+HbInputButton *HbInputButtonGroup::button(int index) const
+{
+ Q_D(const HbInputButtonGroup);
+
+ if (index >= 0 && index < d->mButtonData.count()) {
+ return d->mButtonData.at(index);
+ }
+ return 0;
+}
+
+/*!
+Returns button data.
+Ownership of the button items is not transferred.
+
+\sa setButtons
+\sa setButton
+*/
+HbInputButton *HbInputButtonGroup::button(int column, int row) const
+{
+ Q_D(const HbInputButtonGroup);
+
+ int index = d->mButtonGridPositions.value(QPair<int, int>(column, row));
+ return button(index);
+}
+
+/*!
+Returns button data.
+Ownership of the button items is not transferred.
+
+\sa setButtons
+\sa setButton
+*/
+HbInputButton *HbInputButtonGroup::button(HbInputButton::HbInputButtonKeyCode keyCode) const
+{
+ Q_D(const HbInputButtonGroup);
+
+ foreach (HbInputButton *button, d->mButtonData) {
+ if (button->keyCode() == keyCode) {
+ return button;
+ }
+ }
+ return 0;
+}
+
+/*!
+Sets custom actions and updates button group based on the new data. Custom actions
+are mapped to buttons which keycode is equal or bigger than HbInputButtonKeyCustom.
+Ownership of the actions is not transferred.
+
+\sa customButtonActions
+*/
+void HbInputButtonGroup::setCustomButtonActions(const QList<HbAction*> &actions)
+{
+ Q_D(HbInputButtonGroup);
+
+ disconnect(this, SLOT(updateCustomButtons()));
+
+ d->mCustomActions = actions;
+
+ foreach (HbAction *action, d->mCustomActions) {
+ connect(action, SIGNAL(changed()), this, SLOT(updateCustomButtons()));
+ }
+
+ d->updateCustomActions();
+ d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+ d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+ update();
+}
+
+/*!
+Returns current custom actions.
+Ownership of the actions is not transferred.
+
+\sa setCustomButtonActions
+*/
+QList<HbAction*> HbInputButtonGroup::customButtonActions() const
+{
+ Q_D(const HbInputButtonGroup);
+
+ return d->mCustomActions;
+}
+
+/*!
+Sets the border size for the buttons and updates button group based on the new value.
+Size must be in a range between 0 to half of button size.
+
+\sa buttonBorderSize
+*/
+void HbInputButtonGroup::setButtonBorderSize(qreal borderSize)
+{
+ Q_D(HbInputButtonGroup);
+
+ if (borderSize < 0.0) {
+ borderSize = 0.0;
+ } else if (boundingRect().width() != 0.0 && boundingRect().height() != 0.0) {
+ qreal maxSize = boundingRect().width() / d->mGridSize.width() * 0.5;
+ if (boundingRect().width() > boundingRect().height()) {
+ maxSize = boundingRect().height() / d->mGridSize.height() * 0.5;
+ }
+ if (borderSize > maxSize) {
+ borderSize = maxSize;
+ }
+ }
+ d->mButtonBorderSize = borderSize;
+
+ d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+ update();
+}
+
+/*!
+Returns the border size.
+
+\sa setButtonBorderSize
+*/
+qreal HbInputButtonGroup::buttonBorderSize() const
+{
+ Q_D(const HbInputButtonGroup);
+
+ return d->mButtonBorderSize;
+}
+
+/*!
+Sets button preview state.
+
+\sa isButtonPreviewEnabled
+*/
+void HbInputButtonGroup::setButtonPreviewEnabled(bool enabled)
+{
+ Q_D(HbInputButtonGroup);
+
+ d->mButtonPreviewEnabled = enabled;
+}
+
+/*!
+Returns preview state.
+
+\sa setButtonPreviewEnabled
+*/
+bool HbInputButtonGroup::isButtonPreviewEnabled() const
+{
+ Q_D(const HbInputButtonGroup);
+
+ return d->mButtonPreviewEnabled;
+}
+
+/*!
+Sets button specific character selection preview state.
+
+\sa isCharacterSelectionPreviewEnabled
+*/
+void HbInputButtonGroup::setCharacterSelectionPreviewEnabled(bool enabled)
+{
+ Q_D(HbInputButtonGroup);
+
+ d->mCharacterSelectionPreviewEnabled = enabled;
+}
+
+/*!
+Returns button specific character selection preview state.
+
+\sa setCharacterSelectionPreviewEnabled
+*/
+bool HbInputButtonGroup::isCharacterSelectionPreviewEnabled() const
+{
+ Q_D(const HbInputButtonGroup);
+
+ return d->mCharacterSelectionPreviewEnabled;
+}
+
+
+/*!
+Sets multi touch enabled or disabled.
+
+\sa isMultiTouchEnabled
+*/
+void HbInputButtonGroup::setMultiTouchEnabled(bool enabled)
+{
+ Q_D(HbInputButtonGroup);
+
+ d->mMultiTouchEnabled = enabled;
+ setAcceptTouchEvents(enabled);
+}
+
+/*!
+Returns multi touch state.
+
+\sa setMultiTouchEnabled
+*/
+bool HbInputButtonGroup::isMultiTouchEnabled() const
+{
+ Q_D(const HbInputButtonGroup);
+
+ return d->mMultiTouchEnabled;
+}
+
+/*!
+Sets button group background graphics.
+Takes ownership of the background object.
+*/
+void HbInputButtonGroup::setBackground(HbFrameDrawer *background)
+{
+ Q_D(HbInputButtonGroup);
+
+ HbFrameDrawerPool::release(d->mBackground);
+ d->mBackground = background;
+}
+
+/*!
+Returns all possible buttons the user could have intended to press
+for the last registered touch along with their corresponding probabilities.
+*/
+QList<HbKeyPressProbability> HbInputButtonGroup::buttonProbabilities() const
+{
+ Q_D(const HbInputButtonGroup);
+
+ return d->mProbabilities;
+}
+
+/*!
+Sets the button group enabled or disabled.
+
+\sa isEnabled
+*/
+void HbInputButtonGroup::setEnabled(bool enabled)
+{
+ Q_D(HbInputButtonGroup);
+
+ d->mEnabled = enabled;
+ d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+ d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+ update();
+}
+
+/*!
+Returns the button group state.
+
+\sa setEnabled
+*/
+bool HbInputButtonGroup::isEnabled() const
+{
+ Q_D(const HbInputButtonGroup);
+
+ return d->mEnabled;
+}
+
+/*!
+Draws the button group.
+*/
+void HbInputButtonGroup::paint(QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+
+ Q_D(HbInputButtonGroup);
+
+ if (d->mBackground) {
+ d->mBackground->paint(painter, QRectF(0, 0, boundingRect().width(), boundingRect().height()));
+ }
+
+ qreal cellWidth = boundingRect().width() / d->mGridSize.width();
+ qreal cellHeight = boundingRect().height() / d->mGridSize.height();
+
+ for (int i = 0; i < d->mButtonData.count(); ++i) {
+ HbInputButton *item = d->mButtonData.at(i);
+
+ if (d->mButtonDrawers.at(i)) {
+ qreal x = item->position().x() * cellWidth + d->mButtonBorderSize;
+ qreal y = item->position().y() * cellHeight + d->mButtonBorderSize;
+ qreal width = item->size().width() * cellWidth - 2 * d->mButtonBorderSize;
+ qreal height = item->size().height() * cellHeight - 2 * d->mButtonBorderSize;
+
+ painter->save();
+ painter->translate(x, y);
+ d->mButtonDrawers.at(i)->paint(painter, QRectF(0, 0, width, height));
+ painter->restore();
+ }
+
+ if (!item->icon(HbInputButton::ButtonIconIndexPrimary).isNull()) {
+ qreal x = item->position().x() * cellWidth;
+ qreal y = item->position().y() * cellHeight;
+ qreal width = item->size().width() * cellWidth;
+ qreal height = item->size().height() * cellHeight;
+
+ if (!item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() ||
+ !item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() ||
+ !item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull() ||
+ !item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+ x += HbHorizontalMarginInUnits * d->mUnitValue + d->mButtonBorderSize;
+ y += 0.5 * (item->size().height() * cellHeight - HbPrimaryIconSizeInUnits * d->mUnitValue);
+ width = HbPrimaryIconSizeInUnits * d->mUnitValue;
+ height = HbPrimaryIconSizeInUnits * d->mUnitValue;
+ }
+ item->icon(HbInputButton::ButtonIconIndexPrimary).paint(painter, QRectF(x, y, width, height));
+ }
+
+ if (!item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull()) {
+ qreal x = (item->position().x() + item->size().width()) * cellWidth -
+ HbSecondaryIconSizeInUnits * d->mUnitValue - HbHorizontalMarginInUnits * d->mUnitValue - d->mButtonBorderSize;
+ qreal y = (item->position().y() + item->size().height()) * cellHeight -
+ HbSecondaryIconSizeInUnits * d->mUnitValue - HbVerticalMarginInUnits * d->mUnitValue - d->mButtonBorderSize;
+ qreal width = HbSecondaryIconSizeInUnits * d->mUnitValue;
+ qreal height = HbSecondaryIconSizeInUnits * d->mUnitValue;
+
+ Qt::Alignment alignment = static_cast<Qt::Alignment>(Qt::AlignVCenter | Qt::AlignRight);
+ item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).paint(painter, QRectF(x, y, width, height), Qt::KeepAspectRatio, alignment);
+ }
+
+ if (!item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+ qreal x = (item->position().x() + item->size().width()) * cellWidth -
+ HbSecondaryIconSizeInUnits * d->mUnitValue - HbHorizontalMarginInUnits * d->mUnitValue - d->mButtonBorderSize;
+ qreal y = item->position().y() * cellHeight + HbVerticalMarginInUnits * d->mUnitValue + d->mButtonBorderSize;
+ qreal width = HbSecondaryIconSizeInUnits * d->mUnitValue;
+ qreal height = HbSecondaryIconSizeInUnits * d->mUnitValue;
+
+ Qt::Alignment alignment = static_cast<Qt::Alignment>(Qt::AlignVCenter | Qt::AlignRight);
+ item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).paint(painter, QRectF(x, y, width, height), Qt::KeepAspectRatio, alignment);
+ }
+
+ }
+
+ for (int i = 0; i < HbTextLayoutCount; ++i) {
+ painter->save();
+ painter->setPen(d->mColors.at(i % HbTextTypeCount));
+
+ if (d->mTextLayouts.at(i)) {
+ d->mTextLayouts.at(i)->draw(painter, QPointF(0, 0));
+ }
+ painter->restore();
+ }
+}
+
+/*!
+\reimp
+
+Handles touch events.
+*/
+bool HbInputButtonGroup::sceneEvent(QEvent *event)
+{
+ Q_D(HbInputButtonGroup);
+
+ if (!d->mEnabled) {
+ event->ignore();
+ return false;
+ }
+
+ if (event->type() == QEvent::TouchBegin) {
+ QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
+ foreach (QTouchEvent::TouchPoint point, touchEvent->touchPoints()) {
+ if (!point.isPrimary() && d->mMultiTouchEnabled) {
+ d->pressEvent(point.pos());
+ }
+ }
+ } else if (event->type() == QEvent::TouchUpdate) {
+ QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
+ foreach (QTouchEvent::TouchPoint point, touchEvent->touchPoints()) {
+ if (!point.isPrimary() && d->mMultiTouchEnabled) {
+ if (point.state() & Qt::TouchPointPressed) {
+ d->pressEvent(point.pos());
+ } else if (point.state() & Qt::TouchPointMoved) {
+ d->moveEvent(point.lastPos(), point.pos());
+ } else if (point.state() & Qt::TouchPointReleased) {
+ d->releaseEvent(point.pos());
+ }
+ }
+ }
+ } else if (event->type() == QEvent::TouchEnd) {
+ QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
+ foreach (QTouchEvent::TouchPoint point, touchEvent->touchPoints()) {
+ if (!point.isPrimary() && d->mMultiTouchEnabled) {
+ d->releaseEvent(point.pos());
+ }
+ }
+ } else if (event->type() == QEvent::GraphicsSceneMousePress) {
+ QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
+ d->pressEvent(mouseEvent->pos());
+ } else if (event->type() == QEvent::GraphicsSceneMouseDoubleClick) {
+ QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
+ d->doublePressEvent(mouseEvent->pos());
+ } else if (event->type() == QEvent::GraphicsSceneMouseMove) {
+ QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
+ d->moveEvent(mouseEvent->lastPos(), mouseEvent->pos());
+ } else if (event->type() == QEvent::GraphicsSceneMouseRelease) {
+ QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
+ d->releaseEvent(mouseEvent->pos());
+ } else {
+ return HbWidget::event(event);
+ }
+ return true;
+}
+
+/*!
+\reimp
+
+Updates button group geometry.
+*/
+void HbInputButtonGroup::setGeometry(const QRectF &rect)
+{
+ Q_D(HbInputButtonGroup);
+
+ HbWidget::setGeometry(rect);
+
+ setButtonBorderSize(d->mButtonBorderSize);
+ d->updateButtonGrid(QSizeF(rect.width(), rect.height()));
+ d->updateGraphics(QSizeF(rect.width(), rect.height()));
+ d->updateTextLayouts(QSizeF(rect.width(), rect.height()));
+}
+
+/*!
+\reimp
+
+Updates theme graphics
+ */
+void HbInputButtonGroup::changeEvent(QEvent *event)
+{
+ Q_D(HbInputButtonGroup);
+
+ if (event->type() == HbEvent::ThemeChanged) {
+ if (d->mBackground) {
+ d->mBackground->themeChanged();
+ }
+
+ foreach (HbFrameDrawer *drawer, d->mButtonDrawers) {
+ drawer->themeChanged();
+ }
+
+ d->updateColorArray();
+
+ for (int i = 0; i < d->mButtonData.count(); ++i) {
+ HbInputButton *item = d->mButtonData.at(i);
+
+ QColor color;
+ if (d->mEnabled) {
+ color = d->mColors.at(item->type() * HbInputButton::ButtonStateCount + item->state());
+ } else {
+ color = d->mColors.at(item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled);
+ }
+
+ if (!item->icon(HbInputButton::ButtonIconIndexPrimary).isNull()) {
+ HbIcon icon = item->icon(HbInputButton::ButtonIconIndexPrimary);
+ icon.setColor(color);
+ item->setIcon(icon, HbInputButton::ButtonIconIndexPrimary);
+ }
+ }
+ }
+ HbWidget::changeEvent(event);
+}
+
+/*!
+\reimp
+
+Enables touch events if multi touch is enabled.
+*/
+void HbInputButtonGroup::showEvent(QShowEvent *event)
+{
+ Q_D(HbInputButtonGroup);
+
+ setAcceptTouchEvents(d->mMultiTouchEnabled);
+
+ HbWidget::showEvent(event);
+}
+
+/*!
+\reimp
+
+Releases all pressed buttons when hidden.
+*/
+void HbInputButtonGroup::hideEvent(QHideEvent *event)
+{
+ cancelButtonPress();
+
+ HbWidget::hideEvent(event);
+}
+
+/*!
+Emits buttonPressed signal.
+*/
+void HbInputButtonGroup::emitButtonPressed(const QKeyEvent &event)
+{
+ emit buttonPressed(event);
+}
+
+/*!
+Emits buttonDoublePressed signal.
+*/
+void HbInputButtonGroup::emitButtonDoublePressed(const QKeyEvent &event)
+{
+ emit buttonDoublePressed(event);
+}
+
+/*!
+Emits buttonReleased signal.
+*/
+void HbInputButtonGroup::emitButtonReleased(const QKeyEvent &event)
+{
+ Q_D(HbInputButtonGroup);
+
+ if (d->mCharacterSelectionPreview) {
+ d->mCharacterSelectionPreview->hide();
+ }
+
+ emit buttonReleased(event);
+}
+
+/*!
+Emits buttonLongPressed signal.
+*/
+void HbInputButtonGroup::emitButtonLongPressed(const QKeyEvent &event)
+{
+ emit buttonLongPressed(event);
+}
+
+/*!
+Emits pressedButtonChanged signal.
+*/
+void HbInputButtonGroup::emitPressedButtonChanged(const QKeyEvent &releaseEvent, const QKeyEvent &pressEvent)
+{
+ emit pressedButtonChanged(releaseEvent, pressEvent);
+}
+
+/*!
+Cancels current button press and releases all buttons.
+*/
+void HbInputButtonGroup::cancelButtonPress()
+{
+ Q_D(HbInputButtonGroup);
+
+ ungrabMouse();
+
+ for (int i = 0; i < d->mButtonData.count(); ++i) {
+ if (d->mButtonData.at(i)->state() == HbInputButton::ButtonStatePressed) {
+ d->mButtonData.at(i)->setState(HbInputButton::ButtonStateReleased);
+ }
+ d->hideButtonPreview(d->mButtonData.at(i));
+
+ if (d->mLongPressButtons.contains(i)) {
+ int listIndex = d->mLongPressButtons.indexOf(i);
+ delete d->mLongPressTimers.at(listIndex);
+ d->mLongPressTimers.removeAt(listIndex);
+ d->mLongPressButtons.removeAt(listIndex);
+ }
+ }
+ if (d->mCharacterSelectionPreview) {
+ d->mCharacterSelectionPreview->hide();
+ }
+
+ d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+ d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+ update();
+}
+
+/*!
+Called when long press occurs.
+*/
+void HbInputButtonGroup::longPressEvent()
+{
+ Q_D(HbInputButtonGroup);
+
+ d->longPressEvent();
+}
+
+/*!
+Updates custom buttons with custom actions.
+
+\sa setCustomButtonActions
+*/
+void HbInputButtonGroup::updateCustomButtons()
+{
+ Q_D(HbInputButtonGroup);
+
+ d->updateCustomActions();
+ d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+ d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+ update();
+}
+
+// End of file