diff -r 000000000000 -r 15bf7259bb7c uiacceltk/hitchcock/coretoolkit/src/HuiRosterImpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uiacceltk/hitchcock/coretoolkit/src/HuiRosterImpl.cpp Tue Feb 02 07:56:43 2010 +0200 @@ -0,0 +1,1709 @@ +/* +* Copyright (c) 2006-2007 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: Implementation of CHuiRosterImpl. CHuiRosterImpl implements +* the interface defined by CHuiRoster. +* +*/ + + + +#include "HuiRosterImpl.h" // Class definition +#include "HuiRosterEntry.h" +#include "uiacceltk/HuiEnv.h" +#include "uiacceltk/HuiControlGroup.h" +#include "uiacceltk/HuiControl.h" +#include "uiacceltk/HuiDisplay.h" +#include "uiacceltk/HuiEvent.h" +#include "uiacceltk/HuiTransformation.h" +#include "uiacceltk/HuiPanic.h" +#include "uiacceltk/HuiUtil.h" +#include "uiacceltk/HuiProbe.h" +#include "uiacceltk/HuiCanvasVisual.h" +#include "huilongtapdetector.h" +#include "HuiFxEffect.h" +#include "huieffectable.h" +#include "huicanvasrenderbuffer.h" +#include "huicanvasgc.h" +#include "HuiRenderPlugin.h" + +#ifdef RD_TACTILE_FEEDBACK +#include +#endif //RD_TACTILE_FEEDBACK + +const TReal32 KHuiVisualOutlineWidth = 1.f; + +struct THuiPointerEventDetails + { + MHuiEventHandler* iEventHandler; + THuiXYMetric iXYMetric; + TBool iDisableLongTapWhenDragging; + TBool iDragging; + }; + + + +CHuiRosterImpl::CHuiRosterImpl(CHuiDisplay* aDisplay) + : iDisplay(aDisplay), iInitialDownEvent(NULL), iEffectOpacity(1.f) + { + } + +CHuiRosterImpl::~CHuiRosterImpl() + { + FreezeVisibleContentL(EFalse); + + delete iLongTapDetector; + iEntries.ResetAndDestroy(); + iPointerDragObservers.Close(); + iDisplay = NULL; + iInputFocus = NULL; + iUnhandledPointerObservers.Close(); + iLongTapObservers.Close(); + while(iPointerEventDetails.Count()>0) + { + delete iPointerEventDetails[0]; + iPointerEventDetails.Remove(0); + } + iPointerEventDetails.ResetAndDestroy(); + } + + +void CHuiRosterImpl::SetDisplay(CHuiDisplay* aDisplay) + { + iDisplay = aDisplay; + } + + +void CHuiRosterImpl::SetRect(const TRect& aRect) + { + iRect = TRect(0, 0, aRect.Width(), aRect.Height()); + UpdateLayout(); + + SetChanged(); + } + + +TRect CHuiRosterImpl::Rect() const + { + return(iRect); + } + + +void CHuiRosterImpl::ShowL(CHuiControlGroup& aGroup, TInt aWhere) + { + // If the group is already shown on the display, just adjust its position + // according to the parameters. + if(Find(&aGroup) != KErrNotFound) + { + // It is already shown. Only adjust position. + TInt newPos = aWhere; + if(newPos == KHuiRosterShowAtTop) + { + newPos = Count() - 1; + } + else if(newPos == KHuiRosterShowAtBottom) + { + newPos = 0; + } + else + { + // for PC lint + } + Move(&aGroup, newPos); + return; + } + + if(aWhere == KHuiRosterShowAtTop) + { + // Put the group on top of the roster. + AppendL(&aGroup); + } + else if(aWhere == KHuiRosterShowAtBottom) + { + InsertL(&aGroup, 0); + } + else + { + InsertL(&aGroup, aWhere); + } + + // The group will automatically accept input events once shown. + aGroup.SetAcceptInput(ETrue); + + // Show all the controls of the group. + for(TInt i = 0; i < aGroup.Count(); ++i) + { + aGroup.Control(i).ShowL(*iDisplay); + } + } + + +void CHuiRosterImpl::Hide(CHuiControlGroup& aGroup) + { + // Hide all the controls of the group. + for(TInt i = 0; i < aGroup.Count(); ++i) + { + aGroup.Control(i).Hide(*iDisplay); + } + + Remove(&aGroup); + } + + +void CHuiRosterImpl::AppendL(CHuiControlGroup* aGroup) + { + ASSERT( aGroup ); + CHuiRosterEntry* entry = new (ELeave) CHuiRosterEntry(*aGroup); + CleanupStack::PushL(entry); + User::LeaveIfError(iEntries.Append(entry)); + CleanupStack::Pop(entry); + + if(iDisplay) + { + iDisplay->Env().ContinueRefresh(); + } + + SetChanged(); + } + + +void CHuiRosterImpl::InsertL(CHuiControlGroup* aGroup, TInt aPos) + { + ASSERT( aGroup ); + if(Find(aGroup) != KErrNotFound) + { + User::Leave(KErrAlreadyExists); + } + + CHuiRosterEntry* entry = new (ELeave) CHuiRosterEntry(*aGroup); + CleanupStack::PushL(entry); + User::LeaveIfError(iEntries.Insert(entry, aPos)); + CleanupStack::Pop(entry); + + if(iDisplay) + { + iDisplay->Env().ContinueRefresh(); + } + + SetChanged(); + } + +void CHuiRosterImpl::Move(CHuiVisual* aVisual, TInt aPos) + { + CHuiRosterEntry* entry = EntryForVisual(aVisual); + if (entry) + { + Move(&entry->ControlGroup(), aPos); + } + } + +void CHuiRosterImpl::Move(CHuiControlGroup* aGroup, TInt aPos) + { + TInt index = Find(aGroup); + TInt k = 0; + + if(index != KErrNotFound && index != aPos) + { + CHuiRosterEntry* moving = iEntries[index]; + + if(aPos > index) + { + for(k = index; k < aPos; ++k) + { + iEntries[k] = iEntries[k + 1]; + } + } + else + { + for(k = index; k > aPos; --k) + { + iEntries[k] = iEntries[k - 1]; + } + } + iEntries[aPos] = moving; + } + + if(iDisplay) + { + iDisplay->Env().ContinueRefresh(); + } + + SetChanged(); + } + + +TInt CHuiRosterImpl::Find(CHuiControlGroup* aGroup) const + { + for(TInt i = 0; i < iEntries.Count(); ++i) + { + if(&iEntries[i]->ControlGroup() == aGroup) + { + return i; + } + } + return KErrNotFound; + } + + +void CHuiRosterImpl::Remove(CHuiControlGroup* aGroup) + { + TInt index = Find(aGroup); + if(index != KErrNotFound) + { + delete iEntries[index]; + iEntries.Remove(index); + + if(iDisplay) + { + iDisplay->Env().ContinueRefresh(); + } + + SetChanged(); + } + } + + +TInt CHuiRosterImpl::Count() const + { + return iEntries.Count(); + } + + +CHuiControlGroup& CHuiRosterImpl::ControlGroup(TInt aIndex) const + { + return iEntries[aIndex]->ControlGroup(); + } + + +CHuiControl* CHuiRosterImpl::FindControl(TInt aControlId) const + { + CHuiControl* control = 0; + for(TInt i = 0; i < iEntries.Count(); ++i) + { + control = iEntries[i]->ControlGroup().FindControl(aControlId); + if(control) + { + break; + } + } + return control; + } + + +CHuiRosterEntry* CHuiRosterImpl::EntryForVisual(const CHuiVisual* aVisual) + { + ASSERT( aVisual != NULL ); + CHuiControlGroup* group = aVisual->Owner().ControlGroup(); + TInt index = Find(group); + if(index == KErrNotFound) + { + // The group is not in this roster. + return NULL; + } + return iEntries[index]; + } + + +void CHuiRosterImpl::ShowVisualL(CHuiVisual* aVisual) + { + CHuiRosterEntry* entry = EntryForVisual(aVisual); + + if(!entry) + { + User::Leave(KErrNotFound); + } + + if(entry->iRootVisuals.Find(aVisual) != KErrNotFound) + { + User::Leave(KErrAlreadyExists); + } + + User::LeaveIfError( entry->iRootVisuals.Append(aVisual) ); + + SetVisualToFullArea(aVisual); + } + + +void CHuiRosterImpl::HideVisual(CHuiVisual* aVisual) + { + ASSERT( aVisual ); + aVisual->SetDisplay(NULL); + + CHuiRosterEntry* entry = EntryForVisual(aVisual); + if(entry) + { + TInt index = entry->iRootVisuals.Find(aVisual); + if(index != KErrNotFound) // do nothing if visual was not found + { + entry->iRootVisuals.Remove(index); + + if(iDisplay) + { + iDisplay->Env().ContinueRefresh(); + } + } + } + } + + +void CHuiRosterImpl::SetFocus(CHuiControl& aControl) + { + ChangeInputFocus(&aControl); + } + + +void CHuiRosterImpl::ClearFocus() + { + ChangeInputFocus(NULL); + } + + +void CHuiRosterImpl::ChangeInputFocus(CHuiControl* aControl) + { + if(aControl) + { + // The control must be in one of groups of the roster. + CHuiControl* control = FindControl(aControl->Id()); + if(control != aControl) + { + // Illegal focus. + return; + } + } + + iInputFocus = aControl; + } + +TBool CHuiRosterImpl::PrepareDraw() const + { + HUI_PROBE_PROGRAMFLOW_ENTER(MHuiProbe::EProgramFlowPointRefreshPrepareDraw) + + TInt i = 0; + TInt j = 0; + + TInt visualCount = 0; + TInt entryCount = iEntries.Count(); + // Prepare the visuals tree in the display. + for(j = 0; j < entryCount; ++j) + { + CHuiRosterEntry& entry = *iEntries[j]; + + visualCount = entry.iRootVisuals.Count(); + for(i = 0; i < visualCount; ++i) + { + CHuiVisual* visual = entry.iRootVisuals[i]; + //Ignore inactive visuals + if ( visual->Flags()& EHuiVisualFlagInactive ) + { + continue; + } + TBool successfullyPrepared = ETrue; + TRAPD(err, successfullyPrepared = visual->PrepareDrawL()); + if (err != KErrNone) + { + // Handle the error by calling the visual owner + // errorhandling callback + visual->Owner().VisualPrepareDrawFailed(*visual, err); + + HUI_PROBE_PROGRAMFLOW_EXIT(MHuiProbe::EProgramFlowPointRefreshPrepareDraw) + return EFalse; + } + if (!successfullyPrepared) + { + // we can stop preparing the rest of the root visuals + // if one prepare failed (we won't be drawing + // anything anyway) + + // also if the prepare failed but it didn't leave, + // we assume it was already handled + + HUI_PROBE_PROGRAMFLOW_EXIT(MHuiProbe::EProgramFlowPointRefreshPrepareDraw) + return EFalse; + } + } + } + + HUI_PROBE_PROGRAMFLOW_EXIT(MHuiProbe::EProgramFlowPointRefreshPrepareDraw) + return ETrue; + } + + +void CHuiRosterImpl::Draw(CHuiGc& aGc) const + { + Draw(aGc, NULL); + } + +void CHuiRosterImpl::Draw(CHuiGc& aGc, CHuiDisplay* aDisplay) const + { + CHuiDisplay* display = aDisplay ? aDisplay : iDisplay; + THuiRealRect displayRect = display->VisibleArea(); + TBool refreshCache = ETrue; // TODO: Could this be optimized ? + TBool opaque = EFalse; + + // Init projection matrix + aGc.LoadIdentity(EHuiGcMatrixProjection); + + // Init model matrix + aGc.LoadIdentity(EHuiGcMatrixModel); + + // Set up display-specifc window transformations e.g. scaling for tv out + aGc.SetWindowTransformation(&(display->WindowTransformation())); + aGc.UpdateProjection(); + + TBool didDrawEffect = EFalse; + if (iEffect) + { + //RDebug::Print(_L("CHuiRosterImpl::Draw trying to use effect")); + TRgb oldColor = aGc.PenColor(); + TInt oldAlpha = aGc.PenAlpha(); + + // Clear + aGc.SetPenColor(KRgbBlack); + aGc.SetPenAlpha(0); + aGc.Disable(CHuiGc::EFeatureBlending); + aGc.Disable(CHuiGc::EFeatureClipping); + aGc.Clear(); + + // Restore Gc values + aGc.SetPenColor(oldColor); + aGc.SetPenAlpha(oldAlpha); + aGc.Enable(CHuiGc::EFeatureBlending); + aGc.Enable(CHuiGc::EFeatureClipping); + + // Note: Opacity implementation in effect system does not really work visually + // correct if there are semitransparent child windows. Child window opacity becomes too + // large, because opacity is applied during visual tree drawing and thus blending child + // visuals on top of the parent produces wrong transparency level. + // + // We workaround this issue here so that we force rendering to cached render + // target (with opacity 255) and give the real opacity as a parameter to effect + // drawing so the whole operation gets correct opacity. However there is possibility + // that complex effect fxml would assume transparency to be handled *before* + // some other part of the effect, so this workaround won't work correctly in those cases. + // To get those working, propably whole opacity effect handling should be re-written + // differently. + if (iEffect->IsSemitransparent() || iEffectOpacity < 1.f) + { + iEffect->ForceCachedRenderTargetUsage(ETrue); + } + RRegion dummy; + didDrawEffect = iEffect->CachedDraw(aGc, displayRect, refreshCache, opaque, dummy, iEffectOpacity*255); + dummy.Close(); + } + + if (!didDrawEffect) + { + DrawSelf(aGc, aDisplay); + } + else + { + // Effect was drawn, OpenGLES/OpenVG may be in different state than what Gc thinks so we restore it. + aGc.RestoreState(); + } + + // Undo display-specifc window transformations + aGc.SetWindowTransformation(NULL); + aGc.UpdateProjection(); + + // Undo changes to model matrix + aGc.LoadIdentity(EHuiGcMatrixModel); + } + +void CHuiRosterImpl::DrawSelf(CHuiGc& aGc, CHuiDisplay* aDisplay) const + { + HUI_PROBE_PROGRAMFLOW_ENTER(MHuiProbe::EProgramFlowPointRefreshDraw) + + TInt i = 0; + TInt j = 0; + + CHuiDisplay* display = aDisplay ? aDisplay : iDisplay; + + if (iCanvasRenderBuffer && iCanvasGc) + { + DrawSelfFrozen(aGc, aDisplay); + return; + } + + TInt visualCount = 0; + TInt entryCount = iEntries.Count(); + // Draw the visuals tree in the display. + for(j = 0; j < entryCount; ++j) + { + CHuiRosterEntry& entry = *iEntries[j]; + CHuiControlGroup& group = entry.ControlGroup(); + + // Init model matrix always for every group + //aGc.LoadIdentity(EHuiGcMatrixModel); + aGc.Push(EHuiGcMatrixModel); + + // Set up display-specifc transformations i.e. camera transformations + display->Transformation().Execute(EHuiGcMatrixModel, aGc); + + // Set up a group-specific transformation. + if(group.IsTransformed()) + { + group.Transformation().Execute(EHuiGcMatrixModel, aGc); + } + + // Draw visuals + visualCount = entry.iRootVisuals.Count(); + for(i = 0; i < visualCount; ++i) + { + CHuiVisual* visual = entry.iRootVisuals[i]; + //Ignore inactive visuals + if ( visual->Flags()& EHuiVisualFlagInactive || visual->LoadingEffect() ) + { + continue; + } + visual->Draw(aGc); + } + + if( display->DrawVisualOutline() != CHuiDisplay::EDrawVisualOutlineNone ) + { + for(i = 0; i < visualCount; ++i) + { + // Draw Visual Outline depending on central repository setting + // and visual flag value + const TBool drawOutline = + ( entry.iRootVisuals[i]->Flags() & EHuiVisualFlagEnableDebugMode ) || + ( display->DrawVisualOutline() == CHuiDisplay::EDrawVisualOutlineAllVisuals ); + + DrawBoundaries( aGc, entry.iRootVisuals[i], drawOutline ); + } + } + + aGc.Pop(EHuiGcMatrixModel); + } + + HUI_PROBE_PROGRAMFLOW_EXIT(MHuiProbe::EProgramFlowPointRefreshDraw) + } + +void CHuiRosterImpl::DrawSelfFrozen(CHuiGc& aGc, CHuiDisplay* aDisplay) const + { + if (iCanvasGc && iCanvasRenderBuffer) + { + iCanvasGc->SetGc(aGc); + iCanvasGc->SetDefaults(); + iCanvasGc->PushTransformationMatrix(); + + // Calculate rotation as relative to the current display rotation. + CHuiGc::TOrientation relativeOrientation = CHuiGc::EOrientationNormal; + CHuiGc::TOrientation displayOrientation = aDisplay->Orientation(); + CHuiGc::TOrientation renderBufferOrientation = iCanvasRenderBufferOrientation; + + TInt rotationAngle[] = + { + 0, + 270, + 90, + 180 + }; + + TInt displayOrientationAngle = rotationAngle[displayOrientation]; + TInt renderBufferOrientationAngle = rotationAngle[renderBufferOrientation]; + TInt relativeOrientationAngle = renderBufferOrientationAngle - displayOrientationAngle; + + // Check over/underflow + if (relativeOrientationAngle > 360) + { + relativeOrientationAngle -= 360; + } + else if (relativeOrientationAngle < 0) + { + relativeOrientationAngle += 360; + } + + switch (relativeOrientationAngle) + { + case 0: + { + relativeOrientation = CHuiGc::EOrientationNormal; + break; + } + case 90: + { + relativeOrientation = CHuiGc::EOrientationCW90; + break; + } + case 270: + { + relativeOrientation = CHuiGc::EOrientationCCW90; + break; + } + case 180: + { + relativeOrientation = CHuiGc::EOrientation180; + break; + } + default: + { + // As usual, this should not happen...but just in case it does use normal rotation + relativeOrientation = CHuiGc::EOrientationNormal; + break; + } + } + + TRect displayArea = aDisplay->VisibleArea(); + TInt w = displayArea.Width(); + TInt h = displayArea.Height(); + + + // ...select right rotation... + if (relativeOrientation == CHuiGc::EOrientationCW90) + { + // Rotate around origo and move back to displayarea + iCanvasGc->Rotate(-90, 0, 0, 1.f); + iCanvasGc->Translate(-h, 0, 0); + } + else if (relativeOrientation == CHuiGc::EOrientationCCW90) + { + // Rotate around origo and move back to displayarea + iCanvasGc->Rotate(90, 0, 0, 1.f); + iCanvasGc->Translate(0, -w, 0); + } + else if (relativeOrientation == CHuiGc::EOrientation180) + { + // Rotate around origo and move back to displayarea + iCanvasGc->Rotate(180, 0, 0, 1.f); + iCanvasGc->Translate(-w, -h, 0); + } + else + { + // Nothing + } + + // Pixels are upside down in OpenVG canvas render buffer + if (CHuiStatic::Env().Renderer() == EHuiRendererVg10) + { + TInt height = h; + if (relativeOrientation == CHuiGc::EOrientationCW90 || relativeOrientation == CHuiGc::EOrientationCCW90) + { + height = w; + } + iCanvasGc->Translate(0.0f, height, 0.0f); + iCanvasGc->Scale(1.f, -1.f, 1.f); + } + + iCanvasGc->DrawImage(*iCanvasRenderBuffer, TPoint(0,0)); + iCanvasGc->PopTransformationMatrix(); + } + } + +void CHuiRosterImpl::DrawBoundaries( CHuiGc& aGc, CHuiVisual* aVisual, TBool aDrawOutline ) const + { + if( aDrawOutline ) + { + const THuiRealRect content = aVisual->DisplayRect(); + + if (aVisual->Flags()& EHuiVisualFlagInactive) + { + aGc.SetPenColor( KRgbDarkGray ); + } + else + { + aGc.SetPenColor( TUint32(aVisual)&0x00ffffff/*KRgbBlack*/ ); // Use "random" color + } + aGc.DrawBorders(content.Round(), + KHuiVisualOutlineWidth, KHuiVisualOutlineWidth, + KHuiVisualOutlineWidth, KHuiVisualOutlineWidth, + CHuiGc::EBorderFixedCorners); + } + + for( TInt k = 0; k < aVisual->Count(); ++k ) + { + DrawBoundaries( + aGc, + &aVisual->Visual( k ), + ( ( aVisual->Visual( k ).Flags() & EHuiVisualFlagEnableDebugMode ) || + aDrawOutline ) ); + } + } + + +TBool CHuiRosterImpl::HasTransformedControlGroups() const + { + TInt j = 0; + for(j = 0; j < iEntries.Count(); ++j) + { + CHuiRosterEntry& entry = *iEntries[j]; + CHuiControlGroup& group = entry.ControlGroup(); + if(group.IsTransformed()) + { + return ETrue; + } + } + return EFalse; + } + + +TBool CHuiRosterImpl::HandleEventL(const THuiEvent& aEvent) + { + TInt i = 0; + TInt k = 0; + + if(iDisplay) + { + iDisplay->Env().ContinueRefresh(); + } + + if(aEvent.IsPointerEvent()) + { + iTactileFeedbackHandled = EFalse; + + // Put event details array up to date + CleanEventDetails(); + + if ( !iLongTapDetector ) + { + iLongTapDetector = CHuiLongTapDetector::NewL( *this ); + } + iLongTapDetector->OfferPointerEvent( aEvent ); + + if ( aEvent.PointerDown() ) + { + iInitialDownEvent = aEvent; + CleanDraggingFlags(); + } + + + // Restricted distribution? + if(aEvent.iPointerEvent.iType == TPointerEvent::EDrag) + { + // Only send these if there are observers. + for(i = 0; i < iPointerDragObservers.Count(); ++i) + { + if( DragEventOutOfRangeL( &iPointerDragObservers[i], aEvent) ) + { + if(iPointerDragObservers[i].OfferEventL(aEvent)) + { + return ETrue; + } + } + } + return EFalse; + } + + // The event is generated by the long tap detector + if(aEvent.iPointerEvent.iType == TPointerEvent::EButtonRepeat) + { + // Only send these if there are observers. + for(i = 0; i < iLongTapObservers.Count(); ++i) + { + if(IsLongTapEventAllowed(&iLongTapObservers[i])) + { + if(iLongTapObservers[i].OfferEventL(aEvent)) + { + return ETrue; + } + } + } + return EFalse; + } + + // The other pointer events are offered depending on the visuals. + for(i = iEntries.Count() - 1; i >= 0; --i) + { + CHuiRosterEntry& entry = *iEntries[i]; + CHuiControlGroup& group = entry.ControlGroup(); + + if(!group.AcceptInput()) + { + // The group will not be receiving input events. + continue; + } + + for(k = entry.iRootVisuals.Count() - 1; k >= 0; --k) + { + if(OfferPointerEventWithinTreeL(*entry.iRootVisuals[k], aEvent)) + { + return ETrue; + } + } + + // Offer to the fallback handlers of the group. + for(k = 0; k < group.iUnhandledEventObservers.Count(); ++k) + { + if(group.iUnhandledEventObservers[k].OfferEventL(aEvent)) + { + return ETrue; + } + } + } + + // No one handled the event. + for(i = 0; i < iUnhandledPointerObservers.Count(); ++i) + { + if(iUnhandledPointerObservers[i].OfferEventL(aEvent)) + { + return ETrue; + } + } + } + else + { + // First offer to the input control. + if(aEvent.IsKeyEvent() && iInputFocus && iInputFocus->AcceptInput()) + { + if(iInputFocus->OfferEventL(aEvent)) + { + return ETrue; + } + } + + // Iterate through the groups and controls in priority order. + for(i = iEntries.Count() - 1; i >= 0; --i) + { + CHuiControlGroup& group = iEntries[i]->ControlGroup(); + + if(!group.AcceptInput()) + { + // The group will not be receiving input events. + continue; + } + + for(k = group.Count() - 1; k >= 0; --k) + { + CHuiControl& control = group.Control(k); + if(control.OfferEventL(aEvent)) + { + // The event was consumed, now it can't be handled by + // anyone else. + return ETrue; + } + } + // Notify observer that group didn't handle event? + } + } + + return EFalse; + } + + +TBool CHuiRosterImpl::OfferPointerEventWithinTreeL(CHuiVisual& aVisual, const THuiEvent& aEvent, TBool aUseDispRect) + { + //Ignore inactive visuals + if( ( aVisual.Flags() & EHuiVisualFlagIgnorePointer ) || + ( aVisual.Flags() & EHuiVisualFlagInactive ) ) + { + // Discard the entire branch of visuals. + return EFalse; + } + + const TPoint& pos = aEvent.iPointerEvent.iPosition; + + TBool useDispRect = EFalse; + // If it has children, offer to those first. + for(TInt i = aVisual.Count() - 1; i >= 0; --i) + { + // set useDispRect, if scroll is enabled on a layout + useDispRect = static_cast(aVisual).Scrolling(); + + if(OfferPointerEventWithinTreeL(aVisual.Visual(i), aEvent, useDispRect)) + { + return ETrue; + } + } + + TRect visualRect; + if(aUseDispRect) + { + visualRect = TRect(aVisual.DisplayRect()); + } + else + { + // use cashed display rect + visualRect = TRect(aVisual.CachedDisplayRect()); + } + + // Offer to the visual itself. + if(visualRect.Contains(pos)) + { + HUI_DEBUG3(_L("CHuiRosterImpl::OfferPointerEventWithinTreeL: aVisual=%x pos=%i,%i"), + &aVisual, pos.iX, pos.iY); + + MHuiEventHandler* handler = aVisual.Owner().EventHandler(); + if(handler) + { + THuiEvent eventWithVisual = aEvent; + eventWithVisual.SetVisual(&aVisual); + HandleTactileFeedback( eventWithVisual ); + if(handler->OfferEventL(eventWithVisual)) + { + return ETrue; + } + } + } + + // Not consumed. + return EFalse; + } + + +TBool CHuiRosterImpl::Changed() const + { + if(iChanged) + { + return ETrue; + } + + TInt entryCount = iEntries.Count(); + for(TInt i = 0; i < entryCount; ++i) + { + if(iEntries[i]->ControlGroup().Changed()) + { + return ETrue; + } + } + + if (iEffect && iEffect->Changed()) + { + return ETrue; + } + + return EFalse; + } + + +void CHuiRosterImpl::ScanDirty() + { + if(Changed()) + { + // If the entire roster has changed, there is no need to query + // individual visuals. + if(iDisplay) + { + iDisplay->AddDirtyRegion(iRect); + } + + SetChanged(EFalse); + return; + } + + if (iDisplay && !iDisplay->IsDirtyScanNeeded()) + { + // Dirty scan is not needed, we can return directly. + return; + } + + TInt entryCount = iEntries.Count(); + for(TInt j = 0; j < entryCount; ++j) + { + CHuiRosterEntry& entry = *iEntries[j]; + TInt count = entry.iRootVisuals.Count(); + for(TInt i = 0; i < count; ++i) + { + //Ignore inactive visuals + if ( entry.iRootVisuals[i]->Flags()& EHuiVisualFlagInactive ) + { + continue; + } + entry.iRootVisuals[i]->ReportChanged(); + } + } + } + + +// This ScanDirty-method supports transformed dirty rects +void CHuiRosterImpl::ScanTransformedDirty(CHuiGc& aGc, CHuiDisplay* aDisplay) + { + CHuiDisplay* display = aDisplay ? aDisplay : iDisplay; + + // Init projection matrix + aGc.LoadIdentity(EHuiGcMatrixProjection); + + // Set up display-specifc window transformations e.g. scaling for tv out + aGc.SetWindowTransformation(&(display->WindowTransformation())); + aGc.UpdateProjection(); + + if(Changed()) + { + // If the entire roster has changed, there is no need to query + // individual visuals. + if(display) + { + display->AddDirtyRegion(iRect); + } + + SetChanged(EFalse); + } + + for(TInt j = 0; j < iEntries.Count(); ++j) + { + if (display && !display->IsDirtyScanNeeded()) + { + break; + } + + CHuiRosterEntry& entry = *iEntries[j]; + CHuiControlGroup& group = entry.ControlGroup(); + + // Init model matrix always for every group + aGc.LoadIdentity(EHuiGcMatrixModel); + + // Set up display-specifc transformations i.e. camera transformations + __ASSERT_DEBUG(display, USER_INVARIANT()); + display->Transformation().Execute(EHuiGcMatrixModel, aGc); + + // Set up a group-specific transformation. + if(group.IsTransformed()) + { + group.Transformation().Execute(EHuiGcMatrixModel, aGc); + } + + for(TInt i = 0; i < entry.iRootVisuals.Count(); ++i) + { + if (display && !display->IsDirtyScanNeeded()) + { + break; + } + //Ignore inactive visuals + if ( entry.iRootVisuals[i]->Flags()& EHuiVisualFlagInactive ) + { + continue; + } + entry.iRootVisuals[i]->ReportChanged(); + } + } + + // Undo display-specifc window transformations + aGc.SetWindowTransformation(NULL); + aGc.UpdateProjection(); + + // Undo changes to model matrix + aGc.LoadIdentity(EHuiGcMatrixModel); + } + + +void CHuiRosterImpl::MoveVisualToFront(CHuiVisual* aRootVisual) + { + ASSERT( aRootVisual ); + MoveVisualToFront(*aRootVisual); + } + + +void CHuiRosterImpl::MoveVisualToFront(const CHuiVisual& aRootVisual) + { + CHuiRosterEntry* entry = EntryForVisual(&aRootVisual); + __ASSERT_ALWAYS( entry != NULL, THuiPanic::Panic(THuiPanic::ERosterGroupNotFound) ); + TInt index = entry->iRootVisuals.Find(&aRootVisual); + if(index == KErrNotFound) + { + /** @todo Panic? */ + return; + } + + entry->iRootVisuals.Remove(index); + entry->iRootVisuals.Append(&aRootVisual); + + UpdateLayout(); + } + + +void CHuiRosterImpl::UpdateLayout() + { + SetChanged(); + + TInt visualCount = 0; + TInt entryCount = iEntries.Count(); + for(TInt i = 0; i < entryCount; ++i) + { + visualCount = iEntries[i]->iRootVisuals.Count(); + for(TInt j = 0; j < visualCount; ++j) + { + //Ignore inactive visuals + if ( iEntries[i]->iRootVisuals[j]->Flags()& EHuiVisualFlagInactive ) + { + continue; + } + SetVisualToFullArea(iEntries[i]->iRootVisuals[j]); + } + } + } + + +void CHuiRosterImpl::SetVisualToFullArea(CHuiVisual* aVisual) + { + ASSERT( aVisual ); + + TInt globalTransitionTime = CHuiStatic::LayoutTransitionTime(); + + // Root visuals are automatically full size. + /** @todo Needs a better way to set the visual's display. */ + if(iDisplay) + { + aVisual->SetDisplay(iDisplay); + iDisplay->Env().ContinueRefresh(); + } + + if(!(aVisual->Flags() & EHuiVisualFlagManualPosition)) + { + aVisual->SetPos(iRect.iTl, globalTransitionTime); + } + + if(!(aVisual->Flags() & EHuiVisualFlagManualSize)) + { + aVisual->SetSize(iRect.Size(), globalTransitionTime); + } + else + { + aVisual->UpdateChildrenLayout(globalTransitionTime); + } + + aVisual->ReportLayoutUpdate(); + } + + +void CHuiRosterImpl::NotifySkinChangedL() + { + TInt visualCount = 0; + TInt entryCount = iEntries.Count(); + for(TInt j = 0; j < entryCount; ++j) + { + CHuiRosterEntry& entry = *iEntries[j]; + visualCount = entry.iRootVisuals.Count(); + for(TInt i = 0; i < visualCount; ++i) + { + //Ignore inactive visuals + if ( entry.iRootVisuals[i]->Flags()& EHuiVisualFlagInactive ) + { + continue; + } + entry.iRootVisuals[i]->NotifySkinChangedL(); + } + } + } + + +void CHuiRosterImpl::DumpRootLevelTrees() const + { + TInt visualCount = 0; + TInt entryCount = iEntries.Count(); + for(TInt j = 0; j < entryCount; ++j) + { + CHuiRosterEntry& entry = *iEntries[j]; + visualCount = entry.iRootVisuals.Count(); + for(TInt i = 0; i < visualCount; ++i) + { + CHuiVisual* visual = entry.iRootVisuals[i]; + visual->DumpTree(); + } + } + } + + +void CHuiRosterImpl::ClearChanged() + { + HUI_DEBUGF(_L("CHuiRosterImpl::ClearChanged() - Clearing all change flags.")); + + TInt visualCount = 0; + TInt entryCount = iEntries.Count(); + for(TInt j = 0; j < entryCount; ++j) + { + CHuiRosterEntry& entry = *iEntries[j]; + visualCount = entry.iRootVisuals.Count(); + for(TInt i = 0; i < visualCount; ++i) + { + // Ignore inactive visuals + if ( entry.iRootVisuals[i]->Flags()& EHuiVisualFlagInactive ) + { + continue; + } + + // This will clear the change flags of the entire tree of visuals. + entry.iRootVisuals[i]->ClearChanged(); + } + } + } + + +void CHuiRosterImpl::SetChanged(TBool aIsChanged) + { + if(aIsChanged && !iChanged) + { + HUI_DEBUG(_L("CHuiRosterImpl::SetChanged() - Roster flagged as changed.")); + } + else if(!aIsChanged && iChanged) + { + HUI_DEBUG(_L("CHuiRosterImpl::SetChanged() - Roster change flag cleared.")); + } + else + { + // for PC lint + } + + iChanged = aIsChanged; + } + + +RHuiObserverArray& CHuiRosterImpl::Observers(THuiInputType aInputType) + { + switch(aInputType) + { + case EHuiInputPointerDrag: + return iPointerDragObservers; + + case EHuiInputPointerLongTap: + return iLongTapObservers; + + case EHuiInputPointerUnhandled: + return iUnhandledPointerObservers; + + default: + HUI_PANIC(THuiPanic::ERosterUnknownInputObserverType) + return iPointerDragObservers; // never reached + } + } + +void CHuiRosterImpl::HandleTactileFeedback( const THuiEvent& aEvent ) + { + // If tactile feedback has been already deciede for this event.... + if ( iTactileFeedbackHandled ) + { + return; + } + + // The tactile feedback is defined on visual basis + if ( !aEvent.Visual() ) + { + // no visual, no feedback + return; + } + + // Only pointer events + if ( !aEvent.IsPointerEvent() ) + { + return; + } + + // Currently support only pointer down events + if ( !aEvent.PointerDown() ) + { + return; + } + + const TInt eventType = 0; // = ETouchEventStylusDown + + // Check if the viusal has a tactile feedback specified + const TInt feedbackType = aEvent.Visual()->TactileFeedback( eventType ); + + if ( feedbackType != KErrNotFound ) + { + iTactileFeedbackHandled = ETrue; // Handling it now. + +#ifdef RD_TACTILE_FEEDBACK + MTouchFeedback* feedback = MTouchFeedback::Instance(); + if ( feedback ) + { + feedback->InstantFeedback( (TTouchLogicalFeedback)feedbackType ); + } +#else + +#ifdef _DEBUG + // for RnD + switch( feedbackType ) + { + case 0: // none + User::InfoPrint( _L("None") ); + break; + case 1: // basic + User::InfoPrint( _L("Basic") ); + break; + case 2: // sensitive + User::InfoPrint( _L("Sensitive") ); + break; + default: + break; + } +#endif // _DEBUG + +#endif + } + } + +// Adds new detail entry to iPointerEventDetails +void CHuiRosterImpl::AddEventDetailsL(MHuiEventHandler* aEventHandler, const THuiXYMetric& aXYMetric, TBool aDisable) + { + THuiPointerEventDetails* newDetails = new (ELeave) THuiPointerEventDetails; + newDetails->iEventHandler = aEventHandler; + newDetails->iXYMetric = aXYMetric; + newDetails->iDisableLongTapWhenDragging = aDisable; + newDetails->iDragging = EFalse; + TInt err = iPointerEventDetails.Append(newDetails); + if ( err != KErrNone ) + { + delete newDetails; + User::Leave( err ); + } + } + +// Cleans entries from iPointerEventDetails if there isn't observer for +// that event handler +void CHuiRosterImpl::CleanEventDetails() + { + TInt i = 0; + + while(i < iPointerEventDetails.Count()) + { + TBool used = EFalse; + + // Check in drag observers + for(TInt j = 0; j < iPointerDragObservers.Count(); ++j) + { + if(iPointerEventDetails[i]->iEventHandler == &iPointerDragObservers[j]) + { + used = ETrue; + break; + } + } + + // Check in long tap observers + if(!used) + { + for(TInt j = 0; j < iLongTapObservers.Count(); ++j) + { + if(iPointerEventDetails[i]->iEventHandler == &iLongTapObservers[j]) + { + used = ETrue; + break; + } + } + } + + // Check in unhandled observers + if(!used) + { + for(TInt j = 0; j < iUnhandledPointerObservers.Count(); ++j) + { + if(iPointerEventDetails[i]->iEventHandler == &iUnhandledPointerObservers[j]) + { + used = ETrue; + break; + } + } + } + + // If event handler isn't found in observers, we remove details for that + // event handler from iPointerEventDetails + if(!used) + { + delete iPointerEventDetails[i]; + iPointerEventDetails.Remove(i); + } + else + { + i++; + } + } + } + +// Cleans dragging flags in iPointerEventDetails +void CHuiRosterImpl::CleanDraggingFlags() + { + for(TInt i = 0; i < iPointerEventDetails.Count(); ++i) + { + iPointerEventDetails[i]->iDragging = EFalse; + } + } + +// Sets treshold which pointer needs to be moved before starting to send drag events. +void CHuiRosterImpl::SetPointerDragThresholdL(const MHuiEventHandler& aEventHandler, const THuiXYMetric& aXYMetric) + { + MHuiEventHandler *handler = (MHuiEventHandler*)&aEventHandler; + + // Check if there is already detail entry in iPointerEventDetails where to update + // details + for(TInt i = 0; i < iPointerEventDetails.Count(); ++i) + { + if(iPointerEventDetails[i]->iEventHandler == handler) + { + iPointerEventDetails[i]->iXYMetric = aXYMetric; + return; + } + } + + // If event handler wasn't found, we add new detail entry + AddEventDetailsL(handler, aXYMetric, EFalse); + } + +// Disables long tap events when dragging is going on. +void CHuiRosterImpl::DisableLongTapEventsWhenDraggingL(const MHuiEventHandler& aEventHandler, TBool aDisable) + { + MHuiEventHandler* handler = const_cast( &aEventHandler ); + + // Check if there is already detail entry in iPointerEventDetails where to update + // details + for(TInt i = 0; i < iPointerEventDetails.Count(); ++i) + { + if(iPointerEventDetails[i]->iEventHandler == handler) + { + iPointerEventDetails[i]->iDisableLongTapWhenDragging = aDisable; + return; + } + } + + // If event handler wasn't found, we add new detail entry + AddEventDetailsL(handler, THuiXYMetric(KDefaultDragTresholdInPixelsX, KDefaultDragTresholdInPixelsY), aDisable); + } + +// Checks if event handler is within threshold range. +TBool CHuiRosterImpl::DragEventOutOfRangeL(MHuiEventHandler* aEventHandler, const THuiEvent& aEvent) + { + if ( aEvent.IsPointerEvent() && iInitialDownEvent.IsPointerEvent()) + { + TBool handlerFound = EFalse; + + // Find event handler from detail array + for(TInt i = 0; i < iPointerEventDetails.Count(); ++i) + { + if(iPointerEventDetails[i]->iEventHandler == aEventHandler) + { + + // If we are already sending dragging events to this handler + // we can return immediately + if(iPointerEventDetails[i]->iDragging) + { + return ETrue; + } + + handlerFound = ETrue; + + // calculate moved distance in pixels + TPoint result = iInitialDownEvent.iPointerEvent.iPosition-aEvent.iPointerEvent.iPosition; + + // Do metric calculations + THuiRealPoint tresholdInPx(iPointerEventDetails[i]->iXYMetric.iX.iMagnitude, iPointerEventDetails[i]->iXYMetric.iY.iMagnitude); + if(iPointerEventDetails[i]->iXYMetric.iX.iUnit != EHuiUnitPixel) + { + TReal32 reference = 0; + if (iPointerEventDetails[i]->iXYMetric.iX.iUnit == EHuiUnitRelativeToDisplay && iDisplay ) + { + reference = iDisplay->VisibleArea().Width(); + } + if (iPointerEventDetails[i]->iXYMetric.iX.iUnit == EHuiUnitS60 && iDisplay ) + { + reference = iDisplay->UnitValue(); + } + tresholdInPx.iX = tresholdInPx.iX * reference; + } + if(iPointerEventDetails[i]->iXYMetric.iY.iUnit != EHuiUnitPixel) + { + TReal32 reference = 0; + if (iPointerEventDetails[i]->iXYMetric.iY.iUnit == EHuiUnitRelativeToDisplay && iDisplay ) + { + reference = iDisplay->VisibleArea().Width(); + } + if (iPointerEventDetails[i]->iXYMetric.iY.iUnit == EHuiUnitS60 && iDisplay ) + { + reference = iDisplay->UnitValue(); + } + tresholdInPx.iY = tresholdInPx.iY * reference; + } + + // Check if we are outside of the threshold + if (result.iX < -tresholdInPx.iX || result.iX > tresholdInPx.iX|| + result.iY < -tresholdInPx.iY || result.iY > tresholdInPx.iY ) + { + iPointerEventDetails[i]->iDragging = ETrue; + return ETrue; + } + else + { + iPointerEventDetails[i]->iDragging = EFalse; + } + } + } + + // If no event handler found in iPointerEventDetails array, + // check with default threshold. + if(!handlerFound) + { + TPoint result = iInitialDownEvent.iPointerEvent.iPosition-aEvent.iPointerEvent.iPosition; + + if (result.iX < -KDefaultDragTresholdInPixelsX || result.iX > KDefaultDragTresholdInPixelsX|| + result.iY < -KDefaultDragTresholdInPixelsY || result.iY > KDefaultDragTresholdInPixelsY) + { + // We need to add new event detail to store dragging flag + AddEventDetailsL(aEventHandler, THuiXYMetric(KDefaultDragTresholdInPixelsX, KDefaultDragTresholdInPixelsY), EFalse); + return DragEventOutOfRangeL(aEventHandler, aEvent); + } + } + } + return EFalse; + } + +// Checks if long tap event is allowed to send. +TBool CHuiRosterImpl::IsLongTapEventAllowed(MHuiEventHandler* aEventHandler) + { + for(TInt i = 0; i < iPointerEventDetails.Count(); ++i) + { + if(iPointerEventDetails[i]->iEventHandler == aEventHandler) + { + if ( iPointerEventDetails[i]->iDragging ) + { + return !(iPointerEventDetails[i]->iDisableLongTapWhenDragging); + } + } + } + return ETrue; + } + + +void CHuiRosterImpl::SetDrawingExternalContent(TBool aEnable) + { + iDrawEvenIfDisabledDrawInRoster = aEnable; + } + + +TBool CHuiRosterImpl::IsDrawingExternalContent() const + { + return iDrawEvenIfDisabledDrawInRoster; + } + +void CHuiRosterImpl::RemoveExternalContentVisualFromParentL(CHuiVisual* aExternalContentVisual) + { + // External content is only used with canvas visuals, and the layouts of canvas visuals are always in the roster. + // Browse all layouts in the roster and check if they have a canvas visual as a child visual. + // Note: this can be slow operation, so it should only be done rarely. + + TInt visualCount = 0; + TInt entryCount = iEntries.Count(); + for(TInt j = 0; j < entryCount; ++j) + { + CHuiRosterEntry& entry = *iEntries[j]; // control group + visualCount = entry.iRootVisuals.Count(); + for(TInt i = 0; i < visualCount; ++i) + { + CHuiLayout* layout = dynamic_cast(entry.iRootVisuals[i]); // layout + + if (layout) + { + RemoveExternalContentVisualFromParentL(aExternalContentVisual,layout); + } + } + } + } + +void CHuiRosterImpl::RemoveExternalContentVisualFromParentL(CHuiVisual* aExternalContentVisual, CHuiLayout* aLayout) + { + for(TInt k = 0; aLayout && k < aLayout->Count(); ++k) + { + CHuiCanvasVisual* canvasVisual = dynamic_cast(&(aLayout->Visual(k))); + + if (canvasVisual) + { + if (canvasVisual->ExternalContent() == aExternalContentVisual) + { + // Remove aExternalContentVisual from the parent visual + canvasVisual->SetExternalContentL(NULL); + } + } + else + { + CHuiLayout* layoutVisual = dynamic_cast(&(aLayout->Visual(k))); + if ( layoutVisual) + { + RemoveExternalContentVisualFromParentL(aExternalContentVisual,layoutVisual); + } + } + } + } + + +void CHuiRosterImpl::FreezeVisibleContentL(TBool aEnable) + { + if (aEnable) + { + if (!iCanvasGc) + { + CHuiRenderPlugin& renderplugin = CHuiStatic::Renderer(); + iCanvasGc = renderplugin.CreateCanvasGcL(); + } + if (!iCanvasRenderBuffer) + { + iCanvasRenderBuffer = iCanvasGc->CreateRenderBufferL(TSize(0,0)); + iCanvasRenderBuffer->InitializeL(CHuiStatic::Env().Display(0).VisibleArea().Size()); + iCanvasRenderBuffer->Copy(TPoint(0,0)); + iCanvasRenderBufferOrientation = CHuiStatic::Env().Display(0).Orientation(); + } + } + else + { + delete iCanvasGc; + iCanvasGc = NULL; + delete iCanvasRenderBuffer; + iCanvasRenderBuffer = NULL; + SetChanged(); + } + } + +TBool CHuiRosterImpl::IsVisibleContentFrozen() const + { + return ((iCanvasRenderBuffer != NULL) && (iCanvasGc != NULL)); + } + +void CHuiRosterImpl::EffectSetEffect(CHuiFxEffect* aEffect) + { + if (iEffect) + { + delete iEffect; + iEffect = NULL; + } + iEffect = aEffect; + SetChanged(); + } + +TReal32 CHuiRosterImpl::EffectOpacityTarget() const + { + return iEffectOpacity; + } + +void CHuiRosterImpl::EffectSetOpacity(TReal32 aOpacity) + { + iEffectOpacity = aOpacity; + } + +void CHuiRosterImpl::EffectDrawSelf( CHuiGc &aGc, const TRect & aDisplayRect) const + { + DrawSelf(aGc, iDisplay); + } + +THuiRealRect CHuiRosterImpl::EffectDisplayRect() const __SOFTFP + { + if (iDisplay) + { + return iDisplay->VisibleArea(); + } + else + { + return THuiRealRect(TRect(0,0,0,0)); + } + } + +MHuiEffectable* CHuiRosterImpl::Effectable() + { + return this; + } + +void CHuiRosterImpl::SetLoadingEffect(TBool /*aLoading*/) + { + // not needed + } +void CHuiRosterImpl::EffectSetSource( TBool aIsInput1 ) + { + iIsInput1 = aIsInput1; + } + +TBool CHuiRosterImpl::EffectGetSource() const + { + return iIsInput1; + }