// EIKGYSEL.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <eikgysel.h>
#include <eikgysel.hrh>
#include <bamatch.h>
#include <barsread.h>
#include <badesca.h>
#include <eikenv.h>
#include <eikchlst.hrh>
#include <eikcmbut.h>
#include <eikdutil.h>
#include <eiksfont.h>
#include <eikon.rsg>


const TInt KMaxGray16Level=16;
const TInt KMaxGray4Level=4;
const TInt KIndicatorWidth=8;
const TInt KIndicatorHeight=5;
const TInt KEikGrayDisplayWidth=20;
const TInt KPaletteSpaceToScreenEdge=10;

//
// class CEikGraySelector
//
	   
EXPORT_C CEikGraySelector::CEikGraySelector()
	{
	}

EXPORT_C void CEikGraySelector::ConstructL(CCoeControl* aParent, TInt aFlags)
	{
	SetContainerWindowL(*aParent);
	BaseConstructL(aFlags);
	}

void CEikGraySelector::BaseConstructL(TInt aFlags)
	{
	iGraySelectorFlags = aFlags;
	if (iGraySelectorFlags & EEikGraySelIncrementalMatching)
		iChoiceListFlags |= EEikChlistIncrementalMatching;
	if ((iGraySelectorFlags & (EEikGraySelDisplay4Gray|EEikGraySelDisplay16Gray)) && 
				(iGraySelectorFlags & EEikGraySelDisplay16Color))
		{
		TInt numGrays=0;
		TInt numColors=0;
		TDisplayMode defaultMode=iEikonEnv->WsSession().GetDefModeMaxNumColors(numColors,numGrays);
		if ((aFlags&EEikGraySelColorIfAvailable && numColors>=16) || defaultMode>=EColor16)
			iGraySelectorFlags&=~(EEikGraySelDisplay4Gray|EEikGraySelDisplay16Gray);
		else
			iGraySelectorFlags&=~(EEikGraySelDisplay16Color);
		}
	CreateGrayLevelArrayL();
	// ConstructTabButtonL();
	if (iChoiceListFlags&EEikChlistIncrementalMatching && iArray)
		iMatchBuf=new(ELeave)RIncrMatcherBuf<KEikMaxMatchingBufLength>;
	}

EXPORT_C CEikGraySelector::~CEikGraySelector()
	{
	DestroyPopout();
	}

EXPORT_C TSize CEikGraySelector::MinimumSize()
	{
	TSize size;
	TInt textWidth = 0;
	if (!(iGraySelectorFlags&EEikGraySelDisplayNoText))
		textWidth = CalculateTextWidth() + 2*KEikChoiceListTextEdge;
	size.iWidth = textWidth + KEikGrayDisplayWidth + iBorder.SizeDelta().iWidth;
	size.iHeight = iEikonEnv->EditableControlStandardHeight();
	return size;
	}

EXPORT_C void CEikGraySelector::ConstructFromResourceL(TResourceReader& aReader)
	{
	BaseConstructL(aReader.ReadInt16());
	}

void CEikGraySelector::CreateGrayLevelArrayL()
	{
	if (iGraySelectorFlags&EEikGraySelDisplayNoText)
		{
		iArray=new(ELeave) CDesCArrayFlat(4);
		TPtrC blank;
		for (TInt ii=0;ii<KMaxGray16Level;ii++)
			DesCArray()->AppendL(blank);
		}
	else
		{
		if (iGraySelectorFlags&EEikGraySelDisplay16Gray)
			{
			iArray=new(ELeave) CDesCArrayFlat(4); // granularity of 4
			TBuf<2> level;
			for (TInt ii=0;ii<KMaxGray16Level;ii++)
				{
				level.Num(ii);
				DesCArray()->AppendL(level);
				}
			}
		else if (iGraySelectorFlags&EEikGraySelDisplay16Color)
			iArray=iCoeEnv->ReadDesCArrayResourceL(R_EIK_SIXTEEN_COLOR_NAMES);
		else if (iGraySelectorFlags&EEikGraySelDisplay4Gray)
			iArray=iCoeEnv->ReadDesCArrayResourceL(R_EIK_FOUR_GRAY_NAMES);
		}
	}

EXPORT_C void CEikGraySelector::DrawContent() const
	{
	CWindowGc& gc = SystemGc();
   	gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	gc.SetBrushColor(KRgbWhite);
	gc.UseFont(iEikonEnv->NormalFont());
	TRect rect = iBorder.InnerRect(Rect());
	rect.iBr.iX -= KEikGrayDisplayWidth;
	TPtrC ptr;
	if (iArray && iArray->MdcaCount() && (iCurrentItem != -1))
		ptr.Set(iArray->MdcaPoint(iCurrentItem));
	if (!(iGraySelectorFlags&EEikGraySelDisplayNoText))
		{
		gc.SetBrushColor(iEikonEnv->ControlColor(EEikColorControlBackground, *this));
		gc.SetPenColor(iEikonEnv->ControlColor(EEikColorControlText, *this));
		gc.DrawText(ptr,rect,iAscent,CGraphicsContext::ELeft,KEikChoiceListTextEdge);
		}
	TRect displayRect(TPoint(rect.iBr.iX,rect.iTl.iY),rect.iBr+TPoint(KEikGrayDisplayWidth,0));
//	gc.SetPenColor(KRgbWhite);
	gc.SetPenColor(iEikonEnv->ControlColor(EEikColorControlBackground, *this));
	gc.SetBrushStyle(CGraphicsContext::ENullBrush);
	gc.DrawRect(displayRect);
	displayRect.Shrink(1,1);
	gc.DrawRect(displayRect);
	displayRect.Shrink(1,1);
	gc.SetPenColor(KRgbBlack);
	gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	TRgb color=TRgb::Gray4(iCurrentItem);
	if (iGraySelectorFlags&EEikGraySelDisplay16Color)
		color=TRgb::Color16(iCurrentItem);
	else if (iGraySelectorFlags&EEikGraySelDisplay16Gray)
		color=TRgb::Gray16(iCurrentItem);
	gc.SetBrushColor(color);
	gc.DrawRect(displayRect);
	}

EXPORT_C void CEikGraySelector::DestroyPopout()
	{
	if (iGrayPalette)
		{
		iEikonEnv->RemoveFromStack(iGrayPalette);
		delete(iGrayPalette);
		iGrayPalette=NULL;
		}
	}

EXPORT_C void CEikGraySelector::CreatePopoutL()
	{
	if (!iArray || !iArray->MdcaCount())
		return;
	if (iGrayPalette)
		return;
	TRAPD(err,DoCreatePopoutL());
	if (err)
		{
		DestroyPopout();
		User::Leave(err);
		}
	}

EXPORT_C void CEikGraySelector::DoCreatePopoutL()
	{
	iGrayPalette=new(ELeave) CEikGrayPalette();
//	iGrayPalette->ConstructL(iGraySelectorFlags&EEikGraySelDisplay16Gray? CEikGrayPalette::EDisplayMode16Gray : CEikGrayPalette::EDisplayMode4Gray);
	iGrayPalette->ConstructL(iGraySelectorFlags&EEikGraySelDisplay4Gray? CEikGrayPalette::EDisplayMode4Gray : 
								(iGraySelectorFlags&EEikGraySelDisplay16Color ? 
										CEikGrayPalette::EDisplayMode16Color : CEikGrayPalette::EDisplayMode16Gray));
	iGrayPalette->SetObserver(this);
	TRgb color=TRgb::Gray4(iCurrentItem);
	if (iGraySelectorFlags&EEikGraySelDisplay16Gray)
		color=TRgb::Gray16(iCurrentItem);
	else if (iGraySelectorFlags&EEikGraySelDisplay16Color)
		color=TRgb::Color16(iCurrentItem);
	iGrayPalette->SetSelectedGray(color);
	iEikonEnv->AddWindowShadow(iGrayPalette);
	TSize screenSize=iCoeEnv->ScreenDevice()->SizeInPixels();
	TInt paletteHeight=screenSize.iHeight;
	if (iGraySelectorFlags&EEikGraySelDisplay4Gray)
		paletteHeight/=2;
	paletteHeight-=2*KPaletteSpaceToScreenEdge;
	TRect paletteRect=TRect(PositionRelativeToScreen(),TSize(Size().iWidth,paletteHeight));
	TInt checkHeight=paletteRect.iBr.iY+KPaletteSpaceToScreenEdge-screenSize.iHeight;
	if (checkHeight>0)
		paletteRect.Move(0,-checkHeight);
	iGrayPalette->SetRectL(paletteRect);
	iEikonEnv->AddDialogLikeControlToStackL(iGrayPalette);
	iGrayPalette->ActivateL();
	}

EXPORT_C TInt CEikGraySelector::PopoutCurrentItem() const
	{
	TRgb color=iGrayPalette->SelectedGray();
	TInt item=color.Gray4();
	if (iGraySelectorFlags&EEikGraySelDisplay16Gray)
		item=color.Gray16();
	else if (iGraySelectorFlags&EEikGraySelDisplay16Color)
		item=color.Color16();
	return(item);
	}
		   
EXPORT_C TRgb CEikGraySelector::SelectedColor() const
	{
	TRgb color=TRgb::Gray4(iCurrentItem);
	if (iGraySelectorFlags&EEikGraySelDisplay16Gray)
		color=TRgb::Gray16(iCurrentItem);
	else if (iGraySelectorFlags&EEikGraySelDisplay16Color)
		color=TRgb::Color16(iCurrentItem);
	return(color);
	}

EXPORT_C void CEikGraySelector::SetSelectedColor(TRgb& aColor)
	{
	TInt item=aColor.Gray4();
	if (iGraySelectorFlags&EEikGraySelDisplay16Gray)
		item=aColor.Gray16();
	else if (iGraySelectorFlags&EEikGraySelDisplay16Color)
		item=aColor.Color16();
	SetCurrentItem(item);
	}

//
// Class CEikGrayPalette
//


EXPORT_C CEikGrayPalette::~CEikGrayPalette()
	{
	}

EXPORT_C CEikGrayPalette::CEikGrayPalette()
	{
	__DECLARE_NAME(_S("CEikGrayPalette"));
	iBorder=TEikBorder(TEikBorder::EDeepRaisedWithOutline);
	}
EXPORT_C void CEikGrayPalette::ConstructL(TGrayPaletteDisplayMode aMode)
	{
	CreateWindowL();
	EnableDragEvents();
	Window().SetPointerGrab(ETrue);
	iMaxGrayLevel=aMode;
	}

inline TInt CEikGrayPalette::MaxLevel() const
	{
	return(((iMaxGrayLevel&EDisplayMode16Gray) || (iMaxGrayLevel&EDisplayMode16Color))? KMaxGray16Level : KMaxGray4Level);
	}

EXPORT_C void CEikGrayPalette::SizeChangedL()
	{
	TRect displayRect=iBorder.InnerRect(Rect());
	iTopLeft=displayRect.iTl;
	if (MaxLevel()==KMaxGray16Level)
		iSingleGrayDisplaySize=TSize(displayRect.Width()/2,displayRect.Height()/(KMaxGray16Level/2));
	else
		iSingleGrayDisplaySize=TSize(displayRect.Width(),displayRect.Height()/KMaxGray4Level);
	}

EXPORT_C void CEikGrayPalette::Draw(const TRect& /*aRect*/) const
	{
	iBorder.Draw(SystemGc(),Rect());
	DrawGraySelections();
	DrawHighlightToGray(iSelectedGray,ETrue);
	}

void CEikGrayPalette::DrawHighlightToGray(TInt aGrayLevel, TBool aHighLighted) const
	{
	const TInt indicatorWidth=(MaxLevel()==KMaxGray16Level? KIndicatorWidth : 2*KIndicatorWidth);
	TPoint topLeft=iTopLeft;
	if (aGrayLevel<(KMaxGray16Level/2))
		topLeft+=TPoint(0,aGrayLevel*iSingleGrayDisplaySize.iHeight);
	else
		topLeft+=TPoint(iSingleGrayDisplaySize.iWidth,(aGrayLevel-8)*iSingleGrayDisplaySize.iHeight);
	TRect rect=TRect(topLeft,iSingleGrayDisplaySize);
	rect.Shrink(1,1);
	if (aGrayLevel<(KMaxGray16Level/2))
		rect.iBr.iX=rect.iTl.iX+indicatorWidth;
	else
		rect.iTl.iX=rect.iBr.iX-indicatorWidth;
	CWindowGc& gc=SystemGc();
	gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	gc.SetBrushColor(iEikonEnv->ControlColor(EEikColorControlBackground, *this));
	if (!aHighLighted)
		{
		gc.SetPenStyle(CGraphicsContext::ENullPen);
		gc.DrawRect(rect);
		}
	else
		{
		const TInt charCode=(MaxLevel()==KMaxGray16Level? (aGrayLevel<KMaxGray16Level/2? 
							ESymFontGraySel16RightPoint : ESymFontGraySel16LeftPoint) :
							ESymFontGraySel4);
		gc.SetPenStyle(CGraphicsContext::ESolidPen);
		gc.SetPenColor(KRgbBlack);
		const CFont* font=iEikonEnv->SymbolFont();
		gc.UseFont(font);
		const TInt offset=Max(font->AscentInPixels(),
							(rect.Height() - font->HeightInPixels())/2 + font->AscentInPixels());
		TBuf<1> buf;
		buf.Append(TChar(charCode));
		const CGraphicsContext::TTextAlign align=(MaxLevel()==KMaxGray16Level? (aGrayLevel<KMaxGray16Level/2? 
							CGraphicsContext::ERight : CGraphicsContext::ELeft) : CGraphicsContext::ERight);
		gc.DrawText(buf,rect,offset,align);
		gc.UseFont(iEikonEnv->NormalFont());
		}
	}

void CEikGrayPalette::DrawHighlightToGrayNow(TInt aGrayLevel, TBool aHighLighted) const
	{
	ActivateGc();
	DrawHighlightToGray(aGrayLevel,aHighLighted);
	DeactivateGc();
	}

void CEikGrayPalette::DrawGraySelections() const
	{
	TInt indicatorWidth=2*KIndicatorWidth;
	if (MaxLevel()==KMaxGray16Level)
		indicatorWidth= KIndicatorWidth;

	CWindowGc& gc=SystemGc();
	TRect rect=TRect(iTopLeft,iSingleGrayDisplaySize);
	TInt colorLevel=0;
	FOREVER
		{
		if (colorLevel>=MaxLevel())
			break;
		TRgb color=TRgb::Gray4(colorLevel);
		if (iMaxGrayLevel&EDisplayMode16Gray)
			color=TRgb::Gray16(colorLevel);
		else if (iMaxGrayLevel&EDisplayMode16Color)
			color=TRgb::Color16(colorLevel);
		TRect drawRect=rect;
		gc.SetPenColor(iEikonEnv->ControlColor(EEikColorControlBackground, *this));
		gc.SetBrushStyle(CGraphicsContext::ENullBrush);
		gc.DrawRect(drawRect);
		drawRect.Shrink(1,1);
		gc.DrawRect(drawRect);
		drawRect.Shrink(1,1);
		TRect indicatorRect(drawRect.iTl,TPoint(drawRect.iTl.iX+indicatorWidth,drawRect.iBr.iY));
		drawRect.Resize(-indicatorWidth,0);
		if (colorLevel<KMaxGray16Level/2)
			drawRect.Move(indicatorRect.Width(),0);
		else
			indicatorRect.Move(drawRect.Width(),0);
		gc.SetBrushColor(iEikonEnv->ControlColor(EEikColorControlBackground, *this));
		gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
		gc.DrawRect(indicatorRect);
		gc.SetPenColor(KRgbBlack);
		gc.SetBrushColor(color);
		gc.DrawRect(drawRect);
		rect.Move(0,iSingleGrayDisplaySize.iHeight);
		colorLevel++;
		if (colorLevel==KMaxGray16Level/2)
			rect.SetRect(iTopLeft+TPoint(iSingleGrayDisplaySize.iWidth,0),iSingleGrayDisplaySize);
		}
	TRect displayRect=iBorder.InnerRect(Rect());
	gc.SetPenColor(iEikonEnv->ControlColor(EEikColorControlBackground, *this));
	gc.SetBrushColor(iEikonEnv->ControlColor(EEikColorControlBackground, *this));
	gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	TRect innerRect(displayRect.iTl,TPoint(rect.iBr.iX,rect.iTl.iY));
	EikDrawUtils::DrawBetweenRects(gc,displayRect,innerRect);
	}

EXPORT_C void CEikGrayPalette::HandlePointerEventL(const TPointerEvent& aPointerEvent)
	{
	if ((aPointerEvent.iType==TPointerEvent::EButton1Down || aPointerEvent.iType==TPointerEvent::EButton1Up) && !Rect().Contains(aPointerEvent.iPosition))
		{
		ReportEventL(MCoeControlObserver::EEventRequestCancel);
		return;
		}
	switch (aPointerEvent.iType)
		{
		case TPointerEvent::EButton1Down:
		case TPointerEvent::EDrag:
			{
			TPoint pos=aPointerEvent.iPosition-Rect().iTl;
			TInt oldSelectedGray=iSelectedGray;
			iSelectedGray=0;
			TInt maxCount=MaxLevel();
			if (MaxLevel()==KMaxGray16Level)
				maxCount/=2;
			for (TInt i=0;i<maxCount;i++)
				{
				if (aPointerEvent.iPosition.iY>(iTopLeft.iY+(maxCount-1-i)*iSingleGrayDisplaySize.iHeight))
					{
					iSelectedGray=maxCount-1-i;
					break;
					}
				}
			if (MaxLevel()==KMaxGray16Level && pos.iX>iTopLeft.iX+iSingleGrayDisplaySize.iWidth)
				iSelectedGray+=KMaxGray16Level/2;
			if (oldSelectedGray!=iSelectedGray)
				{
				DrawHighlightToGrayNow(oldSelectedGray,EFalse);
				DrawHighlightToGrayNow(iSelectedGray,ETrue);
				ReportEventL(MCoeControlObserver::EEventStateChanged);
				}
			break;
			}
		case TPointerEvent::EButton1Up:
			ReportEventL(MCoeControlObserver::EEventRequestExit);
			break;
		default:
			break;
		}
	}

EXPORT_C TKeyResponse CEikGrayPalette::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode /*aType*/)
	{
	TInt oldSelectedGray=iSelectedGray;
	switch (aKeyEvent.iCode)
		{
	case EKeyUpArrow:
		iSelectedGray--;
		break;
	case EKeyDownArrow:
		iSelectedGray++;
		break;
	case EKeyLeftArrow:
		if (MaxLevel()==KMaxGray16Level)
			iSelectedGray-=KMaxGray16Level/2;
		break;
	case EKeyRightArrow:
		if (MaxLevel()==KMaxGray16Level)
			iSelectedGray+=KMaxGray16Level/2;
		break;
	case EKeyHome:
		iSelectedGray=0;
		break;
	case EKeyEnd:
		iSelectedGray=MaxLevel() - 1;
		break;
		}
	if (iSelectedGray<0 || iSelectedGray>=MaxLevel())
		iSelectedGray=oldSelectedGray;
	if (oldSelectedGray!=iSelectedGray)
		{
		DrawHighlightToGrayNow(oldSelectedGray,EFalse);
		DrawHighlightToGrayNow(iSelectedGray,ETrue);
		ReportEventL(MCoeControlObserver::EEventStateChanged);
		}
	switch (aKeyEvent.iCode)
		{
	case EKeyEnter:
		ReportEventL(MCoeControlObserver::EEventRequestExit);
		break;
	case EKeyEscape:
		ReportEventL(MCoeControlObserver::EEventRequestCancel);
		break;
		}
	return(EKeyWasConsumed);
	}

EXPORT_C TRgb CEikGrayPalette::SelectedGray() const
	{
	TRgb color=TRgb::Gray4(iSelectedGray);
	if (iMaxGrayLevel&EDisplayMode16Gray)
		color=TRgb::Gray16(iSelectedGray);
	else if (iMaxGrayLevel&EDisplayMode16Color)
		color=TRgb::Color16(iSelectedGray);
	return(color);
	}

EXPORT_C void CEikGrayPalette::SetSelectedGray(const TRgb& aColor)
	{
	iSelectedGray=aColor.Gray4();
	if (iMaxGrayLevel&EDisplayMode16Gray)
		iSelectedGray=aColor.Gray16();
	else if (iMaxGrayLevel&EDisplayMode16Color)
		iSelectedGray=aColor.Color16();
	}
