// EIKFPNE.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <eikfpne.h>

#include <e32math.h>
#include <eikpanic.h>
#include <barsread.h>
#include <eikenv.h>
#include <eikedwin.hrh>
#include <eikon.rsg>


TInt TenToThePower(TInt n)// mostly, n small, eg 2, so integer arithmetic more efficient than real
	{
    TInt ret=1;
    while (n--)
        ret*=10;
	return (ret);
	}

// class CEikFloatingPointEditor ////////////////////////////////////////////////////////////

EXPORT_C CEikFloatingPointEditor::CEikFloatingPointEditor()
	{
    iEdwinInternalFlags=ENumericCharacters;
	}

EXPORT_C void CEikFloatingPointEditor::ConstructL(const TReal& aMin,const TReal& aMax,TInt aTextLimit)
	{
	SetMinMax(aMin,aMax);
	CEikEdwin::ConstructL(0,aTextLimit,aTextLimit,1);
	}

EXPORT_C void CEikFloatingPointEditor::PrepareForFocusLossL()
	{
	TBuf<32> des;
	GetText(des);
	TLex lex(des);
	TInt err=lex.Val(iValue);
    TInt resId=0;
    TReal* pReal=NULL;
	//if (err || lex.Remainder().Length())
	if (err==KErrGeneral || err==KErrArgument || lex.Remainder().Length()) // changed by AnnW
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_FAILED_RECOG_NUMBER);
    if (iValue<iMin)
        {
        resId=R_EIK_TBUF_FNUMBER_BELOW_MIN;
        pReal=(&iMin);
        }
    else if (iValue>iMax)
        {
        resId=R_EIK_TBUF_FNUMBER_ABOVE_MAX;
        pReal=(&iMax);
        }
    if (resId)
        {
        TBuf<22> buf;	// changed to 22 by AnnW
        // 22 gives you 15 digit mantissa, 3 digit exponent, ".", "e", and two "-" (one each for mantissa and exponent).
        TRealFormat format(22);
		format.iType|=KAllowThreeDigitExp;
        buf.Num(*pReal,format);
        iEikonEnv->LeaveWithInfoMsg(resId,&buf);
        }
	}

EXPORT_C void CEikFloatingPointEditor::ConstructFromResourceL(TResourceReader& aReader)
	{
	TInt textLimit=aReader.ReadUint16();
	TReal min=aReader.ReadReal64();
	TReal max=aReader.ReadReal64();
	ConstructL(min,max,textLimit);
	}

/*
EXPORT_C TKeyResponse CEikFloatingPointEditor::OfferKeyEventL(TKeyEvent* aKeyEvent,TEventCode aType)
	{
	TInt code=aKeyEvent->iCode;
	if ( (aKeyEvent->iModifiers)&EModCtrl || ! TChar(code).IsPrint()
		|| ( !((aKeyEvent->iModifiers)&EModShift)
			&& ( ('0' <= code && code <= '9') 
				|| code = '.'
				|| code = '-'
				|| code = 'e'
				)
			)
		)
		return CEikEdwin::OfferKeyEventL(aKeyEvent, aType)
	else
		return(EKeyWasNotConsumed);// it would be nice to beep on illegal keypress
	}
*/

EXPORT_C TReal CEikFloatingPointEditor::Value() const
	{
	return iValue;// assumes model already checked for validity
	}

EXPORT_C void CEikFloatingPointEditor::SetValueL(const TReal* aValue)
	{
    if (!aValue)
        {
		SetTextL(NULL);
        return;
        }
	iValue=*aValue;
	// !! Now check for validity?
	TBuf<32> des;
	TRealFormat format(iTextLimit);
	format.iType|=KAllowThreeDigitExp;
	des.Num(iValue,format);
	SetTextL(&des);
	}

EXPORT_C void CEikFloatingPointEditor::SetMinMax(TReal aMin,TReal aMax)
	{
	iMin=aMin;
	iMax=aMax;
	__ASSERT_DEBUG(iMin<=iMax, Panic(EEikPanicInvalidBounds) );
	}

EXPORT_C void CEikFloatingPointEditor::GetMinMax(TReal& aMin, TReal& aMax) const
	{
	aMin=iMin;
	aMax=iMax;
	}

// class CEikFixedPointEditor ///////////////////////////////////////////////////////////////////

EXPORT_C CEikFixedPointEditor::CEikFixedPointEditor()
	{
    iEdwinInternalFlags=ENumericCharacters;
	}

EXPORT_C void CEikFixedPointEditor::ConstructL(TInt aMin,TInt aMax)
	{
	SetMinMax(aMin,aMax);
	iTextLimit=RequiredNumberOfCharacters();
	CEikEdwin::ConstructL(0,iTextLimit,iTextLimit,1);
	}

EXPORT_C void CEikFixedPointEditor::ConstructFromResourceL(TResourceReader& aReader)
	{
	iDecimalPlaces=aReader.ReadUint16();
	iMin=aReader.ReadInt32();
	iMax=aReader.ReadInt32();
	__ASSERT_DEBUG(iMin<=iMax, Panic(EEikPanicInvalidBounds) );
	iTextLimit=RequiredNumberOfCharacters();
	CalculateWidth(iTextLimit);
	iNumberOfLines=1;
    BaseConstructL();
	}

TInt CEikFixedPointEditor::RequiredNumberOfCharacters() const
	{
	TInt absMax=(iMax >= -iMin) ? iMax : -iMin;
	TInt numberOfCharacters=0;
	while (absMax!=0)
		{
		++numberOfCharacters;
		absMax/=10;
		}
	if (numberOfCharacters<iDecimalPlaces+1)
		numberOfCharacters=iDecimalPlaces+1;// if bounds ensure leading digits will be zero, still need enough characters
	++numberOfCharacters;// one character for the decimal point
	if (iMin<0)
		++numberOfCharacters;// one character for the minus sign
	return numberOfCharacters;
	}

EXPORT_C void CEikFixedPointEditor::PrepareForFocusLossL()
	{
	TBuf<32> string;
	GetText(string);
	TLex lex(string);
	TReal real;
	TInt err=lex.Val(real);
	if (err==KErrGeneral || err==KErrArgument || lex.Remainder().Length())
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_FAILED_RECOG_NUMBER);
	real*=TenToThePower(iDecimalPlaces);
	real+=(real>0)?0.5:(-0.5);
	Math::Int((TInt32&)iValue, real);
    TInt resId=0;
    TInt limit=0;
    if (iValue<iMin)
		{
        resId=R_EIK_TBUF_FNUMBER_BELOW_MIN;
        limit=iMin;
		}
    else if (iValue>iMax)
		{
        resId=R_EIK_TBUF_FNUMBER_ABOVE_MAX;
        limit=iMax;
		}
    if (resId)
        {
	    real=(TReal)(limit) / TenToThePower(iDecimalPlaces);
        TBuf<16> buf; // 16 chars - actually need 12 max : 1 for d.p., 1 for minus sign, 10 for TInt
        TRealFormat format(16,iDecimalPlaces);
		format.iType|=KDoNotUseTriads;
        buf.Num(real,format);
        iEikonEnv->LeaveWithInfoMsg(resId,&buf);
        }
	}

EXPORT_C TInt CEikFixedPointEditor::Value() const
	{
	return iValue;
	}

EXPORT_C void CEikFixedPointEditor::SetValueL(const TInt* aValue)
	{
    if (!aValue)
        {
		SetTextL(NULL);
        return;
        }
	iValue=*aValue;
	//
	TRealFormat format(iTextLimit,iDecimalPlaces);
	format.iType|=KDoNotUseTriads;
	//
	TReal real=(TReal)iValue;
	real/=TenToThePower(iDecimalPlaces);
	TBuf<32> string;
	string.Num(real,format);
	SetTextL(&string);
	}

EXPORT_C void CEikFixedPointEditor::SetMinMax(TInt aMin, TInt aMax)
	{
	iMin=aMin;
	iMax=aMax;
	__ASSERT_DEBUG(iMin<=iMax, Panic(EEikPanicInvalidBounds) );
	}

EXPORT_C void CEikFixedPointEditor::GetMinMax(TInt& aMin, TInt& aMax) const
	{
	aMin=iMin;
	aMax=iMax;
	}

EXPORT_C void CEikFixedPointEditor::SetDecimalPlaces(TInt aDecimalPlaces)
	{
	iDecimalPlaces=aDecimalPlaces;
	}

EXPORT_C TInt CEikFixedPointEditor::DecimalPlaces() const
	{
	return iDecimalPlaces;
	}


// class CEikTwipsEditor ////////////////////////////////////////////////////////////////////////

const TInt KTwipsStringDecimalPlaces=2;
const TInt KTwipsStringInfoMessageDecimalPlaces=3;
const TInt KMetricIncInTwips=3;				// = Int((0.005*1440/2.54)+0.5)
const TInt KImperialIncInTwips=7;			// = Int((0.005*1440)+0.5)

EXPORT_C CEikTwipsEditor::CEikTwipsEditor()
	{
    iEdwinInternalFlags=ENumericCharacters;
	}

EXPORT_C void CEikTwipsEditor::ConstructL(TInt aMin,TInt aMax)
	{
	SetMinMax(aMin,aMax);
	iTextLimit=RequiredNumberOfCharacters();
	CEikEdwin::ConstructL(0,iTextLimit,iTextLimit,1);
	}

EXPORT_C void CEikTwipsEditor::ConstructFromResourceL(TResourceReader& aReader)
	{
	iMin=aReader.ReadInt32();
	iMax=aReader.ReadInt32();
	//
	TLocale locale;
	SetUnits(locale.UnitsDistanceShort());
	//
	iTextLimit=RequiredNumberOfCharacters();
	CalculateWidth(iTextLimit);
	iNumberOfLines=1;
    BaseConstructL();
	}

TInt CEikTwipsEditor::RequiredNumberOfCharacters() const
	{
	const TInt absMax=(iMax >= -iMin) ? iMax : -iMin;
	TInt maxCm=(absMax*254)/(100*1440);// max characters is when it's cm
	TInt numberOfCharacters=0;
	do // ensure at least one digit before decimal point
		{
		++numberOfCharacters;
		maxCm/=10;
		}
	while (maxCm!=0);
	numberOfCharacters+=KTwipsStringDecimalPlaces+1;// one for decimal point
	if (iMin<0)
		++numberOfCharacters;// one character for the minus sign
	return numberOfCharacters;
	}

EXPORT_C void CEikTwipsEditor::PrepareForFocusLossL()
	{
	TBuf<16> string;
	GetText(string);
   // if (!string.Length()/* && iFlags&EEikControlAllowIndeterminateState*/)
   //     return;
	TBool valid=Twips::StringToTwips(string, iUnits, iValue);
	if (!valid)
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_FAILED_RECOG_NUMBER);
	TInt resId=0;
    TInt limit=0;
	if (iValue<iMin)
		{
		resId=R_EIK_TBUF_FNUMBER_BELOW_MIN;
		limit=iMin;
		}
	else if (iValue>iMax)
		{
		resId=R_EIK_TBUF_FNUMBER_ABOVE_MAX;
		limit=iMax;
		}
	if (resId)
		{
		TBuf<16> buf;
		Twips::TwipsToString(limit,iUnits,KTwipsStringInfoMessageDecimalPlaces,buf);
		iEikonEnv->LeaveWithInfoMsg(resId,&buf);
		}
	}

EXPORT_C TInt CEikTwipsEditor::Value() const
	{
	return iValue;
	}

EXPORT_C void CEikTwipsEditor::SetValueL(const TInt* aValue)
	{
    if (!aValue)
        {
		SetTextL(NULL);
        return;
        }
	iValue=*aValue;
	//
	TBuf<32> buf;
	Twips::TwipsToString(iValue,iUnits,KTwipsStringDecimalPlaces,buf);
	

	// convert back to check within limits
	TInt temp;
	Twips::StringToTwips(buf,iUnits,temp);
	if (temp<iMin || temp>iMax)
		{
		temp=(temp<iMin ? iMin : iMax);
		TInt incInTwips=(iUnits==EUnitsMetric ? KMetricIncInTwips : KImperialIncInTwips);
		temp=(temp==iMin ? temp+incInTwips : temp-incInTwips);
		iValue=temp;
		Twips::TwipsToString(iValue,iUnits,KTwipsStringDecimalPlaces,buf);
		}

	SetTextL(&buf);
	}

EXPORT_C void CEikTwipsEditor::SetMinMax(TInt aMin, TInt aMax)
	{
	iMin=aMin;
	iMax=aMax;
	}

EXPORT_C void CEikTwipsEditor::GetMinMax(TInt& aMin, TInt& aMax) const
	{
	aMin=iMin;
	aMax=iMax;
	}

EXPORT_C void CEikTwipsEditor::SetUnits(TUnitsFormat aUnitsFormat)
	{
	iUnits=aUnitsFormat;
	// !! if trailer were set here, we would be safer against units changing during lifetime of editor
	}

EXPORT_C TUnitsFormat CEikTwipsEditor::Units()
	{
	return iUnits;
	}

// class Twips /////////////////////////////////////////////////////////////////////////////////

EXPORT_C TBool Twips::StringToTwips(const TDes& aDes, TInt& aTwips)
	{
	TLocale locale;
	return StringToTwips(aDes, locale.UnitsDistanceShort(), aTwips);
	}

EXPORT_C void Twips::TwipsToString(TInt aTwips, TInt aDecimalPlaces, TDes& aDes)
	{
	TLocale locale;
	TwipsToString(aTwips, locale.UnitsDistanceShort(), aDecimalPlaces, aDes);
	}

EXPORT_C TBool Twips::StringToTwips(const TDes& aDes, TUnitsFormat aUnitsFormat, TInt& aTwips)
	{
	TLex lex(aDes);
	TReal real;
	TInt err=lex.Val(real);
	if (err || lex.Remainder().Length() )
		return EFalse;
	real*=1440.0;
	if (aUnitsFormat==EUnitsMetric)
		real/=2.54;
	Math::Int((TInt32&)aTwips, real+0.5);
	return ETrue;
	}

EXPORT_C void Twips::TwipsToString(TInt aTwips, TUnitsFormat aUnitsFormat, TInt aDecimalPlaces, TDes& aDes)
	{
	TRealFormat format(16,aDecimalPlaces);
	format.iType|=KDoNotUseTriads;
	//
	TReal multiplier=1.0/1440.0;// inches per twip
	if (aUnitsFormat==EUnitsMetric)
		multiplier*=2.54;// cm per inch
	//
	aDes.Num((TReal)aTwips * multiplier, format);
	}
