// EIKCMBUT.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <eikcmbut.h>
#include <barsread.h>
#include <eikbordr.h>
#include <eikenv.h>
#include <eiklabel.h>
#include <eikimage.h>
#include <eikpanic.h>

#include "eikcolor.h"

const TInt KPressedDepth=2;
const TInt KSetDepth=1;
const TInt KShrinkAmount=KPressedDepth;

// the border types for the above set and pressed depths
const TEikBorder::TBorderType KBorderClear=TEikBorder::EDeepRaised;
const TEikBorder::TBorderType KBorderClearPressed=TEikBorder::EDeepSunken;
const TEikBorder::TBorderType KBorderSet=TEikBorder::EShallowSunken;
const TEikBorder::TBorderType KBorderSetPressed=TEikBorder::EDeepSunken;

const TInt KImageMargin=0;
const TInt KLabelMargin=0;
const TInt KIntraComponentMargin=2;
const TInt KLayoutMask				=0x0007;
const TInt KLayoutAndFontMask		=0x000f;
const TInt KExcessMask				=0x00f0;
const TInt KDisplayContentMask		=0x0f00;

//
// class CEikCommandButtonBase
//

EXPORT_C CEikCommandButtonBase::~CEikCommandButtonBase()
	{
	delete iComponents[0];
	delete iComponents[1];
	}

EXPORT_C CEikCommandButtonBase::CEikCommandButtonBase()
	{
	__DECLARE_NAME(_S("CEikCommandButton"));
	iBorder=TEikBorder(KBorderClear);
    iContext = this;
	SetBehavior(EEikButtonStaysClear);
	SetDisplayContent(EBoth); // default if button contains both
	SetExcessSpace(EShare); // default if button contains both
	SetButtonLayout(EFirstRightSecondLeft); // default if button contains both
	SetNonFocusing();
	}

EXPORT_C void CEikCommandButtonBase::SetTextL(const TDesC& aText,CEikAlignedControl*& aComponent)
	{
	if (aComponent==NULL)
		{
		CEikLabel* label=new(ELeave) CEikLabel;
		CleanupStack::PushL(label);
		label->SetContainerWindowL(*this);
		CleanupStack::Pop(); // label
		label->SetFont(iCmdFlags&EDenseFont? iEikonEnv->DenseFont() : iEikonEnv->LegendFont());
		label->SetAllMarginsTo(KLabelMargin);
		aComponent=label;
		}
	STATIC_CAST(CEikLabel*,aComponent)->SetTextL(aText);
	}

EXPORT_C void CEikCommandButtonBase::SetPictureL(const CFbsBitmap* aMain,const CFbsBitmap* aMask,CEikAlignedControl*& aComponent)
	{
	if (aMain)
		{
		CEikImage* image=new(ELeave) CEikImage;
		CleanupStack::PushL(image);
		image->SetContainerWindowL(*this);
		image->SetPicture(aMain,aMask);
		SetImageAttributes(image);
		if (IsReadyToDraw())
			image->ActivateL();
		if (aComponent)
			{
			const TRect rect(aComponent->Rect());
			if (rect.Width())
				image->SetRectL(rect); // won't leave
			delete aComponent;
			}
		CleanupStack::Pop(); // image
		aComponent=image;
		}
	else
		{
		delete aComponent;
		SetNewComponentExtentL();
		}
	}

EXPORT_C void CEikCommandButtonBase::SetPictureFromFileL(const TDesC& aFilename,TInt aMain,TInt aMask,CEikAlignedControl*& aComponent)
	{
	CEikImage* image=new(ELeave) CEikImage;
	CleanupStack::PushL(image);
	image->SetContainerWindowL(*this);
	image->CreatePictureFromFileL(aFilename,aMain,aMask);
	SetImageAttributes(image);
	if (IsReadyToDraw())
		image->ActivateL();
	if (aComponent)
		{
		const TRect rect(aComponent->Rect());
		if (rect.Width())
			image->SetRectL(rect); // won't leave
		delete aComponent;
		}
	CleanupStack::Pop(); // image
	aComponent=image;
	}

EXPORT_C void CEikCommandButtonBase::StartConstructFromResourceL(TResourceReader& aReader)
	{
	const TInt behavior=aReader.ReadInt16();
	SetBehavior(STATIC_CAST(TButtonBehavior,behavior));
	const TInt layout=aReader.ReadInt16();
	SetButtonLayout(STATIC_CAST(TLayout,(layout&KLayoutAndFontMask)));
	SetExcessSpace(STATIC_CAST(TExcess,(layout&KExcessMask)));
	}

EXPORT_C void CEikCommandButtonBase::ConstructLabelFromResourceL(TResourceReader& aReader,TWhichComponent aWhich)
	{
	TPtrC text=aReader.ReadTPtrC();
	if (text.Length())
		{
		SetTextL(text,((CEikAlignedControl*&)(aWhich==EFirst? iComponents[0] : iComponents[1])));
		CEikLabel* label=STATIC_CAST(CEikLabel*,(aWhich==EFirst? iComponents[0] : iComponents[1]));
		label->SetAllMarginsTo(KLabelMargin);
		label->SetContainerWindowL(*this);
		}
	}

EXPORT_C void CEikCommandButtonBase::ConstructImageFromResourceL(TResourceReader& aReader,TWhichComponent aWhich)
	{
	TPtrC bitmapFile=aReader.ReadTPtrC();
	const TInt bitmapId=aReader.ReadInt16();
	const TInt bitmapMask=aReader.ReadInt16();
	if (bitmapId!=-1)
		SetPictureFromFileL(bitmapFile,bitmapId,bitmapMask,(aWhich==EFirst? iComponents[0] : iComponents[1]));
	}

EXPORT_C TSize CEikCommandButtonBase::MinimumSize()
	{
	TSize size;
	const TSize comp1Size=(iComponents[0] ? iComponents[0]->MinimumSize() : size);
	const TSize comp2Size=(iComponents[1] ? iComponents[1]->MinimumSize() : size);
	size=TSize(2*KShrinkAmount,2*KShrinkAmount);
    size+=iBorder.SizeDelta();
	if (iComponents[1]==NULL || ((iCmdFlags&KDisplayContentMask)==EFirstOnly))
		size+=comp1Size;
	else if (iComponents[0]==NULL || ((iCmdFlags&KDisplayContentMask)==ESecondOnly))
		size+=comp2Size;
	else if (LayoutIsVertical())
		{
		size.iHeight+=comp1Size.iHeight+comp2Size.iHeight+KIntraComponentMargin;
		size.iWidth+=Max(comp1Size.iWidth,comp2Size.iWidth);
		}
	else
		{
		size.iWidth+=comp1Size.iWidth+comp2Size.iWidth+KIntraComponentMargin;
		size.iHeight+=Max(comp1Size.iHeight,comp2Size.iHeight);
		}
	return size;
	}

EXPORT_C void CEikCommandButtonBase::SetDimmed(TBool aDimmed)
	{
	CCoeControl::SetDimmed(aDimmed);
	if (iComponents[0])
		iComponents[0]->SetDimmed(aDimmed);
	if (iComponents[1])
		iComponents[1]->SetDimmed(aDimmed);
	}

EXPORT_C void CEikCommandButtonBase::SetContainerWindowL(const CCoeControl& aContainer)
	{
	CCoeControl::SetContainerWindowL(aContainer);
	if (iComponents[0])
		iComponents[0]->SetContainerWindowL(aContainer);
	if (iComponents[1])
		iComponents[1]->SetContainerWindowL(aContainer);
	}

EXPORT_C void CEikCommandButtonBase::ActivateL()
	{
	UpdateComponentAlignment();
	CCoeControl::ActivateL();
	}

EXPORT_C void CEikCommandButtonBase::UpdateComponentAlignment()
	{
	const TInt layout=iCmdFlags&KLayoutAndFontMask;
	if (layout==EFirstBottomSecondTop || layout==EFirstTopSecondBottom)
		{
		if (iComponents[0])
			iComponents[0]->SetAlignment(EHCenterVCenter);
		if (iComponents[1])
			iComponents[1]->SetAlignment(EHCenterVCenter);
		}
	else
		{
		if (iComponents[0])
			{
			if (iComponents[1])
				{
				iComponents[0]->SetAlignment(layout==EFirstLeftSecondRight? EHLeftVCenter : EHRightVCenter);
				iComponents[1]->SetAlignment(layout==EFirstLeftSecondRight? EHRightVCenter : EHLeftVCenter);
				}
			else
				iComponents[0]->SetAlignment(EHCenterVCenter);
			}
		else
			iComponents[1]->SetAlignment(EHCenterVCenter);
		}
	}

EXPORT_C void CEikCommandButtonBase::SetButtonLayout(TLayout aLayout)
	{
    iCmdFlags &= (~KLayoutAndFontMask);
	iCmdFlags |= aLayout;
	}

EXPORT_C void CEikCommandButtonBase::SetExcessSpace(TExcess aExcess)
	{
	iCmdFlags&=~KExcessMask;
	iCmdFlags|=aExcess;
	}

EXPORT_C void CEikCommandButtonBase::SetDisplayContent(TDisplayContent aContent)
	{
	iCmdFlags &= (~KDisplayContentMask);
	iCmdFlags |= aContent;
	}

EXPORT_C TInt CEikCommandButtonBase::CountComponentControls() const
	{
	__ASSERT_DEBUG((iComponents[0]||iComponents[1]),Panic(EEikPanicButtonHasNoComponent));
	if (iComponents[0] && iComponents[1] && ((iCmdFlags&KDisplayContentMask)==EBoth))
		return 2;
	return 1;
	}

EXPORT_C CCoeControl* CEikCommandButtonBase::ComponentControl(TInt aIndex) const
	{
	__ASSERT_DEBUG((iComponents[0]||iComponents[1]),Panic(EEikPanicButtonHasNoComponent));
	if (iComponents[1]==NULL || ((iCmdFlags&KDisplayContentMask)==EFirstOnly))
		return iComponents[0];
	if (iComponents[0]==NULL || ((iCmdFlags&KDisplayContentMask)==ESecondOnly))
		return iComponents[1];
	if (aIndex==0)
		return iComponents[0];
	return iComponents[1];
	}

EXPORT_C void CEikCommandButtonBase::SizeChangedL()
	{
	__ASSERT_DEBUG((iComponents[0]||iComponents[1]),Panic(EEikPanicButtonHasNoComponent));
    TRect innerRect=iBorder.InnerRect(Rect());
	innerRect.Shrink(KShrinkAmount,KShrinkAmount);
	innerRect.Move(iDrawOffset,iDrawOffset);
	if (iComponents[1]==NULL || ((iCmdFlags&KDisplayContentMask)==EFirstOnly))
		iComponents[0]->SetRectL(innerRect);
	else if (iComponents[0]==NULL || ((iCmdFlags&KDisplayContentMask)==ESecondOnly))
		iComponents[1]->SetRectL(innerRect);
	else
		SetComponentExtents(innerRect);
	}

EXPORT_C void CEikCommandButtonBase::LayoutComponentsL()
	{
	SizeChangedL();
	}

EXPORT_C void CEikCommandButtonBase::StateChanged()
	{
	TInt pos=0;
	const TDrawState drawState = DrawState();
	if (iButFlags&EEikButtonLatches)
		{
		switch (drawState)
			{
		case EDrawClear:
			iBorder.SetType(KBorderClear);
			break;
		case EDrawClearPressed:
			pos = KPressedDepth;
			iBorder.SetType(KBorderClearPressed);
			break;
		case EDrawSet:
			pos = KSetDepth;
			iBorder.SetType(KBorderSet);
			break;
		case EDrawSetPressed:
 			pos = KPressedDepth;
			iBorder.SetType(KBorderSetPressed);
			break;
		default:
			break;
			}
		}
	else
		{
		switch (drawState)
			{
		case EDrawSetPressed:
 			pos = KPressedDepth;
			iBorder.SetType(KBorderSetPressed);
			break;
		case EDrawClear:
			iBorder.SetType(KBorderClear);
			break;
		case EDrawClearPressed:
		case EDrawSet:
			pos = KSetDepth;
			iBorder.SetType(KBorderSet);
			break;
		default:
			break;
			}
		}

	if (pos==iDrawOffset)
		return;
	const TPoint delta(pos-iDrawOffset,pos-iDrawOffset);
	if (iComponents[0])
		iComponents[0]->SetPosition(iComponents[0]->Position()+delta);
	if (iComponents[1])
		iComponents[1]->SetPosition(iComponents[1]->Position()+delta);
	iDrawOffset=pos;
	}

EXPORT_C void CEikCommandButtonBase::PrepareContext(CWindowGc& aGc) const
	{
	aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	TRgb penColor;
	TRgb brushColor;
	switch (DrawState())
		{
	case EDrawSet:
//		penColor=KEikCommandButtonTextSetColor;
//		brushColor=KEikCommandButtonFaceSetColor;
		penColor=iEikonEnv->ControlColor(EEikColorButtonTextPressed,*this);
		brushColor=iEikonEnv->ControlColor(EEikColorButtonFaceSet,*this);
		break;
	case EDrawClearPressed:
//		penColor=KEikCommandButtonTextClearPressedColor;
//		brushColor=KEikCommandButtonFaceClearPressedColor;
		penColor=iEikonEnv->ControlColor(EEikColorButtonTextPressed,*this);
		brushColor=iEikonEnv->ControlColor(EEikColorButtonFaceClearPressed,*this);
		break;
	case EDrawClear:
//		penColor=KEikCommandButtonTextClearColor;
//		brushColor=KEikCommandButtonFaceClearColor;
		penColor=iEikonEnv->ControlColor(EEikColorButtonText,*this);
		brushColor=iEikonEnv->ControlColor(EEikColorButtonFaceClear,*this);
		break;
	case EDrawSetPressed:
//		penColor=KEikCommandButtonTextSetPressedColor;
//		brushColor=KEikCommandButtonFaceSetPressedColor;
		penColor=iEikonEnv->ControlColor(EEikColorButtonText,*this);
		brushColor=iEikonEnv->ControlColor(EEikColorButtonFaceSetPressed,*this);
		break;
	default:
		break;
		}
	aGc.SetPenColor(penColor);
	aGc.SetBrushColor(brushColor);
	}

EXPORT_C void CEikCommandButtonBase::Draw(const TRect& /*aRect*/) const
	{
	CWindowGc& gc=SystemGc();
    iBorder.Draw(gc,Rect());
	PrepareContext(gc);
    TRect outer=iBorder.InnerRect(Rect());
	TRect innerRect = outer;

	innerRect.Shrink(KShrinkAmount+1,KShrinkAmount+1);
	innerRect.Move(iDrawOffset,iDrawOffset);
	innerRect.iBr.iX-=1;
	innerRect.iBr.iY-=1;
	EikDrawUtils::ClearBetweenRects(gc,outer,innerRect);

    }

void CEikCommandButtonBase::SetComponentExtents(const TRect& aRect)
	{
	TSize comp1Size=iComponents[0]->MinimumSize();
	TSize comp2Size=iComponents[1]->MinimumSize();
	const TInt excess=(LayoutIsVertical()? 
								aRect.Size().iHeight-(comp1Size+comp2Size).iHeight :
								aRect.Size().iWidth-(comp1Size+comp2Size).iWidth);
	switch (iCmdFlags&KExcessMask)
		{
	case EToFirst:
		if (LayoutIsVertical())
			comp1Size.iHeight+=excess-KIntraComponentMargin;
		else
			comp1Size.iWidth+=excess-KIntraComponentMargin;
		break;
	case EToSecond:
		if (LayoutIsVertical())
			comp2Size.iHeight+=excess-KIntraComponentMargin;
		else
			comp2Size.iWidth+=excess-KIntraComponentMargin;
		break;
	case EShare:
		if (LayoutIsVertical())
			{
			comp2Size.iHeight+=excess>>1;
			comp1Size.iHeight+=excess-(excess>>1);
			}
		else
			{
			comp2Size.iWidth+=excess>>1;
			comp1Size.iWidth+=excess-(excess>>1);
			}
		break;
		}
	if (LayoutIsVertical())
		{
		comp2Size.iHeight+=KIntraComponentMargin>>1;
		comp1Size.iHeight+=KIntraComponentMargin>>1;
		}
	else
		{
		comp2Size.iWidth+=KIntraComponentMargin>>1;
		comp1Size.iWidth+=KIntraComponentMargin>>1;
		}
	TRect comp1Rect=aRect;
	TRect comp2Rect=aRect;
    switch (iCmdFlags&KLayoutMask)
        {
    case EFirstTopSecondBottom:
		comp2Rect.iTl.iY+=comp1Size.iHeight;
		comp1Rect.iBr.iY=comp2Rect.iTl.iY;
		iComponents[0]->iMargin.iBottom=KIntraComponentMargin>>1;
		iComponents[1]->iMargin.iTop=KIntraComponentMargin>>1;
        break;
    case EFirstBottomSecondTop:
		comp1Rect.iTl.iY+=comp2Size.iHeight;
		comp2Rect.iBr.iY=comp1Rect.iTl.iY;
		iComponents[0]->iMargin.iTop=KIntraComponentMargin>>1;
		iComponents[1]->iMargin.iBottom=KIntraComponentMargin>>1;
        break;
    case EFirstLeftSecondRight:
		comp2Rect.iTl.iX+=comp1Size.iWidth;
		comp1Rect.iBr.iX=comp2Rect.iTl.iX;
		iComponents[0]->iMargin.iRight=KIntraComponentMargin>>1;
		iComponents[1]->iMargin.iLeft=KIntraComponentMargin>>1;
        break;
    case EFirstRightSecondLeft:
		comp1Rect.iTl.iX+=comp2Size.iWidth;
		comp2Rect.iBr.iX=comp1Rect.iTl.iX;
		iComponents[0]->iMargin.iLeft=KIntraComponentMargin>>1;
		iComponents[1]->iMargin.iRight=KIntraComponentMargin>>1;
        break;
		}
	iComponents[0]->SetRectL(comp1Rect); // won't leave
	iComponents[1]->SetRectL(comp2Rect); // won't leave
	}

void CEikCommandButtonBase::SetImageAttributes(CEikImage* aImage)
	{
//	aImage->SetAlignment(EHCenterVCenter);
	aImage->SetAllMarginsTo(KImageMargin);
	}

void CEikCommandButtonBase::SetNewComponentExtentL()
// only ever called when the image changes
	{
    TRect innerRect=iBorder.InnerRect(Rect());
	innerRect.Shrink(KShrinkAmount,KShrinkAmount);
	innerRect.Move(iDrawOffset,iDrawOffset);
	if (!iComponents[1] || (iCmdFlags&KDisplayContentMask==EFirstOnly))
		iComponents[0]->SetRectL(innerRect);
	else if (!iComponents[0] || (iCmdFlags&KDisplayContentMask==ESecondOnly))
		iComponents[1]->SetRectL(innerRect);
	else
		SetComponentExtents(innerRect);
	}

TBool CEikCommandButtonBase::LayoutIsVertical() const
	{ // !! change back to TLayout values to simplify this routine again
	TInt layout=iCmdFlags&KLayoutMask;
	return (layout==EFirstBottomSecondTop || layout==EFirstTopSecondBottom);
	}

EXPORT_C void CEikCommandButtonBase::Reserved_1()
	{}
EXPORT_C void CEikCommandButtonBase::Reserved_2()
	{}
EXPORT_C void CEikCommandButtonBase::Reserved_3()
	{}
EXPORT_C void CEikCommandButtonBase::Reserved_4()
	{}

//
// class CEikCommandButton
//

EXPORT_C CEikCommandButton::CEikCommandButton()
	{}

EXPORT_C CEikCommandButton::~CEikCommandButton()
	{}

EXPORT_C void CEikCommandButton::SetTextL(const TDesC& aText)
	{
	CEikCommandButtonBase::SetTextL(aText,iComponents[0]);
	}

EXPORT_C void CEikCommandButton::SetPictureL(const CFbsBitmap* aMain,const CFbsBitmap* aMask)
	{
	CEikCommandButtonBase::SetPictureL(aMain,aMask,iComponents[1]);
	}

EXPORT_C void CEikCommandButton::SetPictureFromFileL(const TDesC& aFilename,TInt aMain,TInt aMask)
	{
	CEikCommandButtonBase::SetPictureFromFileL(aFilename,aMain,aMask,iComponents[1]);
	}

EXPORT_C CEikLabel* CEikCommandButton::Label() const
	{
	return STATIC_CAST(CEikLabel*,iComponents[0]);
	}

EXPORT_C CEikImage* CEikCommandButton::Picture() const
	{
	return STATIC_CAST(CEikImage*,iComponents[1]);
	}

EXPORT_C void CEikCommandButton::SetButtonLayout(TLayout aLayout)
	{
	CEikCommandButtonBase::SetButtonLayout(((CEikCommandButtonBase::TLayout)aLayout));
	}

EXPORT_C void CEikCommandButton::SetExcessSpace(TExcess aExcess)
	{
	CEikCommandButtonBase::SetExcessSpace(((CEikCommandButtonBase::TExcess)aExcess));
	}

EXPORT_C void CEikCommandButton::SetDisplayContent(TDisplayContent aContent)
	{
	CEikCommandButtonBase::SetDisplayContent(((CEikCommandButtonBase::TDisplayContent)aContent));
	}

EXPORT_C void CEikCommandButton::ConstructFromResourceL(TResourceReader& aReader)
	{
	StartConstructFromResourceL(aReader);
	ConstructLabelFromResourceL(aReader,EFirst);
	ConstructImageFromResourceL(aReader,ESecond);
	}

EXPORT_C void CEikCommandButton::UpdateComponentAlignment()
	{
	const TInt layout=iCmdFlags&KLayoutAndFontMask;
	if (layout==EFirstBottomSecondTop || layout==EFirstTopSecondBottom)
		{
		if (iComponents[0])
			iComponents[0]->SetAlignment(EHCenterVCenter);
		if (iComponents[1])
			iComponents[1]->SetAlignment(EHCenterVCenter);
		}
	else
		{
		if (iComponents[0])
			{
			if (iComponents[1])
				{
				iComponents[0]->SetAlignment(EHLeftVCenter); // always align text on the left
				iComponents[1]->SetAlignment(layout==EFirstLeftSecondRight? EHRightVCenter : EHLeftVCenter);
				}
			else
				iComponents[0]->SetAlignment(EHCenterVCenter);
			}
		else
			iComponents[1]->SetAlignment(EHCenterVCenter);
		}
	}

//
// class CEikTextButton
//

EXPORT_C CEikTextButton::CEikTextButton()
	{}

EXPORT_C CEikTextButton::~CEikTextButton()
	{}

EXPORT_C void CEikTextButton::SetTextL(const TDesC& aText,TWhichComponent aWhich)
	{
	CEikCommandButtonBase::SetTextL(aText,(aWhich==EFirst? iComponents[0] : iComponents[1]));
	}

EXPORT_C CEikLabel* CEikTextButton::Label(TWhichComponent aWhich) const
	{
	return STATIC_CAST(CEikLabel*,(aWhich==EFirst? iComponents[0] : iComponents[1]));
	}

EXPORT_C void CEikTextButton::ConstructFromResourceL(TResourceReader& aReader)
	{
	StartConstructFromResourceL(aReader);
	ConstructLabelFromResourceL(aReader,EFirst);
	ConstructLabelFromResourceL(aReader,ESecond);
	}

//
// class CEikBitmapButton
//

EXPORT_C CEikBitmapButton::CEikBitmapButton()
	{}

EXPORT_C CEikBitmapButton::~CEikBitmapButton()
	{}

EXPORT_C void CEikBitmapButton::SetPictureL(const CFbsBitmap* aMain,const CFbsBitmap* aMask,TWhichComponent aWhich)
	{
	CEikCommandButtonBase::SetPictureL(aMain,aMask,(aWhich==EFirst? iComponents[0] : iComponents[1]));
	}

EXPORT_C void CEikBitmapButton::SetPictureFromFileL(const TDesC& aFilename,TInt aMain,TInt aMask,TWhichComponent aWhich)
	{
	CEikCommandButtonBase::SetPictureFromFileL(aFilename,aMain,aMask,(aWhich==EFirst? iComponents[0] : iComponents[1]));
	}

EXPORT_C CEikImage* CEikBitmapButton::Picture(TWhichComponent aWhich) const
	{
	return STATIC_CAST(CEikImage*,(aWhich==EFirst? iComponents[0] : iComponents[1]));
	}

EXPORT_C void CEikBitmapButton::ConstructFromResourceL(TResourceReader& aReader)
	{
	StartConstructFromResourceL(aReader);
	ConstructImageFromResourceL(aReader,EFirst);
	ConstructImageFromResourceL(aReader,ESecond);
	}
