diff -r 000000000000 -r 16d8024aca5e src/hbplugins/feedback/feedbackeffectplugin/hbfeedbackeffectengine.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hbplugins/feedback/feedbackeffectplugin/hbfeedbackeffectengine.cpp Mon Apr 19 14:02:13 2010 +0300 @@ -0,0 +1,412 @@ +/**************************************************************************** +** +** 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 HbPlugins 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 "hbfeedbackeffectengine.h" +#include "hbfeedbackeffectutils.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "hbmenucontainer_p.h" +#include "hbinputvirtualrocker.h" +#include + +/*! + Constructor +*/ +HbFeedbackEffectEngine::HbFeedbackEffectEngine() : previousCursorPosition(0) +{ + // initialize + HbFeedbackPlayer::instance(); +} + +/*! + Destructor +*/ +HbFeedbackEffectEngine::~HbFeedbackEffectEngine() +{ + if (hbFeedbackPlayer) { + foreach(int identifier, continuousFeedbacks) { + hbFeedbackPlayer->cancelContinuousFeedback(identifier); + } + } + + continuousFeedbacks.clear(); + boundaryWidgets.clear(); +} + +/*! + Called by the feedback manager when an interaction is triggered. +*/ +void HbFeedbackEffectEngine::triggered(const HbWidget *widget, Hb::InstantInteraction interaction, Hb::InteractionModifiers modifiers) +{ + HbFeedback::InstantEffect widgetOverride = widget->overrideFeedback(interaction); + if (widgetOverride != HbFeedback::NoOverride ) { + playInstantFeedback(widget, widgetOverride); + } else { + HbFeedbackEngine::triggered(widget, interaction, modifiers); + } +} + +/*! + Called by the feedback manager when a widget is pressed. +*/ +void HbFeedbackEffectEngine::pressed(const HbWidget *widget) +{ + HbFeedback::InstantEffect effect = HbFeedbackEffectUtils::instantOnPress(widget, modifiers()); + playInstantFeedback(widget, effect); +} + +/*! + Called by the feedback manager when a widget is released. +*/ +void HbFeedbackEffectEngine::released(const HbWidget *widget) +{ + if (continuousFeedbacks.contains(widget)) { + cancelContinuousFeedback(widget); + } + // slider-like widgets are a bit special + if (HbFeedbackEffectUtils::widgetFamily(widget) == HbFeedbackEffectUtils::Slider) { + playInstantFeedback(widget, HbFeedbackEffectUtils::instantOnRelease(widget, modifiers())); + } + // lists in arrange mode react on release + else if (const HbListViewItem *listViewItem = qobject_cast(widget)) { + const HbAbstractItemView* itemView = listViewItem->itemView(); + if (const HbListView * listView = qobject_cast(itemView)) { + if( listView->arrangeMode() ) { + playInstantFeedback(listViewItem,HbFeedbackEffectUtils::instantOnRelease(listViewItem, modifiers())); + } + } + } else if (widget->type() == Hb::ItemType_VirtualTrackPoint) { + playInstantFeedback(widget, HbFeedback::Editor); + } else if (widget->type() == Hb::ItemType_WritingBox) { + playInstantFeedback(widget, HbFeedback::Editor); + } + else if (widget->type() == HbPrivate::ItemType_GroupBoxHeadingWidget || widget->type() == Hb::ItemType_ComboBox) { + playInstantFeedback(widget, HbFeedbackEffectUtils::instantOnRelease(widget, modifiers())); + } + + // normally touch end feedback effect is initiated with a clicked signal +} + +/*! + Called by the feedback manager when a long press is detected for a widget. +*/ +void HbFeedbackEffectEngine::longPressed(const HbWidget *widget) +{ + if (widget->type() == Hb::ItemType_InputCharacterButton) { + playInstantFeedback(widget, HbFeedback::SensitiveKeypad); + } +} + +/*! + Called by the feedback manager when a widget is clicked. +*/ +void HbFeedbackEffectEngine::clicked(const HbWidget *widget) +{ + if (continuousFeedbacks.contains(widget)) { + cancelContinuousFeedback(widget); + } + playInstantFeedback(widget, HbFeedbackEffectUtils::instantOnRelease(widget, modifiers())); +} + +/*! + Called by the feedback manager when keyrepeats are detected for a widget. +*/ +void HbFeedbackEffectEngine::keyRepeated(const HbWidget *widget) +{ + playInstantFeedback(widget, HbFeedbackEffectUtils::instantOnKeyRepeat(widget)); +} + +/*! + Called by the feedback manager when a dragged over event is detected for a widget. +*/ +void HbFeedbackEffectEngine::draggedOver(const HbWidget *widget) +{ + // For editor highlighting + if (const HbAbstractEdit *edit = qobject_cast(widget)) { + if (edit->cursorPosition() != previousCursorPosition) { + playInstantFeedback(widget, HbFeedbackEffectUtils::instantOnEditorHighlight(edit, previousCursorPosition)); + previousCursorPosition = edit->cursorPosition(); + } + } + else if (const HbInputVirtualRocker *trackPoint = qobject_cast(widget)) { + if (trackPoint && trackPoint->mainWindow() && trackPoint->mainWindow()->scene() && + trackPoint->mainWindow()->scene()->focusItem()) { + + QGraphicsItem* graphicsItem = trackPoint->mainWindow()->scene()->focusItem(); + + if (graphicsItem->isWidget() && + static_cast(graphicsItem)->inherits("HbAbstractEdit")) { + + if (HbAbstractEdit* edit = static_cast(graphicsItem)) { + if (edit->cursorPosition() != previousCursorPosition) { + playInstantFeedback(widget, HbFeedbackEffectUtils::instantOnEditorHighlight(edit, previousCursorPosition)); + previousCursorPosition = edit->cursorPosition(); + } + } + } + } + } + else { + playInstantFeedback(widget, HbFeedbackEffectUtils::instantOnDrag(widget, modifiers())); + } +} + +/*! + Called by the feedback manager when a widget is flicked. +*/ +void HbFeedbackEffectEngine::flicked(const HbWidget *widget) +{ + playInstantFeedback(widget, HbFeedback::Flick); +} + +/*! + Called by the feedback manager when a scroll area widget is flicked or dragged and the boundary reached. +*/ +void HbFeedbackEffectEngine::boundaryReached(const HbWidget *widget) +{ + boundaryWidgets.append(widget); +} + +/*! + Called by the feedback manager when a rotate gesture is recognized for a widget. +*/ +void HbFeedbackEffectEngine::rotated90Degrees(const HbWidget *widget) +{ + playInstantFeedback(widget, HbFeedback::RotateStep); +} + +/*! + Called by the feedback manager when a popup opens. +*/ +void HbFeedbackEffectEngine::popupOpened(const HbWidget *widget) +{ + if (HbFeedbackEffectUtils::isFeedbackAllowedForPopup(widget)) { + playInstantFeedback(widget, HbFeedback::PopupOpen); + } +} + +/*! + Called by the feedback manager when a popup closes. +*/ +void HbFeedbackEffectEngine::popupClosed(const HbWidget *widget) +{ + if (HbFeedbackEffectUtils::isFeedbackAllowedForPopup(widget)) { + playInstantFeedback(widget, HbFeedback::PopupClose); + } +} + +/*! + Called by the feedback manager when an item view selection has changed. +*/ +void HbFeedbackEffectEngine::selectionChanged(const HbWidget *widget) +{ + playInstantFeedback(widget, HbFeedbackEffectUtils::instantOnSelectionChanged(widget)); +} + +/*! + Called by the feedback manager when multitouch is activated. +*/ +void HbFeedbackEffectEngine::multitouchActivated(const HbWidget *widget) +{ + playInstantFeedback(widget, HbFeedback::MultitouchActivate); +} + +/*! + Called by the feedback manager when a continuous interaction is triggered. +*/ +void HbFeedbackEffectEngine::continuousTriggered(const HbWidget *widget, Hb::ContinuousInteraction interaction, QPointF delta) +{ + bool feedbackPlayed(false); + switch(HbFeedbackEffectUtils::widgetFamily(widget)) + { + case HbFeedbackEffectUtils::Slider: + { + if (!HbFeedbackEffectUtils::isSliderMoveContinuous(widget)) { + playInstantFeedback(widget, HbFeedback::SensitiveSlider); + feedbackPlayed = true; + } + break; + } + case HbFeedbackEffectUtils::List: + case HbFeedbackEffectUtils::Grid: + { + if (interaction == Hb::ContinuousScrolled) { + if (const HbAbstractItemView * itemView = qobject_cast(widget)) { + feedbackPlayed = true; + QList visibleItems = itemView->visibleItems(); + bool newItemFound(false); + int index(-1); + QList visibleIndexes; + if (widget == activelyScrollingItemView) { + foreach (HbAbstractViewItem * item, visibleItems) { + index = item->modelIndex().row(); + if (!oldVisibleIndexes.contains(index)) { + newItemFound = true; + } + visibleIndexes.append(index); + } + } + if (widget != activelyScrollingItemView){ + activelyScrollingItemView = widget; + newItemFound = false; + } + oldVisibleIndexes.clear(); + oldVisibleIndexes = visibleIndexes; + + if (newItemFound) { + const HbListView* listView = qobject_cast(widget); + if (!( listView && + listView->arrangeMode() && + listView->draggedItem())){ + playInstantFeedback(widget, HbFeedback::ItemScroll); + } + } + } + } + break; + } + default: + { + break; + } + } + + if (interaction == Hb::ContinuousScrolled) { + // menu widget does scroll feedback elsewhere + if (widget->type() == HbPrivate::ItemType_MenuListView) { + feedbackPlayed = true; + } + + // generic scroll areas don't emit continuous feedback + if (const HbScrollArea* scrollArea = qobject_cast(widget)) { + Q_UNUSED(scrollArea) + feedbackPlayed = true; + } + } + + if (!feedbackPlayed) { + int intensity = HbFeedbackEffectUtils::intensity(widget, interaction, delta); + + // Check if the widget has overriden feedback for this interaction + HbFeedback::ContinuousEffect widgetOverride = widget->overrideContinuousFeedback(interaction, &intensity) ; + if (widgetOverride != HbFeedback::NoContinuousOverride) { + playContinuousFeedback(widget, widgetOverride, intensity); + } else { + playContinuousFeedback(widget, HbFeedbackEffectUtils::continuousEffect(widget, interaction), intensity); + + } + } +} + +/*! + Called by the feedback manager when a continuous interaction is stopped. +*/ +void HbFeedbackEffectEngine::continuousStopped(const HbWidget *widget, Hb::ContinuousInteraction interaction) +{ + // determine if instant feedback should be played when a continuous interaction is stopped + HbFeedback::InstantEffect effect = HbFeedback::None; + if (boundaryWidgets.contains(widget)) { + if (interaction == Hb::ContinuousScrolled) { + effect = HbFeedback::BounceEffect; + } + boundaryWidgets.removeAll(widget); + } + + // stop ongoing continuous and list scrolling feedback effects + if (continuousFeedbacks.contains(widget)) { + cancelContinuousFeedback(widget); + } + if (activelyScrollingItemView == widget) { + activelyScrollingItemView = 0; + } + playInstantFeedback(widget, effect); +} + +/*! + Plays the instant feedback. +*/ +void HbFeedbackEffectEngine::playInstantFeedback(const HbWidget* widget, HbFeedback::InstantEffect effect) +{ + const QGraphicsView* view = widget->mainWindow(); + if (view && HbFeedbackEffectUtils::isFeedbackAllowed(widget)) { + HbInstantFeedback feedback(effect); + feedback.setRect(widget, view); + feedback.setOwningWindow(view); + + if (hbFeedbackPlayer && feedback.isLocated()) { + hbFeedbackPlayer->playInstantFeedback(feedback); + } + } +} + +/*! + Plays the continuous feedback. +*/ +void HbFeedbackEffectEngine::playContinuousFeedback(const HbWidget* widget, HbFeedback::ContinuousEffect effect, int intensity) +{ + const QGraphicsView* view = widget->mainWindow(); + if (view && HbFeedbackEffectUtils::isFeedbackAllowed(widget)) { + HbContinuousFeedback feedback(effect,view); + feedback.setRect(widget, view); + feedback.setIntensity(intensity); + + if (hbFeedbackPlayer && feedback.isLocated()) { + // if continuous feedback is still active and not stopped by continuous feedback timeout + if (continuousFeedbacks.contains(widget) + && hbFeedbackPlayer->continuousFeedbackOngoing(continuousFeedbacks.value(widget))) { + hbFeedbackPlayer->updateContinuousFeedback(continuousFeedbacks.value(widget), feedback); + } else { + // if timeout has happened remove the item from the map storing continuous feedback identifiers + if (continuousFeedbacks.contains(widget)) { + continuousFeedbacks.remove(widget); + } + // create a new continuous feedback + continuousFeedbacks.insert(widget, hbFeedbackPlayer->startContinuousFeedback(feedback)); + } + } + } +} + +/*! + Cancels the playing of a continuous feedback. +*/ +void HbFeedbackEffectEngine::cancelContinuousFeedback(const HbWidget* widget) +{ + if (hbFeedbackPlayer && continuousFeedbacks.contains(widget)) { + hbFeedbackPlayer->cancelContinuousFeedback(continuousFeedbacks.take(widget)); + } +} +