// EIKCONSW.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//
	  
#include <e32base.h>
#include <gdi.h>
#include <coecntrl.h>
#include <coemain.h>
#include <eikconso.h>	// #include's eiksbfrm.h
#include <eikenv.h>
#include <barsread.h>
#include <eikpriv.rsg>


void cutmax(TInt &x,TInt max);
void cutmin(TInt &x,TInt min);


#define WHITE 15
#define BLACK 0

///////////////////////////////////////////////////////////////////////////////////////////////////////
// UpdateScrollBarsL()
// ===================
// Updates the thumb positions etc. on the scrollbars.
// Should be called whenever the datasize, visiblesize or position on the scrollbars have changed.
// RETURNS ETrue IF ANY SCROLLBARS (DIS)APPEARED
///////////////////////////////////////////////////////////////////////////////////////////////////////

EXPORT_C TBool CEikConsoleControl::UpdateScrollbarsL(const TSize &aDataSize,const TSize& aVisibleSize,TPoint aPos)
	{
	// complete available area in characters
	TSize viewInChars( iSize.iWidth / iCharSize.iWidth, iSize.iHeight / iCharSize.iHeight );
	
	// remember for next time
	iLastThumbPos = aPos;
	TEikScrollBarModel vModel;
	TEikScrollBarModel hModel;
	if (iVBarVisibility!=CEikScrollBarFrame::EOff) 
		{
		// Vertical
		vModel.iScrollSpan=aDataSize.iHeight;
		if ( viewInChars.iHeight > aVisibleSize.iHeight )
			vModel.iThumbSpan=aVisibleSize.iHeight;
		else
			vModel.iThumbSpan=viewInChars.iHeight;
		vModel.iThumbPosition=aPos.iY;
		}
	if (iHBarVisibility!=CEikScrollBarFrame::EOff) 
		{
		// Horizontal
		hModel.iScrollSpan=aDataSize.iWidth;
		if ( viewInChars.iWidth > aVisibleSize.iWidth )
			hModel.iThumbSpan=aVisibleSize.iWidth;
		else
			hModel.iThumbSpan=viewInChars.iWidth;
		hModel.iThumbPosition=aPos.iX;
		}
	TRect fullRect(iSize);
	TRect clientRect(iViewInPixels);
	TEikScrollBarFrameLayout layout;
	CreateScrollBarFrameLayout(layout);
	if (iSBFrame->TileL(&hModel,&vModel,clientRect,fullRect,layout))
		{
		// something happened, so redetermine the available pixels...
		iViewInPixels=clientRect.Size();
		// the visible characters...
//	zoe	
		iViewInChars = TSize( iViewInPixels.iWidth / iCharSize.iWidth, iViewInPixels.iHeight / iCharSize.iHeight );
		if (iConsole)
			{
			cutmax(iViewInChars.iWidth,iConsole->ScreenSize().iWidth);
			cutmax(iViewInChars.iHeight,iConsole->ScreenSize().iHeight);
			}
		// and clear what's outside the new scope...
		TPoint br(iViewInChars.iWidth*iCharSize.iWidth, iViewInChars.iHeight*iCharSize.iHeight);
		ClearPixels(TRect(br.iX,0,iViewInPixels.iWidth,br.iY),WHITE);
		ClearPixels(TRect(0,br.iY,iViewInPixels.iWidth,iViewInPixels.iHeight),WHITE);
		// and inform caller that the area has changed...
		return ETrue;
		}
	return EFalse;
	}

void CEikConsoleControl::CreateScrollBarFrameLayout(TEikScrollBarFrameLayout& aLayout) const
	{
	// all margins default to 0
	aLayout.iTilingMode=TEikScrollBarFrameLayout::EInclusiveRectConstant;
	aLayout.iClientAreaGranularity=iCharSize;
	}


EXPORT_C void CEikConsoleControl::UpdateArea()
	{
	// determine how many characters will fit and how many pixels we thus ACTUALLY need
//zoe
	iViewInChars = TSize( iViewInPixels.iWidth / iCharSize.iWidth, iViewInPixels.iHeight / iCharSize.iHeight );
	if (iConsole)
		{
		cutmax(iViewInChars.iWidth,iConsole->ScreenSize().iWidth);
		cutmax(iViewInChars.iHeight,iConsole->ScreenSize().iHeight);
		}
	// clear the area and redraw
	ClearPixels(iViewInPixels,WHITE);
	if (iConsole)
		iConsole->Redraw(PixelsToChars(TRect(iViewInPixels)));
	}

///////////////////////////////////////////////////////////////////////////////////////////////////////
// HandleScrollEventL()
// ====================
// Called when someone "touches the scrollbar".
// Note that it calls back the owner (a CEikConsoleScreen) to do any real action
// (specifically, it calls MoveTopLeft(), passing it the required move as a vector)
///////////////////////////////////////////////////////////////////////////////////////////////////////
EXPORT_C void CEikConsoleControl::HandleScrollEventL(CEikScrollBar* aScrollBar,TEikScrollEvent aEventType)
	{
	TInt newThumbPos = aScrollBar->ThumbPosition();
	TInt pageSize = aScrollBar->Model()->iThumbSpan;
	const TInt horizontalNudgeFactor = 1;
	switch (aEventType & KEikScrollEventBarMask)
		{ 
		case KEikScrollEventFromHBar:
			switch (aEventType)
				{
                default:
                    break;
				case EEikScrollLeft:
					newThumbPos -= horizontalNudgeFactor;
					break;
				case EEikScrollRight:
					newThumbPos += horizontalNudgeFactor;
					break;
				case EEikScrollPageLeft:
					newThumbPos -= pageSize;
					break;
				case EEikScrollPageRight:
					newThumbPos += pageSize;
					break;
				case EEikScrollThumbDragVert:
				case EEikScrollThumbReleaseVert:
					// in the case of drag events, the scrollbar automatically updates its thumb pos...
					break;
				}
			iConsole->MoveTopLeft(TPoint(newThumbPos - iLastThumbPos.iX,0));
			if (aEventType != EEikScrollThumbDragHoriz)
				aScrollBar->SetModelThumbPosition(newThumbPos);
			break;
		case KEikScrollEventFromVBar:
			switch (aEventType)
				{
                default:
                    break;
				case EEikScrollUp:
					--newThumbPos;
					break;
				case EEikScrollDown:
					++newThumbPos;
					break;
				case EEikScrollPageUp:
					newThumbPos -= ((pageSize < 2)? 1 : pageSize - 1);
					break;
				case EEikScrollPageDown:
					newThumbPos += ((pageSize < 2)? 1 : pageSize - 1);
					break;
				case EEikScrollThumbDragVert:
				case EEikScrollThumbReleaseVert:
					// in the case of drag events, the scrollbar automatically updates its thumb pos...
					break;
				}
			iConsole->MoveTopLeft(TPoint(0,newThumbPos - iLastThumbPos.iY));
			if (aEventType != EEikScrollThumbDragVert)
				aScrollBar->SetModelThumbPosition(newThumbPos);
			break;
		}
	}


///////////////////////////////////////////////////////////////////////////////////////////////////////
// SetScrollBarVisibility
// ======================
// Changes which scroll bars are visible. Returns EFalse if nothing changed.
///////////////////////////////////////////////////////////////////////////////////////////////////////
EXPORT_C TInt CEikConsoleControl::SetScrollBarVisibilityL(CEikScrollBarFrame::TScrollBarVisibility aHBarVisibility, CEikScrollBarFrame::TScrollBarVisibility aVBarVisibility)
	{
	if ((aHBarVisibility==iHBarVisibility)&&(aVBarVisibility==iVBarVisibility))
		return EFalse;
	iHBarVisibility=aHBarVisibility;
	iVBarVisibility=aVBarVisibility;
	iSBFrame->SetScrollBarVisibilityL(iHBarVisibility, iVBarVisibility);
	return ETrue;
	}


///////////////////////////////////////////////////////////////////////////////////////////////////////
// SizeChangedL
// ==========
///////////////////////////////////////////////////////////////////////////////////////////////////////
EXPORT_C void CEikConsoleControl::SizeChangedL()
	{
	iViewInPixels=Size(); // new area
	if (iConsole && iSBFrame)
		{
		iConsole->UpdateScrollBars();
		UpdateArea();
		}
	}

EXPORT_C void CEikConsoleControl::FocusChanged(TDrawNow aDrawNow)
	{
	if (aDrawNow==ENoDrawNow)
		return;
	if (IsFocused())
		iConsole->DrawCursor();
	else
		iConsole->HideCursor();
	}

EXPORT_C TInt CEikConsoleControl::CountComponentControls() const
	{
	return (iSBFrame) ? iSBFrame->CountComponentControls() : NULL;
	}

EXPORT_C CCoeControl* CEikConsoleControl::ComponentControl(TInt aIndex) const
	{
	return iSBFrame->ComponentControl(aIndex);
	}

///////////////////////////////////////////////////////////////////////////////////////////////////////
// VisibleSize()
// =============
// Simply returns the visible size in characters
///////////////////////////////////////////////////////////////////////////////////////////////////////
EXPORT_C TSize CEikConsoleControl::VisibleSize() const
	{
	return iViewInChars;
	}

///////////////////////////////////////////////////////////////////////////////////////////////////////
// ConstructL
// ==========
// Construct and activate a CEikConsoleControl (claiming the specified part of the physical screen)
///////////////////////////////////////////////////////////////////////////////////////////////////////
EXPORT_C void CEikConsoleControl::ConstructL(TInt aFlags)
	{
    // Init screen. Use RBackedUpWindow instead of RWindow if aFlags & CEikConsoleScreen::EUseBackedUpWindow
	if (aFlags&CEikConsoleScreen::EUseBackedUpWindow)
		CreateBackedUpWindowL((RWindowTreeNode&)iCoeEnv->RootWin(), EGray4);
	else
		CreateWindowL();

	SetExtentToWholeScreenL();

	// Create scrollbars
	iSBFrame=new(ELeave) CEikScrollBarFrame(this, this);
	iSBFrame->SetScrollBarVisibilityL(iHBarVisibility,iVBarVisibility);

	InitFontSpecL();
	SetFontL(iFontSpec,NULL);

	// activate
	ActivateL(); 
	}

EXPORT_C void CEikConsoleControl::ConstructL(TPoint aTopLeft,const TSize &aSize,TInt aFlags,TEikConsWinUnits aUnit)
	{
    // Init screen. Use RBackedUpWindow instead of RWindow if aFlags & CEikConsoleScreen::EUseBackedUpWindow
	if (aFlags&CEikConsoleScreen::EUseBackedUpWindow)
		CreateBackedUpWindowL((RWindowTreeNode&)iCoeEnv->RootWin(), EGray4);
	else
		CreateWindowL();

	// Create scrollbars
	iSBFrame=new(ELeave) CEikScrollBarFrame(this, this);
	iSBFrame->SetScrollBarVisibilityL(iHBarVisibility,iVBarVisibility);

	InitFontSpecL();
	
	if (aUnit==EEikConsWinInChars)
		{
		CFbsFont *font=iEikonEnv->CreateScreenFontL(iFontSpec);
		iCurrentFont=font;
		iCharSize.iWidth=font->MaxNormalCharWidthInPixels();
		iCharSize.iHeight=font->HeightInPixels();
		SetExtentL(TPoint(aTopLeft.iX*iCharSize.iWidth,aTopLeft.iY*iCharSize.iHeight),
			TSize(aSize.iWidth*iCharSize.iWidth,aSize.iHeight*iCharSize.iHeight));
		SetFontL(iFontSpec,font);
		}
	else
		{
		SetExtentL(aTopLeft,aSize);
		SetFontL(iFontSpec,NULL);
		}
	// activate
	ActivateL(); 
	}

void CEikConsoleControl::InitFontSpecL()
	{
	TBuf<KMaxTypefaceNameLength> typeface;
	CEikonEnv* self=CEikonEnv::Static();
	self->ReadResource(typeface,R_EIK_DEFAULT_CONSOLE_FONTSPEC_TYPEFACE);
	iFontSpec.iTypeface.iName=typeface;

	TResourceReader reader;
	self->CreateResourceReaderLC(reader,R_EIK_DEFAULT_CONSOLE_FONTSPEC_HEIGHT);
	iFontSpec.iHeight=reader.ReadInt16();
	CleanupStack::PopAndDestroy(); // reader

#if defined(_UNICODE)
	iFontSpec.iTypeface.SetIsProportional(EFalse);
#endif
	iFontUnderline=EUnderlineOff;				
	iFontSpec.iFontStyle.SetPosture(EPostureUpright);				
	iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightNormal);
	}

///////////////////////////////////////////////////////////////////////////////////////////////////////
// SetRedrawer
// ===========
// Define aConsoleScreen as the object responsible for redrawing
///////////////////////////////////////////////////////////////////////////////////////////////////////
EXPORT_C void CEikConsoleControl::SetRedrawer(CEikConsoleScreen *aConsoleScreen)
	{
	iConsole=aConsoleScreen;
	}

///////////////////////////////////////////////////////////////////////////////////////////////////////
// Constructor and Destructor
///////////////////////////////////////////////////////////////////////////////////////////////////////
EXPORT_C CEikConsoleControl::CEikConsoleControl()
	{
	// *** init color
	iBackGray16=WHITE;	
	iPenGray16=BLACK;  

	// *** init scrollbar settings and font (however, 0-values are free in construction)
	// iHBarPresent=FALSE;
	// iVBarPresent=FALSE;
	// iLastThumbPos = TPoint(0,0);
	// iCurrentFont=NULL;

	// *** init cursor
	iCursorHeightPercentage=20;
	iTextCursor.iType	= TTextCursor::ETypeRectangle;
	iTextCursor.iFlags	= 0;
	iTextCursor.iColor=KRgbWhite;	
	iLastAtt=iLastFontFlags=(ATT_MAXVALUE+1);
	}

EXPORT_C CEikConsoleControl::~CEikConsoleControl()
	{
	iEikonEnv->ReleaseScreenFont(CONST_CAST(CFont*,iCurrentFont));
	delete(iSBFrame);
	}


///////////////////////////////////////////////////////////////////////////////////////////////////////
// NextFontL
// =========
// Utility function: unload current font (if any) and load new font (specified elsewhere in iFontSpec)
///////////////////////////////////////////////////////////////////////////////////////////////////////
void CEikConsoleControl::NextFontL()
	{
    CFbsFont* font=iEikonEnv->CreateScreenFontL(iFontSpec);
    iEikonEnv->ReleaseScreenFont(CONST_CAST(CFont*,iCurrentFont)); // note that this only happens if the previous line succeeds!
    iCurrentFont=font;
	}

///////////////////////////////////////////////////////////////////////////////////////////////////////
// SetFontL
// ========
// Change the font
///////////////////////////////////////////////////////////////////////////////////////////////////////
EXPORT_C void CEikConsoleControl::SetFontL(const TFontSpec& aFontSpec,const CFbsFont *aFont)
	{
	iFontSpec=aFontSpec;
	iFontHeight=(TUint16)iFontSpec.iHeight;
	if (aFont==NULL)
		NextFontL();

	iCharSize = TSize( iCurrentFont->MaxNormalCharWidthInPixels(),iCurrentFont->HeightInPixels() );
	
	SetCursorHeight(iCursorHeightPercentage);

	// Determine font flags for new font
	iFontIsProportional=iCurrentFont->FontSpecInTwips().iTypeface.IsProportional();
	iLastFontFlags = 0;
	if (iFontUnderline!=EUnderlineOff)
        iLastFontFlags|=ATT_UNDERLINE;
	if (iFontSpec.iFontStyle.Posture()!=EPostureUpright)
        iLastFontFlags|=ATT_ITALIC;
	if (iFontSpec.iFontStyle.StrokeWeight()!=EStrokeWeightNormal)
        iLastFontFlags|=ATT_BOLD;

	UpdateArea();
	}

////////////////////////////////////////////////////////////////////////////////////////
//
//  Utility functions: convert between character coordinates to pixel coordinates
//
////////////////////////////////////////////////////////////////////////////////////////

TPoint CEikConsoleControl::CharsToPixels(TPoint aPos)
	{
	return TPoint( iCharSize.iWidth * aPos.iX, iCharSize.iHeight * aPos.iY ); 
	}

TRect CEikConsoleControl::CharsToPixels(const TRect &aRect)
	{
	return TRect(CharsToPixels(aRect.iTl),CharsToPixels(aRect.iBr));
	}

TRect CEikConsoleControl::PixelsToChars(const TRect &aRect) 
	{
	TRect r = aRect;
	r.Normalize();
	r.iTl.iX /= iCharSize.iWidth;
	r.iBr.iX /= iCharSize.iWidth;
	r.iBr.iX ++;
	r.iTl.iY /= iCharSize.iHeight;
	r.iBr.iY /= iCharSize.iHeight;
	r.iBr.iY ++;
	return r;
	}

////////////////////////////////////////////////////////////////////////////////////////
//
//  Cursor stuff
//
////////////////////////////////////////////////////////////////////////////////////////

EXPORT_C void CEikConsoleControl::DrawCursor(TPoint aPosition)
// Show cursor at character position
	{
	//iEikonEnv->RootWin().SetTextCursor(*DrawableWindow(),CharsToPixels(aPosition),iTextCursor);
	iEikonEnv->DrawCursor(this, CharsToPixels(aPosition), iTextCursor.iWidth, iTextCursor.iAscent, iTextCursor.iHeight);
	}

EXPORT_C void CEikConsoleControl::HideCursor(void)
// Hide cursor 
	{
	//iEikonEnv->RootWin().CancelTextCursor(); 
	iEikonEnv->HideCursor(this);
	}


EXPORT_C void CEikConsoleControl::SetCursorHeight(TUint aPercentage)
// Set new cursor height (specified as percentage of font height)
// Should also be called whenever iCharSize changes!
// Change will not take effect until the next call to DrawCursor!
	{
	iCursorHeightPercentage = aPercentage % 101; 
	iTextCursor.iHeight = ( 99 + (iCharSize.iHeight * iCursorHeightPercentage) ) / 100;
	iTextCursor.iAscent = iTextCursor.iHeight-iCharSize.iHeight; 
	iTextCursor.iWidth  = iCharSize.iWidth;
	}

////////////////////////////////////////////////////////////////////////////////////////
//
//  Draw - defers the real work to the owner (a CEikConsoleScreen)
//
////////////////////////////////////////////////////////////////////////////////////////

EXPORT_C void CEikConsoleControl::Draw(const TRect& aRect) const	
	{
	if (iConsole) // if there's no owner, we do nothing
		{
		M().iRedrawing=1;
		TPoint br(iViewInChars.iWidth*iCharSize.iWidth,iViewInChars.iHeight*iCharSize.iHeight);
		ClearPixels(TRect(br.iX,0,iViewInPixels.iWidth,br.iY),WHITE);
		ClearPixels(TRect(0,br.iY,iViewInPixels.iWidth,iViewInPixels.iHeight),WHITE);
		iConsole->Redraw(M().PixelsToChars(aRect)); // Redraw all chars in the rectangle
		M().iRedrawing=0;
		}
	}

////////////////////////////////////////////////////////////////////////////////////////
//
//  Set up GC based for given attribute
//
////////////////////////////////////////////////////////////////////////////////////////

void CEikConsoleControl::InterpretColorBits(TUint aCharacterAttributes)
// Set iPenGrey16 and iBackGrey16 based on character attribute aCharacterAttributes
	{
	if (aCharacterAttributes & ATT_COLORMASK) // is color 
		{
		iPenGray16=(aCharacterAttributes & 0x0F);
		if ( (iBackGray16=((aCharacterAttributes & 0x70)>>4)*2+1)==1 ) 
			iBackGray16=0;		
		}
	else if ( aCharacterAttributes & ATT_INVERSE ) 
		{
		iBackGray16=BLACK;
		iPenGray16=WHITE; 
		}
	else
		{
		iBackGray16=WHITE;
		iPenGray16=BLACK;
		}
	}

void CEikConsoleControl::InterpretAttribute(TUint aCharacterAttributes)
    {
	if (iLastAtt!=aCharacterAttributes)
		{
		iLastAtt=aCharacterAttributes;
		InterpretColorBits(aCharacterAttributes);
		TUint fontFlags = (aCharacterAttributes & ATT_COLORMASK) ? (0) : (aCharacterAttributes & ATT_IGNORE_INVERSE & ATT_IGNORE_RIGHTLEFT);
		if (iLastFontFlags!=fontFlags)
			{
			iLastFontFlags=fontFlags;
			iFontUnderline=((fontFlags & ATT_UNDERLINE)? EUnderlineOn: EUnderlineOff);
    		iFontSpec.iFontStyle.SetPosture(((fontFlags & ATT_ITALIC)? EPostureItalic: EPostureUpright));
			iFontSpec.iFontStyle.SetStrokeWeight(((fontFlags & ATT_BOLD)? EStrokeWeightBold: EStrokeWeightNormal));
			if (fontFlags & ATT_DOUBLEMASK)
				{ // double aVisiblePixels
				if ( (fontFlags & ATT_DOUBLEMASK) == ATT_DOUBLEWIDTH )
					{ // double width 
					iFontSpec.iHeight = iFontHeight;
					if ( iFontSpec.iTypeface.iName.Compare(_L("Monospaced"))==0 )
						iFontSpec.iTypeface.iName=_L("MONODOUBLE"); 			//@@@
					}
				else
					{ // double height
					iFontSpec.iHeight = (TUint16)(iFontHeight*2);
					if ( iFontSpec.iTypeface.iName.Compare(_L("MONODOUBLE"))==0 )
						iFontSpec.iTypeface.iName=_L("Monospaced"); 			//@@@
					}
				}
			else 
				{ // normal aVisiblePixels
				iFontSpec.iHeight = iFontHeight;
				if ( iFontSpec.iTypeface.iName.Compare(_L("MONODOUBLE"))==0 )
					iFontSpec.iTypeface.iName=_L("Monospaced"); 			//@@@
				} 
			TRAPD(err,NextFontL());	// ignore errors. If there is a problem, we'll use the one that was loaded
			}
		}
    }

////////////////////////////////////////////////////////////////////////////////////////
//
//  Basic Graphic services
//  ======================
//	NOTE: if iRedrawing, then a redraw is going on, 
//  i.e. no need to (de)activate gc's or (in)validate rectangles
//
////////////////////////////////////////////////////////////////////////////////////////

EXPORT_C void CEikConsoleControl::InvertChars(const TRect &anArea)
// invert a rectangle of characters
	{
	if (!iRedrawing) 
		ActivateGc();
	CWindowGc& gc=SystemGc();
	gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	gc.SetBrushColor(KRgbWhite);
	gc.SetDrawMode(CGraphicsContext::EDrawModeXOR);
	gc.SetPenStyle(CGraphicsContext::ENullPen);
	gc.DrawRect(CharsToPixels(anArea));
	gc.SetDrawMode(CGraphicsContext::EDrawModePEN);
	gc.SetPenStyle(CGraphicsContext::ESolidPen);
	gc.SetBrushStyle(CGraphicsContext::ENullBrush);
	if (!iRedrawing) 
		DeactivateGc();
	}

EXPORT_C void CEikConsoleControl::ScrollChars(const TRect &anArea,const TPoint &aVector)
// scroll a rectangle of characters by a given vector (character coordinates)
	{
	const TRect areaInPixels=CharsToPixels(anArea);
	Window().Scroll(areaInPixels,CharsToPixels(aVector),areaInPixels);
	}

void CEikConsoleControl::ClearPixels(const TRect &anArea,TUint aGray16) const
	{
	if (!iRedrawing)
		ActivateGc();
	CWindowGc& gc=SystemGc();
	gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	gc.SetBrushColor(TRgb::Gray16(aGray16));
	gc.SetPenStyle(CGraphicsContext::ENullPen);
	gc.DrawRect(anArea);
	gc.SetPenStyle(CGraphicsContext::ESolidPen);
	gc.SetBrushStyle(CGraphicsContext::ENullBrush);
	if (!iRedrawing)
		DeactivateGc();
	}

EXPORT_C void CEikConsoleControl::ClearChars(const TRect &anArea,TUint aCharacterAttributes) 
// Clears a rectangle of characters to the current background color
	{
	TRect theArea=CharsToPixels(anArea);
    InterpretColorBits(aCharacterAttributes); 
	ClearPixels(theArea,iBackGray16);
	}

EXPORT_C void CEikConsoleControl::DrawChars(const TDesC &aString,const TPoint &aPosition,TUint aCharacterAttributes)
// Draw characters at given position using given attribute
	{
	InterpretAttribute(aCharacterAttributes);
	TPoint pos = CharsToPixels(aPosition);
	TInt topMargin 	= iCurrentFont->AscentInPixels();
	TInt isDouble = ( !(aCharacterAttributes & ATT_COLORMASK) && (aCharacterAttributes & ATT_DOUBLEMASK) );
	TRect charArea = TRect(pos,iCharSize);

	if (!iRedrawing)
        ActivateGc();
	
    CWindowGc& gc=SystemGc();
	gc.UseFont(iCurrentFont);
	gc.SetPenColor(TRgb::Gray16(iPenGray16));
	gc.SetBrushColor(TRgb::Gray16(iBackGray16));
	gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
    gc.SetUnderlineStyle(iFontUnderline);

	TInt currentFont_width = iCurrentFont->MaxNormalCharWidthInPixels(); 
	if (isDouble || iFontIsProportional || currentFont_width!=iCharSize.iWidth )
		{
		TInt leftMargin = 0;
		
		if (isDouble)
			{
		if (aCharacterAttributes & ATT_RIGHTMASK) 
			leftMargin -= iCharSize.iWidth;
			if ((aCharacterAttributes & ATT_DOUBLEMASK) == ATT_DOUBLEBOTTOM) 
				topMargin -= iCharSize.iHeight;
			}
		
		for ( TInt i=0;i<aString.Length();i++ )
			{
			gc.DrawText(aString.Mid(i,1),charArea,topMargin,CGraphicsContext::ELeft,leftMargin);
			charArea.Move(iCharSize.iWidth,0);
		if (isDouble)
			leftMargin = - iCharSize.iWidth - leftMargin;
			}
		}
	else
		{
		charArea.iBr.iX += (iCharSize.iWidth*(aString.Length()-1));
		gc.DrawText(aString,charArea,topMargin);
		}
										   
	if (!iRedrawing)
        DeactivateGc();
	}

// Reserved from CCoeControl

EXPORT_C void CEikConsoleControl::Reserved_1()
	{
	}

EXPORT_C void CEikConsoleControl::Reserved_2()
	{
	}

