/*
* Copyright (c) 2005-2006 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 for control group
*
*/

#include "peninputlayoutbutton.h"
#include "peninputlayoutctrlgroup.h"
#include "peninputlayoutrootctrl.h"
#include "peninputlayout.h"
#include "coecntrl.h"
// ============================ MEMBER FUNCTIONS ===============================

/******************************************************************************/
// Implementation to Class CControlGroup
//
/******************************************************************************/

// -----------------------------------------------------------------------------
// CControlGroup::NewL
// Factory function
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
EXPORT_C CControlGroup* CControlGroup::NewL(CFepUiLayout* aUiLayout,
										    TInt aControlId,
										    TBool aRedrawBg /*= ETrue*/)
    {
    CControlGroup* ctrlGroup=new (ELeave)CControlGroup(aUiLayout,aControlId, aRedrawBg);   
    CleanupStack::PushL(ctrlGroup);
    ctrlGroup->ConstructL();
    CleanupStack::Pop(ctrlGroup);
    return ctrlGroup;
    }

// -----------------------------------------------------------------------------
// CControlGroup::NewL
// Factory function
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
CControlGroup* CControlGroup::NewL(CFepUiLayout* aUiLayout,CCoeControl* aControl)
    {
    if(!aControl)
        return NULL;
    CControlGroup* ctrlGroup=new (ELeave)CControlGroup(aUiLayout,
                                                      aControl->UniqueHandle());
    
    ctrlGroup->iWndControl = aControl;
    CleanupStack::PushL(ctrlGroup);
    ctrlGroup->ConstructL();
    ctrlGroup->SetRect(aControl->Rect());    
    CleanupStack::Pop(ctrlGroup);
    return ctrlGroup;
    }
    
// -----------------------------------------------------------------------------
// CControlGroup::CControlGroup
// C++ default constructor
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//        
EXPORT_C CControlGroup::CControlGroup(CFepUiLayout* aUiLayout,TInt aCtrlId)
                :CFepUiBaseCtrl(TRect(0,0,0,0),aUiLayout,aCtrlId)
    {
    iNeedRedrawBg = (TInt)ETrue;
    SetControlType(ECtrlControlGroup);
    }

// -----------------------------------------------------------------------------
// CControlGroup::CControlGroup
// C++ default constructor
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//        
EXPORT_C CControlGroup::CControlGroup(CFepUiLayout* aUiLayout,
									  TInt aCtrlId,
									  TBool aRedrawBg)
                :CFepUiBaseCtrl(TRect(0,0,0,0),aUiLayout,aCtrlId)
    {
    iNeedRedrawBg = aRedrawBg;
    SetControlType(ECtrlControlGroup);
    }

// -----------------------------------------------------------------------------
// CControlGroup::ConstructL
// Second phrase constructor
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//            
EXPORT_C void CControlGroup::ConstructL()
    {
    //do CFepUiBaseCtrl's base construction
    BaseConstructL();
    }

// -----------------------------------------------------------------------------
// CControlGroup::~CControlGroup
// Destructor
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//            
EXPORT_C CControlGroup::~CControlGroup()
    {
    CFepUiBaseCtrl* ctrl;
    for(TInt i = iOwnedCtrlList.Count()-1;i >= 0;i--)
        {
        ctrl = iOwnedCtrlList[i];
        delete ctrl;
        }
    iOwnedCtrlList.Close();
    
    iCtrlList.Close();
    iPopCtrlList.Close();
    iNonHwrStartPtRegion.Close();    
    /*for(TInt i = 0 ; i < iSubRegionArea.Count(); ++i)
        {
         delete iSubRegionArea[i];
        }*/
    iSubRegionArea.ResetAndDestroy();    
    iSubRegionArea.Close();
    iSubCtrlShowStateBeforeHiden.Close();
    }
    
// -----------------------------------------------------------------------------
// CControlGroup::AddControlL
// Add control to group
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//        
EXPORT_C void CControlGroup::AddControlL(CFepUiBaseCtrl* aControl, TBool aOwnerFlag)
    {
    //do nothing if we already has the control.
    if(!aControl || KErrNotFound != iCtrlList.Find(aControl))
        return;
    CalculateClipRegion(aControl);
    
    if(aOwnerFlag)
        iOwnedCtrlList.AppendL(aControl);

    iCtrlList.AppendL(aControl);   
    
    aControl->SetParent(this);
    if(!aControl->Hiden() && !aControl->IsKindOfControl(ECtrlPopupWindow))
        {        
        //TRect rect = Rect();
        
        if(iCtrlList.Count() > 1)
            {
            iRect.BoundingRect(aControl->Rect());       
            }
        else
            iRect = aControl->Rect();
        
        //iRect = rect;

        /*RRegion region(8);
        region.Copy(Region());   

        region.AddRect(aControl->Rect());
        SetRegion(region);*/
        UpdateValidRegion(aControl,EFalse);
        }
    //since control may be added dynamically, we need draw it
//        aControl->Draw();
//        aControl->UpdateArea(aControl->Rect(),ETrue);
    TSubCtrlShownState state = {aControl,aControl->Hiden()};    
    iSubCtrlShowStateBeforeHiden.AppendL(state);
    }


// -----------------------------------------------------------------------------
// CControlGroup::Find
// Find the control in a control group
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//        
CFepUiBaseCtrl* CControlGroup::Find(CCoeControl* aCtrl)
    {
    if(!IsKindOfControl(ECtrlWndBasedCtrl))
        return NULL;
    
    if(aCtrl == iWndControl)
        return this;
    
    for(TInt i = 0; i < iCtrlList.Count(); i++)
        {
        CFepUiBaseCtrl* ctrl = iCtrlList[i];
        if(!ctrl->IsKindOfControl(ECtrlControlGroup))
            {
            if(aCtrl == ctrl->WndBasedControl())
                return ctrl;
            }
        else
            {
            /*
            bFound = static_cast<CControlGroup*>(ctrl)->Find(aCtrl);
            if(bFound)
                return bFound;
                */
            CControlGroup* ctrlGroup = static_cast<CControlGroup*>(ctrl);
            CFepUiBaseCtrl* foundedCtrl = ctrlGroup->Find(aCtrl);
            if(foundedCtrl)
                return foundedCtrl;
            }
        }
    
    return NULL;    
    }
    
    
// -----------------------------------------------------------------------------
// CControlGroup::AddControlL
// Add control to group
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//        
EXPORT_C CFepUiBaseCtrl* CControlGroup::AddControlL(CCoeControl* aControl)
    {
    //do nothing if we already has the control.
    if(!IsKindOfControl(ECtrlWndBasedCtrl) || !aControl)
        return NULL;
    
    CFepUiBaseCtrl* ctrl = Find(aControl);
    if(ctrl)
        return ctrl;   

    //if it's a compound control, we need find out its sub-control one by one
    if(aControl->CountComponentControls())
        {
        //create a control group
        CControlGroup* group = CControlGroup::NewL(UiLayout(),aControl);
        ctrl = group;
        CleanupStack::PushL(ctrl);
        for(TInt i = 0; i < aControl->CountComponentControls(); i++)
            {
            group->AddControlL(aControl->ComponentControl(i));
            }        
        group->SetControlType(ECtrlWndBasedCtrl|ECtrlControlGroup);                
        }
    else
        {
        ctrl = new(ELeave) CFepUiBaseCtrl(aControl,UiLayout());
        ctrl->SetControlType(ECtrlWndBasedCtrl|ECtrlBaseCtrl);
        CleanupStack::PushL(ctrl);
        ctrl->BaseConstructL();
        }   
    AddControlL(ctrl,ETrue);
    CleanupStack::Pop(ctrl);            
    UpdateValidRegion(ctrl,EFalse);    
    return ctrl;
    }

// ---------------------------------------------------------------------------
// CControlGroup::RemoveOwnedControl
// Remove a control from group's owned control list
// ---------------------------------------------------------------------------
//
TBool CControlGroup::RemoveOwnedControl(CFepUiBaseCtrl* aControl)
    {
    TInt index = iOwnedCtrlList.Find(aControl);
    if(KErrNotFound != index)
        {
        iOwnedCtrlList.Remove(index);
        delete aControl;
        }
    return KErrNotFound != index;
    }

// ---------------------------------------------------------------------------
// CControlGroup::RemoveControl
// Remove a control from group
// ---------------------------------------------------------------------------
//
EXPORT_C TBool CControlGroup::RemoveControl(CFepUiBaseCtrl* aControl)
    {
    TInt i;
    TBool bFound = EFalse;
    //CControlGroup* parent = this;
    
    if(!aControl || iCtrlList.Count() <= 0)
        return EFalse;
    
    if(aControl == iActiveCtrl)
        iActiveCtrl = NULL;
    
    //iRect = iCtrlList[0]->Rect();    
    
    //find and remove the control
    for(i = 0 ; i < iCtrlList.Count() && !bFound; ++i)
        {
        if(iCtrlList[i] == aControl)
            {
            iCtrlList.Remove(i);            
            RemoveOwnedControl(aControl);
            bFound = ETrue;            
            }
        }
        
    if(bFound && aControl != NULL && !aControl->Hiden())
        {
        //change iRect
        if(iCtrlList.Count())
            {
            iRect = iCtrlList[0]->Rect();
            }
        else
            iRect = TRect(0,0,0,0);
        
        for( i = 1; i < iCtrlList.Count(); ++i)
            {            
            iRect.BoundingRect(iCtrlList[i]->Rect());            
            }
        }
    else
        return EFalse;
    
    RemoveCtrlFromSubCtrlInfoList(aControl);
    UpdateValidRegion(aControl,ETrue);
    
    CalculateClipRegion();
    return bFound;
    }

void CControlGroup::CalculateClipRegion(CFepUiBaseCtrl* aControl)
    {
    for(TInt i = 0 ; i < iCtrlList.Count(); ++i)
        {
        if(!aControl->Hiden())
            iCtrlList[i]->iClipRegion.SubRect(aControl->Rect());        
        }
    }
    
void CControlGroup::CalculateClipRegion()
    {
    //restore each control's rect first.
    for(TInt i = 0; i < iCtrlList.Count(); ++i)
        {
        CFepUiBaseCtrl* ctrl = iCtrlList[i];
        if(ctrl->IsKindOfControl(ECtrlControlGroup))
            static_cast<CControlGroup*>(ctrl)->CalculateClipRegion();
        ctrl->iClipRegion.Clear();
        ctrl->iClipRegion.AddRect(ctrl->Rect());
        }
    //re calulate clip region
    
    for(TInt curCtrlIdx = iCtrlList.Count() - 1 ; curCtrlIdx >= 0 ; --curCtrlIdx)
        {
        CFepUiBaseCtrl* curCtrl = iCtrlList[curCtrlIdx];
        for(TInt upperCtrlIdx = curCtrlIdx + 1 ;  upperCtrlIdx < iCtrlList.Count(); ++upperCtrlIdx)
            {
            if(!iCtrlList[upperCtrlIdx]->Hiden())
                curCtrl->iClipRegion.SubRect(iCtrlList[upperCtrlIdx]->Rect());
            }
        }
    }
// -----------------------------------------------------------------------------
// CControlGroup::At
// Return control in given position
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C CFepUiBaseCtrl* CControlGroup::At(TInt aIndex)
    {
    if(aIndex >=0 && aIndex < iCtrlList.Count())
        return iCtrlList[aIndex];
    else
        return NULL;
    }

// -----------------------------------------------------------------------------
// CControlGroup::ControlForPoints()
// Find the control which contains the point
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
CFepUiBaseCtrl* CControlGroup::ControlForPoints(const TPoint& aPt)
    {
    CFepUiBaseCtrl* ctrl = NULL;

    if(iActiveCtrl && !iActiveCtrl->Hiden() && iActiveCtrl->Contains(aPt))
        {
        return iActiveCtrl;        
        }
        
    for ( TInt i = iCtrlList.Count() - 1 ; i > -1 ; i-- )
        {
        ctrl = iCtrlList[i];
        if ( ctrl->iExtension->iExtResponseAreaActive && ctrl->Contains( aPt ) )
            {
            return ctrl;
            }
        }
    
    for ( TInt i = iCtrlList.Count() - 1 ; i > -1 ; i-- )
        {
        ctrl = iCtrlList[i];
        if(!ctrl->Hiden() && ctrl->Contains(aPt))
            {
            return ctrl;
            }
        }
    return NULL;
    }


// -----------------------------------------------------------------------------
// CControlGroup::HandlePointerUpEventL()
// Handle pointer up event
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
EXPORT_C CFepUiBaseCtrl* CControlGroup::HandlePointerUpEventL(const TPoint& aPt)
    {
    if(iWndControl)
        {
        return CFepUiBaseCtrl::HandlePointerUpEventL(aPt);
        }
    CFepUiBaseCtrl* ctrl = ControlForPoints(aPt);
    if(!ctrl && !iRect.Contains(aPt)) // not belong our group
        return NULL;
    
    if(!PointerDown())
        {    
        return this;
        }
        
    SetPointerDown(EFalse);    
    
    if(ctrl != iCtrlWithPointerDown)
        {
        if(iCtrlWithPointerDown)
            iCtrlWithPointerDown->CancelPointerDownL();
        }
    else
        {        
        if(ctrl)
            {          // modify by vv for temp  
            if(ctrl->HandlePointerUpEventL(aPt))
                {
                if( !ctrl->Hiden() && ctrl->Ready() )
                    {
                    SetActiveCtrl(ctrl);
                    }
                }
            ctrl->SetPointerDown(EFalse);
            }
        }
    iCtrlWithPointerDown = NULL;
    return this;
    }


// -----------------------------------------------------------------------------
// CControlGroup::HandlePointerDownEventL()
// Handle pointer down event
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
EXPORT_C CFepUiBaseCtrl* CControlGroup::HandlePointerDownEventL(const TPoint& aPt)
    {
    if(iWndControl)
        {
        return CFepUiBaseCtrl::HandlePointerDownEventL(aPt);
        }
        
    CFepUiBaseCtrl* ctrl = ControlForPoints(aPt);
    iCtrlWithPointerDown = ctrl;
    
    if(ctrl)
        {
        SetPointerDown(ETrue);
        
        iPointerLeft = EFalse;
        iTempActiveCtrl = iActiveCtrl;
        SetTempActiveCtrl(ctrl);
        ctrl->HandlePointerDownEventL(aPt);
        return this;
        }
    return NULL;
    }


// -----------------------------------------------------------------------------
// CControlGroup::HandlePointerMoveEvent()
// Handle pointer move event
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
EXPORT_C CFepUiBaseCtrl* CControlGroup::HandlePointerMoveEventL(const TPoint& aPt)
    {
    if(iWndControl)
        {
        return CFepUiBaseCtrl::HandlePointerMoveEventL(aPt);
        }
    CFepUiBaseCtrl* ctrl = ControlForPoints(aPt);

    if(!ctrl && !iRect.Contains(aPt)) // not belong our group
        return NULL; // Check: This will not happen!
    
    if(!iCtrlWithPointerDown) // does not's process move event if no pointer down
        return this;
    
    if(ctrl != iCtrlWithPointerDown) 
    //pointer just move out the control for the first time
        {
        //Inform the control that pointer is out for first time
        if(!iPointerLeft)
            {
            iPointerLeft = ETrue;            
            iCtrlWithPointerDown->HandlePointerLeave(aPt);
            }
        }
    else
        {
        //Inform the control that pointer is in
        if(iPointerLeft)
            {                                    
            iCtrlWithPointerDown->HandlePointerEnter(aPt);
            iPointerLeft = EFalse; //reset the flag
            }
        }
    
    
    if(ctrl)
        ctrl->HandlePointerMoveEventL(aPt);
    else
        return NULL;
    return this;
    }


// -----------------------------------------------------------------------------
// CControlGroup::Draw
// Draw the control
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
EXPORT_C void CControlGroup::Draw()
    {
	if(!AbleToDraw() || WholeHiden())
        return;
    
    if(iWndControl)
        {
        CFepUiBaseCtrl::Draw();
        return;
        }
    //Clear();
        
    for(TInt i=0; i<iCtrlList.Count();i++)        
        {
        CFepUiBaseCtrl* ctrl = iCtrlList[i];
        //not draw hiden control and pop up window. Active control is drawn later
        if(!ctrl->Hiden() && !ctrl->IsKindOfControl(ECtrlPopupWindow)
            && ctrl != iActiveCtrl) 
            ctrl->Draw();        
        }
    //draw active controls
    if(iActiveCtrl)
        iActiveCtrl->Draw();
    
    //draw pop control
     for(TInt i=0; i<iPopCtrlList.Count();i++)        
        {
        CFepUiBaseCtrl* ctrl = iPopCtrlList[i];
        if(!ctrl->Hiden()) 
            ctrl->Draw();        
        }
    }

void DoRedrawInCtrlList(const TRect& aRect, CFepUiBaseCtrl* aCtrl,
                        RPointerArray<CFepUiBaseCtrl>& aList)
    {
    for(TInt i = 0 ; i < aList.Count(); ++i)
        {
        if(aList[i] == aCtrl)
            continue;
        if(!aList[i]->Hiden() && 
            aList[i]->IsOnTopOf(aCtrl) && 
            aRect.Intersects(aList[i]->Rect()))
            {
            TRect r = aRect;
            r.Intersection(aList[i]->Rect());
            aList[i]->ReDrawRect(r);
            }
        }
    }

// -----------------------------------------------------------------------------
// CControlGroup::RedrawRectIfNeeded
// ReDraw the affected control in the rect if needed
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
void CControlGroup::RedrawRectIfNeeded(const TRect& aRect, CFepUiBaseCtrl* aCtrl)
    {
    if( aCtrl->Hiden() )
        {
        return;
        }
	if(!AbleToDraw() || WholeHiden())
        return;
    
    if(aRect.IsEmpty())
        return;
    
    //check all sub controls
    DoRedrawInCtrlList(aRect,aCtrl,iCtrlList);    
    //check pop list
    //check all sub controls
    DoRedrawInCtrlList(aRect,aCtrl,iPopCtrlList);    
    }
    
    
// -----------------------------------------------------------------------------
// CControlGroup::ReDrawRect
// ReDraw the control in the rect
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
EXPORT_C void CControlGroup::ReDrawRect(const TRect& aRect)
    {   
	if(!AbleToDraw() || WholeHiden())
        return;
    
    if(aRect.IsEmpty())
        return;
    if(aRect == Rect())
        {
        Draw();    
        }
    else
        {        
        //find out the controls within the rect
        if( iNeedRedrawBg )
        	DrawBackground( aRect );            
        //DrawControlGroupBackground( aRect );
        TBool needDrawActiveCtrl = EFalse;
        for(TInt i=0;i<iCtrlList.Count();i++)
            {
            CFepUiBaseCtrl* ctrl=iCtrlList[i];
            if(!ctrl->Hiden() && aRect.Intersects(ctrl->Rect()))
                {
                if(iActiveCtrl == ctrl)
                    {
                    needDrawActiveCtrl = ETrue;
                    continue;
                    }
                TRect r = aRect;
                r.Intersection(ctrl->Rect());
                
                ctrl->ReDrawRect(r);
                }
                
            }
        if(needDrawActiveCtrl)
            {
            TRect r = aRect;
            r.Intersection(iActiveCtrl->Rect());
            
            iActiveCtrl->ReDrawRect(r);            
            }
        }        
            
    }    
    

// -----------------------------------------------------------------------------
// CControlGroup::SetTempActiveCtrl
// Set temparary active control in button down state
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CFepUiBaseCtrl* CControlGroup::SetTempActiveCtrl(CFepUiBaseCtrl* aCtrl)
    {
    if( aCtrl && 
    	aCtrl != iTempActiveCtrl && 
        !(aCtrl->ControlType() & ECtrlBackgroundCtrl) )
        {             
        //iPrevActiveCtrl = iActiveCtrl;   
        CFepUiBaseCtrl* previous = iTempActiveCtrl;
        iTempActiveCtrl = aCtrl;
        iTempActiveCtrl->SetActive(ETrue);
        //We need to check whether the control news status is successfully set.   
        if( iTempActiveCtrl->IsActive() )
            {
            if(previous)
                previous->SetActive(EFalse);
            }
        else
            {
            return previous;
            }
        }
    return iTempActiveCtrl;
    }
    
// -----------------------------------------------------------------------------
// CControlGroup::SetActiveCtrl
// Set active control
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C CFepUiBaseCtrl* CControlGroup::SetActiveCtrl(CFepUiBaseCtrl* aCtrl)
    {
    if( aCtrl &&
    	aCtrl != iActiveCtrl &&
    	!(aCtrl->ControlType() & ECtrlBackgroundCtrl) )
        {                
        CFepUiBaseCtrl* previous = iActiveCtrl;
        iActiveCtrl = aCtrl;
        //Change the previous control first, then current control
        if(previous)
            previous->SetActive(EFalse);

        iActiveCtrl->SetActive(ETrue);
        }        
    return iActiveCtrl;
    }
    
// -----------------------------------------------------------------------------
// CControlGroup::SetActiveCtrl
// Set active control
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
EXPORT_C CFepUiBaseCtrl* CControlGroup::SetActiveCtrl(TInt aIndex)
    {
    if(aIndex < 0 || aIndex >= iCtrlList.Count())
        return NULL;
    return SetActiveCtrl(iCtrlList[aIndex]);        
    }
  
// -----------------------------------------------------------------------------
// CControlGroup::ActiveControl
// Get active control
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
EXPORT_C CFepUiBaseCtrl* CControlGroup::ActiveControl()
    {
        return iActiveCtrl;
    }

// -----------------------------------------------------------------------------
// CControlGroup::NumOfControlss
// get control numbers
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
EXPORT_C TInt CControlGroup::NumOfControls()
    {
    return iCtrlList.Count();
    }
    

// -----------------------------------------------------------------------------
// CControlGroup::HideControl
// Hide control
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//       
EXPORT_C void CControlGroup::HideControl(TInt aIndex,TBool aFlag)
    {
    if(aIndex >=0 && aIndex < iCtrlList.Count())
        {
        HideControl(iCtrlList[aIndex],aFlag);
        }
    }
    
// -----------------------------------------------------------------------------
// CControlGroup::HideControl
// Hide control
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//           
EXPORT_C void CControlGroup::HideControl(CFepUiBaseCtrl* aControl,TBool aFlag)
    {
    if(!aControl  || aControl->Hiden() == aFlag)    
        return;
    
    aControl->Hide(aFlag);

    //recalculate the control group rect
    if(aFlag) //hide
        {        
        iRect.SetRect(0,0,0,0);
        for(TInt j = 0; j < iCtrlList.Count(); j++)
            {
            if(aControl != iCtrlList[j] && ! iCtrlList[j]->Hiden())
                {
                if(iRect.IsEmpty())
                    {
                    iRect = iCtrlList[j]->Rect();
                    }
                else
                    {
                    iRect.BoundingRect(iCtrlList[j]->Rect());
                    }
                }
            }
        }
    else	//show
        {
        if(iRect.IsEmpty())
            {
            iRect = aControl->Rect();
            }
        else 
            {                                   
            iRect.BoundingRect(aControl->Rect());
            }
        }

    UpdateValidRegion(aControl,ETrue);
        
    /*
    SetRect(rect);
    RRegion region(8);
    region.Copy(Region());   

    if(aFlag) //hide control
        region.SubRect(aControl->Rect());
    else
        region.AddRect(aControl->Rect());
    SetRegion(region);
    RootControl()->UpdateValidRegion(NULL,EFalse);
    */
    }


// -----------------------------------------------------------------------------
// CControlGroup::Hide
// Hide the control group and all it's controls
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
EXPORT_C void CControlGroup::Hide(TBool aFlag)
    {
    if(Hiden() == aFlag)
        return;
  /*  if(aFlag) //hide
        {
        SaveSubCtrlShownState();
        }*/
    DisableRegionUpdating(); //disable updating caused by sub controls           
    /*for (TInt i = 0; i < iCtrlList.Count(); ++i)
        {
        CFepUiBaseCtrl* ctrl = iCtrlList[i];
        TBool hideFlag = aFlag;
        if( i < iSubCtrlShowStateBeforeHiden.Count() && 
                    iSubCtrlShowStateBeforeHiden[i].iSubCtrl == ctrl)
            {            
            hideFlag = hideFlag || iSubCtrlShowStateBeforeHiden[i].iHiden;
            }
        ctrl->Hide(hideFlag); //loop sub controls        
        }*/
    EnableRegionUpdating();            
    CFepUiBaseCtrl::Hide(aFlag); //hide myself               
    /*if(!aFlag)
        iSubCtrlShowStateBeforeHiden.Reset();
*/
        }

// -----------------------------------------------------------------------------
// CControlGroup::Move
// Move control and component's rect
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//        
EXPORT_C void CControlGroup::Move(const TPoint& aOffset)
    {
    //disable region update and re-calculate it after all sub-control moved.
    DisableRegionUpdating();    
    CFepUiBaseCtrl::Move(aOffset);
    //move components
    for(TInt j = 0; j < iCtrlList.Count(); j++)
        {
        iCtrlList[j]->Move(aOffset);
        }    
    EnableRegionUpdating();
    UpdateValidRegion(NULL,ETrue); //recalculate valid region
    }
    
// -----------------------------------------------------------------------------
// CControlGroup::ControlById
// Get the sub control for given control Id. 
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//            
EXPORT_C CFepUiBaseCtrl* CControlGroup::ControlById(TInt aCtrlId)
    {
    CFepUiBaseCtrl* ctrl = NULL;
    
    for(TInt i = 0; i < iCtrlList.Count(); i++)
        {
        ctrl = iCtrlList[i];
        if(ctrl->ControlId() == aCtrlId)
            {
                return ctrl;
            }
        else
            {
            if(ctrl->IsKindOfControl(ECtrlControlGroup))
                {
                CFepUiBaseCtrl* subCtrl = static_cast<CControlGroup*>(ctrl)->
                                            ControlById(aCtrlId);
                if(subCtrl)
                    return subCtrl; 
                }
            }
        }

    return NULL;
    
    }
    
// ---------------------------------------------------------------------------
// CControlGroup::CancelPointerDownL
// Cancel pointer down event
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//    
EXPORT_C void CControlGroup::CancelPointerDownL()
    {
    //let the pointer downed control do the canceling
    if(iCtrlWithPointerDown)
        {
        if (iCtrlWithPointerDown != iActiveCtrl)
        	{
			iCtrlWithPointerDown->SetActive(EFalse);
			if (iActiveCtrl)
				{
				iActiveCtrl->SetActive(ETrue);        		
				}
        	}
        iCtrlWithPointerDown->CancelPointerDownL();
        iCtrlWithPointerDown = NULL;
        ReportEvent(EEventButtonDownCanceled);
        }    
    }

// ---------------------------------------------------------------------------
// CControlGroup::HandlePointerLeave
// Handle pointer leave event
// ---------------------------------------------------------------------------
//           
EXPORT_C void CControlGroup::HandlePointerLeave(const TPoint& aPt)
    {
    SetPointerDown( EFalse );
    iPointerLeft = ETrue;

    if(iCtrlWithPointerDown)
        {
        if(iCtrlWithPointerDown != iActiveCtrl)
            {
            SetTempActiveCtrl(iActiveCtrl);
            }
        iCtrlWithPointerDown->HandlePointerLeave(aPt);        
        }
    }
    
// ---------------------------------------------------------------------------
// CControlGroup::HandlePointerEnter
// Handle pointer enter event
// ---------------------------------------------------------------------------
//           
EXPORT_C void CControlGroup::HandlePointerEnter(const TPoint& aPt)
    {
    SetPointerDown( ETrue );
    iPointerLeft = EFalse;
    if(iCtrlWithPointerDown)
        {
        //does the pointer really enter this control?
        if(iCtrlWithPointerDown->Contains(aPt))
            {
            SetTempActiveCtrl(iCtrlWithPointerDown);
            iCtrlWithPointerDown->HandlePointerEnter(aPt);        
            }
        }
    }

// ---------------------------------------------------------------------------
// CControlGroup::ControlByType
// Get a control by type and index
// ---------------------------------------------------------------------------
//
EXPORT_C CFepUiBaseCtrl* CControlGroup::ControlByType(TControlType aType,TInt aIndex)
    {
    if(aIndex < 0)
        return NULL;
    
    CFepUiBaseCtrl* ctrl = NULL;
    TInt ctrlIdx = 0;
    for(TInt i = 0;i < iCtrlList.Count();i++)
        {
        if(iCtrlList[i]->ControlType() == aType)
            {
            if(ctrlIdx == aIndex)
                return iCtrlList[i];
            else
                ctrlIdx++;
            }
        else
            {
            //If sub control is a control group, loop inside the control group
            if(iCtrlList[i]->IsKindOfControl(ECtrlControlGroup))
                {
                CControlGroup* ctrlGroup = static_cast<CControlGroup*>(iCtrlList[i]);
                ctrl = ctrlGroup->ControlByType(aType,aIndex - ctrlIdx);
                if(ctrl)
                    return ctrl;
                }
            }
        }

    return ctrl;
    }

// ---------------------------------------------------------------------------
// CControlGroup::ControlHasType
// Get a control by type and index
// ---------------------------------------------------------------------------
//
EXPORT_C CFepUiBaseCtrl* CControlGroup::ControlForKindOfType(
                                        TStockBaseCtrlType aType,TInt aIndex)
    {
    
    if(aIndex < 0 || aIndex >= iCtrlList.Count())
        return NULL;
    
    CFepUiBaseCtrl* ctrl = NULL;
    TInt ctrlIdx = 0;
    for(TInt i = 0;i < iCtrlList.Count();i++)
        {
        if(iCtrlList[i]->IsKindOfControl(aType))
            {
            if(ctrlIdx == aIndex)
                return iCtrlList[i];
            else
                ctrlIdx++;
            }
        else
            {
            //If sub control is a control group, loop inside the control group
            if(iCtrlList[i]->IsKindOfControl(ECtrlControlGroup))
                {
                CControlGroup* ctrlGroup = static_cast<CControlGroup*>(iCtrlList[i]);
                ctrl = ctrlGroup->ControlForKindOfType(aType,aIndex - ctrlIdx);
                if(ctrl)
                    return ctrl;
                }
            }
        }

    return ctrl;
    }


// ---------------------------------------------------------------------------
// CControlGroup::OnDeActivate
// Response to layout de activation event
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//     
EXPORT_C void CControlGroup::OnDeActivate()
    {
    TRAP_IGNORE(OnDeActivateL());
    }

void CControlGroup::OnDeActivateL()
    {
    if(iCtrlWithPointerDown)
        {
        TRAP_IGNORE(iCtrlWithPointerDown->CancelPointerDownL());
        iCtrlWithPointerDown = NULL;
        }
    CFepUiBaseCtrl::OnDeActivate();
    for(TInt i = 0;i < iCtrlList.Count();i++)
        {
        CFepUiBaseCtrl* ctrl = iCtrlList[i];
        
        __ASSERT_DEBUG(ctrl,User::Leave(-1));    
        
        iCtrlList[i]->OnDeActivate();
        }
    }

// ---------------------------------------------------------------------------
// CControlGroup::OnDctivate
// Response to layout activation event
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//     
EXPORT_C void CControlGroup::OnActivate()
    {
    CFepUiBaseCtrl::OnActivate();
    for(TInt i = 0;i < iCtrlList.Count();i++)
        {
        iCtrlList[i]->OnActivate();
        }
    }

// ---------------------------------------------------------------------------
// CControlGroup::OnLayoutDraggingStart
// Response to layout dragging start event
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//     
EXPORT_C void CControlGroup::OnLayoutDraggingStart()
    {
    //notify child controls
    for(TInt i = 0; i < iCtrlList.Count(); i++)
        {
        iCtrlList[i]->OnLayoutDraggingStart();
        }
    }
    
// ---------------------------------------------------------------------------
// CControlGroup::OnLayoutDraggingEnd
// Response to layout dragging end event
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//     
EXPORT_C void CControlGroup::OnLayoutDraggingEnd()
    {
    //notify child controls    
    for(TInt i = 0; i < iCtrlList.Count(); i++)
        {
        iCtrlList[i]->OnLayoutDraggingEnd();
        }    
    }    

// ---------------------------------------------------------------------------
// CControlGroup::ConstructFromResourceL
// Handle resource change
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//     
EXPORT_C void CControlGroup::ConstructFromResourceL()
    {
    //let child control hanlde resource change.
    for(TInt i = 0; i < iCtrlList.Count(); i++)
        {
        iCtrlList[i]->ConstructFromResourceL();
        }    
    }
    
const RRegion& CControlGroup::CalculateNonHwrStartPtArea()
    {
    RRegion r;
    iNonHwrStartPtRegion.Clear();
    for(TInt i = 0; i < iCtrlList.Count(); ++i)
        {						 
        CFepUiBaseCtrl* ctrl = iCtrlList[i];
        if(ctrl->Hiden() || !ctrl->Ready())
            continue;
        if(ctrl->IsKindOfControl(ECtrlControlGroup))
            {
            iNonHwrStartPtRegion.Union(static_cast<CControlGroup*>(ctrl)->
                            CalculateNonHwrStartPtArea());
            continue;
            }
        if(ctrl->IsKindOfControl(ECtrlTransparentHwrWnd))
            {            
            r.Copy(ctrl->Region());
            continue;		          
            }
        
        iNonHwrStartPtRegion.AddRect(ctrl->Rect());
        }
    r.Sort();
    
    RRegion r2;
    r2.AddRect(UiLayout()->Rect());
    r2.SubRegion(iNonHwrStartPtRegion);
    r2.Sort();
    r2.Close();
    r.Close();
    return iNonHwrStartPtRegion;    
    }    
    
// ---------------------------------------------------------------------------
// CControlGroup::UpdateValidRegion
// Update control's valid region when other control show or hide.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
EXPORT_C void CControlGroup::UpdateValidRegion(CFepUiBaseCtrl* aCtrl,TBool aRemoveFlag)
    {
    if(!iUpdateFlagEnabled) //do nothing if disabled.
        return;
    
    if(aCtrl) //update due to this control
        {        
        TInt idx = FindSubRegion(aCtrl);
        if(aRemoveFlag)
            {
            if(idx == KErrNotFound)
                return;
            RemoveSubRegion(idx);            
            
            delete iSubRegionArea[idx];
            iSubRegionArea.Remove(idx);        
            CalculateClipRegion();        
            }
        else
            {
            if(idx == KErrNotFound) //new one
                {            
                //no need to check whether the control is hide as updating is done when 
                //control is hiden.
                //CSubRegionArea area(aCtrl,aCtrl->Region());
                //iSubRegionArea.Append(area);
                TRAP_IGNORE(AddSubRegionL(aCtrl));
                CalculateClipRegion(aCtrl);
                }
            else //replace the old one   
                {            
                RemoveSubRegion(idx);                                            
                iSubRegionArea[idx]->iSubRegion.Copy(aCtrl->Region());
                CalculateClipRegion();
                }
            iValidRegion.Union(aCtrl->Region());                
            }   
        }
    else //recalculate valid region
        {
        iSubRegionArea.ResetAndDestroy();
        iValidRegion.Clear();
        for(TInt i = 0 ; i < iCtrlList.Count(); ++i)
            {		
            iValidRegion.Union(iCtrlList[i]->Region()); 
            //CSubRegionArea area(aCtrl,aCtrl->Region());
            //iSubRegionArea.Append(area);
            TRAP_IGNORE(AddSubRegionL(iCtrlList[i]));
            }
            
        CalculateClipRegion();
        }
        
    if(iParentCtrl)
        iParentCtrl->UpdateValidRegion(this,EFalse);    
    }

TInt CControlGroup::FindSubRegion(CFepUiBaseCtrl* aCtrl)
    {
    for(TInt i = 0; i < iSubRegionArea.Count(); ++i)
        {
        if(aCtrl == iSubRegionArea[i]->iSubCtrl)
            return i;
        }
        
    return KErrNotFound;
    }

void CControlGroup::RemoveCtrlFromSubCtrlInfoList(CFepUiBaseCtrl* aControl)
    {
    for(TInt i = 0 ; i < iSubCtrlShowStateBeforeHiden.Count(); ++i)
        {
        if(iSubCtrlShowStateBeforeHiden[i].iSubCtrl == aControl)
            {
            iSubCtrlShowStateBeforeHiden.Remove(i);
            break;
            }
        }
    }

//record each sub control's current hide/show state
void CControlGroup::SaveSubCtrlShownState()
    {   
    iSubCtrlShowStateBeforeHiden.Reset(); 
    for (TInt i = 0; i < iCtrlList.Count(); ++i)
        {
        TSubCtrlShownState state = {iCtrlList[i],iCtrlList[i]->Hiden()};
            
        TRAP_IGNORE(iSubCtrlShowStateBeforeHiden.AppendL(state));
        }                
    }

void CControlGroup::AddSubRegionL(CFepUiBaseCtrl* aCtrl)
    {
    //no need to check aCtrl    
    CSubRegionArea* area = new (ELeave) CSubRegionArea(aCtrl,aCtrl->Region());
    CleanupStack::PushL(area);
    iSubRegionArea.AppendL(area);
    CleanupStack::Pop(area);    
    }
    
void CControlGroup::RemoveSubRegion(TInt aIdx)
    {    
    //check whether this region is clipped with other region
    RRegion overlappedReg;    
    for(TInt i = 0 ; i < iSubRegionArea.Count(); ++i)
        {
        if(i == aIdx)
            continue;
        
        RRegion r;
        r.Intersection(iSubRegionArea[aIdx]->iSubRegion,
                                        iSubRegionArea[i]->iSubRegion);
        overlappedReg.Union(r);
        r.Close();           
        }						   
    iValidRegion.SubRegion(iSubRegionArea[aIdx]->iSubRegion);
    iValidRegion.Union(overlappedReg);
    overlappedReg.Close();
    
    }

// -----------------------------------------------------------------------------
// CControlGroup::BringToTop
// Bring and show a control in current group
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//     
TBool CControlGroup::MoveSubCtrlToTop(CFepUiBaseCtrl* aCtrl,RPointerArray<CFepUiBaseCtrl>& aList)
    {
    TInt index = aList.Find(aCtrl); 
    if(KErrNotFound == index)
        return EFalse;
    //move the control to the end of the list
    for(; index < aList.Count() -1; ++index)
        {
        aList[index] = aList[index + 1];
        }
    aList[index] = aCtrl;
    return ETrue;    
    }

TBool CControlGroup::MoveSubCtrlToBack(CFepUiBaseCtrl* aCtrl,RPointerArray<CFepUiBaseCtrl>& aList)
    {
    TInt index = aList.Find(aCtrl); 
    if(KErrNotFound == index)
        return EFalse;
    //move the control to the start of the list
    for(; index > 0; --index)
        {
        //stop if found background control
        if( iCtrlList[index-1]->IsKindOfControl(ECtrlBackgroundCtrl) ||
            iCtrlList[index-1]->IsKindOfControl(ECtrlTransparentHwrWnd) )
            {
            break;
            }
        
        aList[index] = aList[index -1];
        }
    aList[index] = aCtrl;
    return ETrue;    
    }

EXPORT_C void CControlGroup::BringToTopInGroup(CFepUiBaseCtrl* aCtrl)
    {
    if(MoveSubCtrlToTop(aCtrl,iCtrlList)) //check in iCtrlList first
        {
        aCtrl->iClipRegion.Clear();
        aCtrl->iClipRegion.AddRect(aCtrl->Rect());
        UpdateValidRegion(aCtrl,EFalse);
        //other control should update its valid/clip region    
        }
    }

EXPORT_C void CControlGroup::BringToBackInGroup(CFepUiBaseCtrl* aCtrl)
    {
    if(MoveSubCtrlToBack(aCtrl,iCtrlList)) //check in iCtrlList first
        {
        aCtrl->iClipRegion.Clear();
        aCtrl->iClipRegion.AddRect(aCtrl->Rect());
        
        UpdateValidRegion(aCtrl,EFalse);
        //other control should update its valid/clip region    
        }
    }

// -----------------------------------------------------------------------------
// CControlGroup::OnResourceChange
// Handle system resource change 
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//     
EXPORT_C void CControlGroup::HandleResourceChange(TInt aType)
    {
    //let child control handle the resource change
    for(TInt i = 0 ; i < iCtrlList.Count(); ++i)
        {
        iCtrlList[i]->HandleResourceChange(aType);
        }
    CFepUiBaseCtrl::HandleResourceChange(aType);
    }
// -----------------------------------------------------------------------------
// CControlGroup::GraphicDeviceSizeChanged
// Handle graphic device size change event
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//     
EXPORT_C void CControlGroup::GraphicDeviceSizeChanged()
    {
    //let child control handle the resource change
    for(TInt i = 0 ; i < iCtrlList.Count(); ++i)
        {
        iCtrlList[i]->GraphicDeviceSizeChanged();
        }
    CFepUiBaseCtrl::GraphicDeviceSizeChanged();     
    }


// ---------------------------------------------------------------------------
// CControlGroup::UpdateArea
// Update layout area
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//       
void CControlGroup::UpdateAreaInGrp(CFepUiBaseCtrl* aControl,const TRect& aRect,TBool aUpdateFlag)
    {
    RedrawRectInGrp( aControl, aRect );
    UpdateArea(aRect,aUpdateFlag);
    }    
    
//implementation for class CControlGroup::CSubRegionArea::CSubRegionArea
CControlGroup::CSubRegionArea::CSubRegionArea(const CFepUiBaseCtrl* aCtrl,const RRegion &aRegion)
                                : iSubCtrl(aCtrl) //,iSubRegion(aRegion) 
    {
    iSubRegion.Copy(aRegion);
    //RRegion's copy constructor will make two region point to same data. !!!
    }
CControlGroup::CSubRegionArea::~CSubRegionArea()
    {
    iSubRegion.Close();
    }

TInt CControlGroup::GetNestedLevel()    
    {
    TInt level = 1;
    CFepUiBaseCtrl* parent = ParentCtrl();
    if(!parent)
        return 0; //This is the root control
 
    while(parent && parent != RootControl())
        {
        parent = ParentCtrl();
        level++;
        }
    return level;
    }


TInt CControlGroup::GetIdx(const CFepUiBaseCtrl* aCtrl)
    {
    for(TInt i = 0; i < iCtrlList.Count(); i++)
        {
        if(iCtrlList[i] == aCtrl)
            {
            return i;            
            }
        } 
    return KErrNotFound;   
    }

// ---------------------------------------------------------------------------
// CControlGroup::DrawControlGroupBackground
// Draw ControlGroup Background
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//  
EXPORT_C void CControlGroup::DrawControlGroupBackground( const TRect& aUpdateRegion )
	{
	DrawBackground( aUpdateRegion );
	}
	
void CControlGroup::AdjustBkCtrlPos()
    {
    //No need to check the first control
    TInt firstBkCtrlPos = 1;
    for(TInt i = 1 ; i < iCtrlList.Count(); ++i)
        {
        if(iCtrlList[i]->IsKindOfControl(ECtrlBackgroundCtrl)) 
            {
            //move to first
            CFepUiBaseCtrl* ctrl = iCtrlList[firstBkCtrlPos];
            iCtrlList[firstBkCtrlPos++] = iCtrlList[i];

            for(TInt j = i ; j < firstBkCtrlPos ; --j)
                {
                iCtrlList[j] = iCtrlList[j-1];
                }
            iCtrlList[firstBkCtrlPos] = ctrl;
            }
        else
            {
            if(iCtrlList[i]->IsKindOfControl(ECtrlControlGroup))
                {
                CControlGroup* ctrlGroup = static_cast<CControlGroup*>(iCtrlList[i]);
                ctrlGroup->AdjustBkCtrlPos();
                }
            }
        }
    } 	
    
// ---------------------------------------------------------------------------
// CControlGroup::UpdateAreaInGrpImmed
// Update layout area
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//  
void CControlGroup::UpdateAreaInGrpImmed(CFepUiBaseCtrl* aControl,const TRect& aRect,TBool aUpdateFlag)
    {
    RedrawRectInGrp( aControl, aRect );
    UpdateAreaImmed(aRect,aUpdateFlag);
    }    


// ---------------------------------------------------------------------------
// CControlGroup::RedrawRectInGrp
// Redraw rect
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//    
void CControlGroup::RedrawRectInGrp( CFepUiBaseCtrl* aControl,const TRect& aRect )
    {
    //check in ctrl list
    TInt idx = 0;
    for(; idx < iCtrlList.Count(); ++idx)
        {
        if(aControl == iCtrlList[idx])
            {
            ++idx;
            break;
            }
        }
       
    for(; idx < iCtrlList.Count(); ++idx)
        {
        if(aRect.Intersects(iCtrlList[idx]->Rect()) &&
                                        !iCtrlList[idx]->Hiden())
            {
            iCtrlList[idx]->ReDrawRect(aRect);
            }
        }
    //check the pop up list
    for(idx = 0 ; idx < iPopCtrlList.Count(); ++idx)
        {
        if(aRect.Intersects(iPopCtrlList[idx]->Rect()) && 
                                        !iPopCtrlList[idx]->Hiden())
            {
            if(aControl != iPopCtrlList[idx]) //not the same one
                iPopCtrlList[idx]->ReDrawRect(aRect);
            }
        }
    }    
//end of file
