diff -r 000000000000 -r 15bf7259bb7c uiacceltk/hitchcock/coretoolkit/src/HuiControl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uiacceltk/hitchcock/coretoolkit/src/HuiControl.cpp Tue Feb 02 07:56:43 2010 +0200 @@ -0,0 +1,794 @@ +/* +* 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: CHuiControl provides a base class for a generic logical +* control element in the HUITK UI. +* +*/ + + + +#include "uiacceltk/HuiControl.h" // Class definition +#include "uiacceltk/HuiControlGroup.h" +#include "uiacceltk/huieventhandler.h" +#include "uiacceltk/HuiVisual.h" +#include "uiacceltk/HuiDisplay.h" +#include "HuiRosterImpl.h" +#include "uiacceltk/HuiEnv.h" +#include "HuiVisualFactory.h" +#include "uiacceltk/HuiUtil.h" +#include "uiacceltk/HuiStatic.h" +#include "uiacceltk/HuiPanic.h" +#include "uiacceltk/HuiProbe.h" + + +EXPORT_C CHuiControl::CHuiControl(CHuiEnv& aEnv) + : iEnv(aEnv), iFocusing(EFalse) + { + HUI_PROBE_ASSOCIATE_WITH_CURRENT_SESSION + HUI_PROBE_REPORT_CONSTRUCTED + + // Generate an automatical ID for all controls. + iId = CHuiStatic::GenerateId(); + } + +// virtual second phase construtor +EXPORT_C void CHuiControl::BaseConstructL() + { + } + + +EXPORT_C CHuiControl::~CHuiControl() + { + // Cancel scheduled commands for this control. + Env().CancelCommands(this); + + iOwnerGroup = NULL; + iBoundDisplay = NULL; + + if(iHost) + { + iHost->RemoveConnection(this); + iHost = NULL; + } + + for(TInt i = iConnections.Count() - 1; i >= 0; --i) + { + RemoveConnection(iConnections[i].iControl); + } + iConnections.Reset(); + + // The visuals are owned by the control. + iVisuals.ResetAndDestroy(); + + HUI_PROBE_REPORT_DESTRUCTED + + } + + +EXPORT_C CHuiEnv& CHuiControl::Env() const + { + return iEnv; + } + + +EXPORT_C CHuiControlGroup* CHuiControl::ControlGroup() const + { + return iOwnerGroup; + } + + +void CHuiControl::SetControlGroup(CHuiControlGroup& aOwnerGroup) + { + iOwnerGroup = &aOwnerGroup; + } + + +EXPORT_C CHuiTextureManager& CHuiControl::TextureManager() const + { + return Env().TextureManager(); + } + + +EXPORT_C CHuiDisplay* CHuiControl::Display() const + { + return iBoundDisplay; + } + + +EXPORT_C void CHuiControl::BindDisplay(CHuiDisplay& aDisplay) + { + iBoundDisplay = &aDisplay; + } + + +EXPORT_C void CHuiControl::SetId(TInt aId) + { + iId = aId; + } + + +EXPORT_C TInt CHuiControl::Id() const + { + return iId; + } + + +EXPORT_C void CHuiControl::AppendL(CHuiVisual* aVisual) + { + User::LeaveIfError(iVisuals.Append(aVisual)); + aVisual->SetOwner(*this); + TRAPD(err, VisualAddedL(aVisual)); + if(err != KErrNone) + { + // Can't leave the visual in the array of our owned visuals. + iVisuals.Remove(iVisuals.Find(aVisual)); + } + } + + +EXPORT_C void CHuiControl::AppendL(CHuiVisual* aVisual, CHuiLayout* aParentLayout) + { + TInt err = KErrNone; + + User::LeaveIfError(iVisuals.Append(aVisual)); + + // Append to the parent layout before notification. + if(aParentLayout) + { + TRAP(err, aParentLayout->AppendL(aVisual)); + } + + TRAP(err, VisualAddedL(aVisual)); + if(err != KErrNone) + { + // Can't leave the visual in the array of our owned visuals. + iVisuals.Remove(iVisuals.Find(aVisual)); + } + } + + +EXPORT_C void CHuiControl::Remove(CHuiVisual* aVisual) + { + TInt index = iVisuals.Find(aVisual); + if(index != KErrNotFound) + { + VisualRemoved(aVisual); + iVisuals.Remove(index); + } + } + + +EXPORT_C CHuiVisual* CHuiControl::AppendVisualL(THuiVisualType aVisualType, + CHuiLayout* aParentLayout) + { + CHuiVisual* visual = Env().VisualFactory().NewVisualLC(aVisualType, *this); + AppendL(visual, aParentLayout); + // The visual is now owned by this control. + CleanupStack::Pop(visual); + return visual; + } + + +EXPORT_C CHuiLayout* CHuiControl::AppendLayoutL(THuiLayoutType aLayoutType, + CHuiLayout* aParentLayout) + { + CHuiLayout* layout = Env().VisualFactory().NewLayoutLC(aLayoutType, *this); + AppendL(layout, aParentLayout); + // The visual is now owned by this control. + CleanupStack::Pop(layout); + return layout; + } + + +EXPORT_C CHuiVisual& CHuiControl::Visual(TInt aIndex) const + { + return *iVisuals[aIndex]; + } + + +EXPORT_C TInt CHuiControl::VisualCount() const + { + return iVisuals.Count(); + } + + +EXPORT_C CHuiVisual* CHuiControl::FindTag(const TDesC8& aTag) const + { + TInt i = 0; + + for(i = 0; i < iVisuals.Count(); ++i) + { + if(HuiUtil::TagMatches(iVisuals[i]->Tag(), aTag)) + { + return iVisuals[i]; + } + } + + return NULL; + } + + +EXPORT_C CHuiControl* CHuiControl::Host() const + { + return iHost; + } + + +EXPORT_C void CHuiControl::SetHost(CHuiControl* aHost) + { + // do not call this function directly. This should be only called by the + // AddConnectionL and RemoveConnection functions. + + if ( aHost ) + { + // When adding a host, the host must be aware of this connection first. + __ASSERT_ALWAYS( aHost->FindConnection(this) != KErrNotFound, USER_INVARIANT() ); + } + + TRAPD(err, HostChangingL(aHost)); + if(err != KErrNone) + { + if(aHost) + { + RemoveVisualsFromHostControl(*aHost); + } + return; + } + + iHost = aHost; + } + + +EXPORT_C void CHuiControl::AddConnectionL(CHuiControl* aConnectedControl, TInt aRole) + { + // check that the connection does not exist: + if ( FindConnection( aConnectedControl ) != KErrNotFound ) + { + User::Leave( KErrAlreadyExists ); + } + + SConnection client; + client.iControl = aConnectedControl; + client.iRole = aRole; + User::LeaveIfError(iConnections.Append(client)); + + // This control is now the client's host. + aConnectedControl->SetHost(this); + + if ( aConnectedControl->Host() != this ) + { + // Adding Host failed -> remove connection + iConnections.Remove( iConnections.Count()-1 ); + User::Leave( KErrGeneral ); + } + else + { + // Host set OK + ConnectionAddedL(aConnectedControl, aRole); + } + } + + +EXPORT_C void CHuiControl::RemoveConnection(CHuiControl* aConnectedControl) + { + for(TInt i = 0; i < iConnections.Count(); ++i) + { + if(iConnections[i].iControl == aConnectedControl) + { + aConnectedControl->SetHost(NULL); + const TInt role = iConnections[i].iRole; + iConnections.Remove(i); + + ConnectionRemoved(aConnectedControl, role ); + return; + } + } + // The client must exist. + __ASSERT_ALWAYS(EFalse, THuiPanic::Panic(THuiPanic::EInternal)); + } + + +EXPORT_C TInt CHuiControl::ConnectionCount() const + { + return iConnections.Count(); + } + + +EXPORT_C CHuiControl& CHuiControl::Connection(TInt aIndex) const + { + return *iConnections[aIndex].iControl; + } + +// @deprecated +EXPORT_C CHuiControl& CHuiControl::ConnectionByOrdinal(TInt aOrdinal) const + { + // First look based on role. + for(TInt i = 0; i < iConnections.Count(); ++i) + { + if(iConnections[i].iRole == aOrdinal + 1) + { + return *iConnections[i].iControl; + } + } + + // Fall back to index. + return Connection(aOrdinal); + } + + +EXPORT_C TInt CHuiControl::FindConnection(const CHuiControl* aConnected) const + { + for(TInt i = 0; i < iConnections.Count(); ++i) + { + if(iConnections[i].iControl == aConnected) + { + return i; + } + } + return KErrNotFound; + } + + +EXPORT_C TInt CHuiControl::ConnectionRole(TInt aIndex) const + { + return iConnections[aIndex].iRole; + } + + +// @deprecated +EXPORT_C TInt CHuiControl::ConnectionOrdinal(TInt aIndex) const + { + if(iConnections[aIndex].iRole) + { + return iConnections[aIndex].iRole - 1; + } + return aIndex; + } + + +EXPORT_C TInt CHuiControl::Role() const + { + return iRole; + } + + +EXPORT_C void CHuiControl::SetRole(TInt aRole) + { + iRole = aRole; + } + + +EXPORT_C TInt CHuiControl::HostId() const + { + return iHostId; + } + + +EXPORT_C void CHuiControl::SetHostId(TInt aHostId) + { + // If adding automatic visual host, there cannot be already one defined. + __ASSERT_ALWAYS( !iHost, USER_INVARIANT() ); + + iHostId = aHostId; + } + + +EXPORT_C CHuiLayout* CHuiControl::ContainerLayout(const CHuiControl* /*aConnected*/) const + { + // Generic controls aren't able to provide container layouts. + return NULL; + } + + +EXPORT_C void CHuiControl::VisualAddedL(CHuiVisual* aVisual) + { + // Add the new visual to the container layout. + if(iHost && !aVisual->Layout()) + { + CHuiLayout* container = iHost->ContainerLayout(this); + if(container) + { + container->AppendL(aVisual); + } + } + else + { + // If the control has been bound to a display (for example, when + // the control is shown), new visuals will be automatically shown. + if(iBoundDisplay && + (iOwnerGroup && iBoundDisplay->Roster().Find(iOwnerGroup) != KErrNotFound) && + !aVisual->Layout() && !aVisual->Display()) + { + iBoundDisplay->Roster().ShowVisualL(aVisual); + } + } + } + + +EXPORT_C void CHuiControl::VisualRemoved(CHuiVisual* aVisual) + { + // Add the new visual to the container layout. + if(iHost) + { + CHuiLayout* container = iHost->ContainerLayout(this); + if(container) + { + container->Remove(aVisual); + } + } + } + + +EXPORT_C void CHuiControl::ConnectionAddedL(CHuiControl* /*aConnectedControl*/, TInt /*aRole*/) + { + // Do nothing. + } + + +EXPORT_C void CHuiControl::ConnectionRemoved(CHuiControl* /*aConnectedControl*/, TInt /*aRole*/) + { + // Do nothing. + } + + +void CHuiControl::RemoveVisualsFromHostControl( CHuiControl& aHostControl ) + { + __ASSERT_ALWAYS( &aHostControl != this, USER_INVARIANT() ); + + // Remove the visuals. + for(TInt i = 0; i < iVisuals.Count(); ++i) + { + if ( iVisuals[i]->Layout() && &iVisuals[i]->Layout()->Owner() == &aHostControl ) + { + iVisuals[i]->Layout()->Remove(iVisuals[i]); + + // If the own control group is showing still in some roster, + // we need to add the root visuals over there + if ( iBoundDisplay ) + { + TRAP_IGNORE( iBoundDisplay->Roster().ShowVisualL( iVisuals[i] ) ) + } + } + } + } + + +EXPORT_C void CHuiControl::HostChangingL(CHuiControl* aNewHost) + { + CHuiLayout* newContainer = 0; + TInt i = 0; + + if(aNewHost) + { + // The container layout provided by the new host. + newContainer = aNewHost->ContainerLayout(this); + } + + if(iHost) + { + RemoveVisualsFromHostControl(*iHost); + } + + if(newContainer) + { + for(i = 0; i < iVisuals.Count(); ++i) + { + // Only the visuals that aren't already attached to a layout + // are added to the container layout. + if(!iVisuals[i]->Layout()) + { + newContainer->AppendL(iVisuals[i]); + } + } + } + } + + +void CHuiControl::ShowL(CHuiDisplay& aDisplay) + { + if(HostId()) + { + CHuiControl* host = Env().FindControl(HostId()); + + if(host) + { + host->AddConnectionL(this, Role()); + } + else + { + } + } + + BindDisplay(aDisplay); + + // Show all the visuals on the specified display. + for(TInt i = 0; i < iVisuals.Count(); ++i) + { + // The visuals that are part of a layout will be shown when the + // layout is shown. + if(!iVisuals[i]->Layout() && !iVisuals[i]->Display()) + { + aDisplay.Roster().ShowVisualL(iVisuals[i]); + } + } + + NotifyControlVisibility(ETrue, aDisplay); + } + + +void CHuiControl::Hide(CHuiDisplay& aDisplay) + { + NotifyControlVisibility(EFalse, aDisplay); + + // Show all the visuals on the specified display. + for(TInt i = 0; i < iVisuals.Count(); ++i) + { + // The visuals that are part of a layout will be shown when the + // layout is shown. + if(!iVisuals[i]->Layout() && iVisuals[i]->Display() == &aDisplay) + { + aDisplay.RosterImpl().HideVisual(iVisuals[i]); + } + } + + // Unbind from display? + if(iBoundDisplay == &aDisplay) + { + iBoundDisplay = NULL; + } + + // Unlink from parent control if automated host id set. + if(Host() && HostId() ) + { + Host()->RemoveConnection(this); + } + } + + +EXPORT_C void CHuiControl::NotifyControlVisibility(TBool /*aIsVisible*/, + CHuiDisplay& /*aDisplay*/) + { + // Nothing to do by default. + } + + +EXPORT_C TPoint CHuiControl::HostToDisplay(const TPoint& aPoint) const + { + if(!iHost) + { + return aPoint; + } + + CHuiLayout* container = iHost->ContainerLayout(this); + + return container->LocalToDisplay(aPoint) + container->Pos().Target(); + } + + +EXPORT_C TPoint CHuiControl::DisplayToHost(const TPoint& aPoint) const + { + if(!iHost) + { + return aPoint; + } + + CHuiLayout* container = iHost->ContainerLayout(this); + + return container->DisplayToLocal(aPoint) - container->Pos().Target(); + } + + +EXPORT_C TRect CHuiControl::Bounds() const + { + TPoint min; + TPoint max; + + min.iX = KMaxTInt; + min.iY = KMaxTInt; + max.iX = KMinTInt; + max.iY = KMinTInt; + + for(TInt i = 0; i < iVisuals.Count(); ++i) + { + TRect visualRect = iVisuals[i]->DisplayRectTarget(); + + min.iX = Min(min.iX, visualRect.iTl.iX); + min.iY = Min(min.iY, visualRect.iTl.iY); + max.iX = Max(max.iX, visualRect.iBr.iX); + max.iY = Max(max.iY, visualRect.iBr.iY); + } + + return TRect(min, max); + } + + +EXPORT_C TBool CHuiControl::HitTest(const TPoint& aPoint) const + { + return Bounds().Contains(aPoint); + } + + + +EXPORT_C void CHuiControl::AcquireFocus() + { + + /** @todo Focus should be set separately in each display the control + has visuals in. */ + + for(TInt i = 0; i < iVisuals.Count(); ++i) + { + if(iVisuals[i]->Display()) + { + iVisuals[i]->Display()->Roster().SetFocus(*this /*Id()*/); + //return; + } + } + } + + +EXPORT_C TBool CHuiControl::Focus() const + { + return iHasFocus; + } + + +void CHuiControl::SetFocus(CHuiDisplay& aDisplay, TBool aHasFocus) + { + if ( ( iHasFocus && !aHasFocus ) || ( !iHasFocus && aHasFocus ) ) + { + iHasFocus = aHasFocus; + FocusChanged(aDisplay, aHasFocus); + } + } + + +EXPORT_C TBool CHuiControl::IsFocusing() const + { + return iFocusing; + } + + +void CHuiControl::SetFocusing(TBool aFocusing) + { + iFocusing = aFocusing; + } + + +EXPORT_C void CHuiControl::FocusChanged(CHuiDisplay& /*aDisplay*/, TBool /*iFocused*/) + { + // Do nothing by default. + } + + +EXPORT_C TBool CHuiControl::AcceptInput() const + { + if(iOwnerGroup) + { + return iOwnerGroup->AcceptInput(); + } + return ETrue; + } + + +EXPORT_C TBool CHuiControl::OfferEventL(const THuiEvent& /*aEvent*/) + { + return EFalse; + } + + +EXPORT_C TRect CHuiControl::DisplayArea() const + { + if(iBoundDisplay) + { + return iBoundDisplay->VisibleArea(); + } + + // The first visual shown on a display determines the display area. + for(TInt i = 0; i < iVisuals.Count(); ++i) + { + if(iVisuals[i]->Display()) + { + return iVisuals[i]->Display()->VisibleArea(); + } + } + + if(!Env().DisplayCount()) + { + // No displays created in the environment yet. Assume device + // native resolution. + return TRect(TPoint(0, 0), HuiUtil::ScreenSize()); + } + + // Assume it is the primary display, then. + return Env().PrimaryDisplay().VisibleArea(); + } + + +EXPORT_C THuiRealPoint CHuiControl::DisplayCenter() const __SOFTFP + { + TRect area(DisplayArea()); + return area.iTl + THuiRealPoint(area.Width()/2.f, area.Height()/2.f); + } + + +EXPORT_C void CHuiControl::CancelAllCommands() + { + iEnv.CancelCommands(this); + + for(TInt i = 0; i < iVisuals.Count(); ++i) + { + iEnv.CancelCommands(iVisuals[i]); + } + } + + +void CHuiControl::ClearChanged() + { + } + + +EXPORT_C void CHuiControl::VisualLayoutUpdated(CHuiVisual& /*aVisual*/) + { + // Nothing done by default. + } + + +EXPORT_C void CHuiControl::VisualDestroyed(CHuiVisual& aVisual) + { + Remove(&aVisual); + } + + +EXPORT_C void CHuiControl::VisualPrepareDrawFailed( +#ifdef _DEBUG + #ifdef __WINS__ + #ifdef HUI_NO_DEBUG_OUTPUT_IN_WINS + CHuiVisual& /*aVisual*/, + TInt /*aErrorCode*/ + #else + CHuiVisual& /*aVisual*/, + TInt /*aErrorCode*/ + #endif + #else + CHuiVisual& /*aVisual*/, + TInt /*aErrorCode*/ + #endif +#else + CHuiVisual& /*aVisual*/, + TInt /*aErrorCode*/ +#endif + ) + { + //HUI_DEBUG2(_L("CHuiControl::VisualPrepareDrawFailed() - ERROR! Visual 0x%x failed to prepare for drawing. Error Code %i. Panicing. (TIP: override this method for custom error handling)."), + // &aVisual, aErrorCode); + #ifdef _DEBUG + HUI_PANIC(THuiPanic::EVisualPrepareDrawFailed) + #endif + } + + +EXPORT_C MHuiEventHandler* CHuiControl::EventHandler() + { + return this; + } + + +HUI_SESSION_OBJECT_IMPL_EXPORT(CHuiControl, ETypeControl) + +EXPORT_C void CHuiControl::ControlExtension(const TUid& /*aExtensionUid*/, TAny** /*aExtensionParams*/) + { + + } + +