uiacceltk/hitchcock/coretoolkit/src/HuiControl.cpp
changeset 0 15bf7259bb7c
--- /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*/)
+    {
+    
+    }
+
+