// TOPBUT1.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <eikenv.h>
#include <coecntrl.h>
#include <eikappui.h>
#include <e32keys.h>
#include <eikdef.h>
#include <eikbordr.h>
#include <eikopbut.h>
#include <eikapp.h>
#include <eikdoc.h>
#include <eikcmds.hrh>
#include <s32std.h>
#include <eikon.rsg>

#ifdef _UNICODE
#define KUidOpButApp KUidOpButApp16
#else
#define KUidOpButApp KUidOpButApp8
#endif

const TUid KUidOpButApp8={223};
const TUid KUidOpButApp16={523};

enum TOpButPanic
	{
	EPanicNoButtonSet,
	EPanicUnexpectedCommand
	};

void Panic(TOpButPanic aPanic)
	{
	User::Panic(_L("TEST-OPBUT1"),aPanic);
	}

//
// class COpButModel
//

class COpButModel : public CBase
	{
public:
	TInt32 iValue;
	};

//
// class CTestContainer
//

class CTestContainer : public CCoeControl
    {
public:
    void ConstructL(TInt aValue,const TRect& aRect);
    ~CTestContainer();
	TInt Value() const;
	void SetValue(TInt aValue);
private: // framework
	void SizeChangedL();
    void Draw(const TRect& aRect) const;
    TInt CountComponentControls() const;
    CCoeControl* ComponentControl(TInt aIndex) const;
private: // new functions
    void CreateOptionButtonsL(TInt aValue);
private:
    CEikOptionButton* iOpBut[3];
    TEikButtonCoordinator* iBCoord;
	};

void CTestContainer::ConstructL(TInt aValue,const TRect& aRect)
    {
    CreateWindowL();
    Window().SetShadowDisabled(ETrue);
    EnableDragEvents();
    CreateOptionButtonsL(aValue);
    SetRectL(aRect);
    ActivateL();
    }

void CTestContainer::SetValue(TInt aValue)
	{
	iOpBut[aValue]->SetState(CEikButtonBase::ESet);
	}

CTestContainer::~CTestContainer()
    {
    for (TInt ii=0; ii<3; ii++)
        delete(iOpBut[ii]);
	delete iBCoord;
    }

void CTestContainer::CreateOptionButtonsL(TInt aValue)
    {
	iBCoord=new(ELeave) TEikButtonCoordinator;
    for (TInt ii=0; ii<3; ii++)
        {
		CEikOptionButton* tmp=new(ELeave) CEikOptionButton;
        iOpBut[ii]=tmp;
		tmp->ConstructL();
        tmp->SetContainerWindowL(*this);
		tmp->SetCoordinator(iBCoord);
		tmp->SetState(ii==aValue? CEikButtonBase::ESet: CEikButtonBase::EClear);
        }
	}

TInt CTestContainer::Value() const
	{
	TInt ii=0;
	FOREVER
		{
		if (ii==3)
			Panic(EPanicNoButtonSet);
		if (iOpBut[ii]->State()==CEikButtonBase::ESet)
			break;
		ii++;
		}
	return(ii);
	}

void CTestContainer::SizeChangedL()
    {
    TPoint pos;
	pos.iY=90;
    const TSize size(40,40);
    for (TInt ii=0; ii<3; ii++)
        {
        pos.iX=iSize.iWidth*(7+ii*3)/25;
        iOpBut[ii]->SetExtentL(pos,size);
        }
    }
   
void CTestContainer::Draw(const TRect& aRect) const
    {
    iEikonEnv->FillTexturedRect(aRect);
    }

TInt CTestContainer::CountComponentControls() const
    {
    return(3);
    }

CCoeControl* CTestContainer::ComponentControl(TInt aIndex) const
    {
    return(iOpBut[aIndex]);
    }

//
// COpButDocument - definition
//

class COpButDocument : public CEikDocument
	{
public:
	COpButDocument(CEikApplication& aApp);
	~COpButDocument();
	COpButModel* Model() const { return(iModel); }
	void ConstructL();
private: // from CEikDocument
	CEikAppUi* CreateAppUiL();
private: // from CApaDocument
	void StoreL(CStreamStore& aStore,CStreamDictionary& aStreamDic) const;
	void RestoreL(const CStreamStore& aStore,const CStreamDictionary& aStreamDic);
	TCapability Capability()const; // returns "can draw as glass"
	CPicture* GlassPictureL();
private:
	COpButModel* iModel;
	//
	TInt iGlassScaleFacWidth;
	TInt iGlassScaleFacHeight;
	TMargins iGlassCropInTwips; // cropping relative to original size of picture
	friend class COpButGlassDoor;
	};

//
// COpButGlassDoor
//

#define KOriginalSizeInTwips TSize(1000,1000)

class COpButGlassDoor : public CPicture
	{
public:
	COpButGlassDoor(COpButDocument* adoc);
	void Draw(CGraphicsContext& aGc,const TPoint& aTopLeft,const TRect& aClipRect,MGraphicsDeviceMap* aMap) const;
	inline void ExternalizeL(RWriteStream& ) const {};
	inline void GetOriginalSizeInTwips(TSize& aSize) const { aSize=KOriginalSizeInTwips; }
	TPictureCapability Capability() const; // can scale and crop
	void SetScaleFactor(TInt aScaleFactorWidth,TInt aScaleFactorHeight); // does nothing
	void SetCropInTwips(const TMargins& aMargins); // does nothing
	void GetCropInTwips(TMargins& aMargins) const; // returns no crop
	TInt ScaleFactorWidth() const;
	TInt ScaleFactorHeight() const;
private:
	COpButDocument* iDoc;
	};

	
COpButGlassDoor::COpButGlassDoor(COpButDocument* aDoc)
	:iDoc(aDoc)
	{}

TPictureCapability COpButGlassDoor::Capability() const
	{
	return TPictureCapability(TPictureCapability::EFullyScaleable,ETrue); // supports scaling and cropping
	}

TInt COpButGlassDoor::ScaleFactorWidth() const
	{
	return iDoc->iGlassScaleFacWidth;
	}

TInt COpButGlassDoor::ScaleFactorHeight() const
	{
	return iDoc->iGlassScaleFacHeight;
	}

void COpButGlassDoor::SetScaleFactor(TInt aScaleFactorWidth,TInt aScaleFactorHeight)
	{
	iDoc->iGlassScaleFacWidth = aScaleFactorWidth;
	iDoc->iGlassScaleFacHeight = aScaleFactorHeight;
	}

void COpButGlassDoor::SetCropInTwips(const TMargins& aMargins)
	{
	__ASSERT_ALWAYS(aMargins.iLeft>=0,User::Panic(_L("TOPBUT1"),-1));
	__ASSERT_ALWAYS(aMargins.iRight>=0,User::Panic(_L("TOPBUT1"),-1));
	__ASSERT_ALWAYS(aMargins.iTop>=0,User::Panic(_L("TOPBUT1"),-1));
	__ASSERT_ALWAYS(aMargins.iBottom>=0,User::Panic(_L("TOPBUT1"),-1));
	//
	iDoc->iGlassCropInTwips = aMargins;
	}

void COpButGlassDoor::GetCropInTwips(TMargins& aMargins) const
	{
	aMargins = iDoc->iGlassCropInTwips;
	}

void COpButGlassDoor::Draw(CGraphicsContext& aGc,const TPoint& aTopLeft,const TRect& aClipRect,
						   MGraphicsDeviceMap* aMap)const
	{
	aGc.SetClippingRect(aClipRect);
	//
	TSize sizeInPixels;
	GetSizeInPixels(aMap,sizeInPixels);
	TRect wholeRect(aTopLeft,sizeInPixels);
	//
	// draw a black background
	aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	aGc.SetBrushColor(TRgb(0,0,0));
	aGc.DrawRect(aClipRect);
	//
	// draw a white button either left, middle or right
	aGc.SetBrushColor(TRgb(255,255,255));
	TRect buttonRect(wholeRect);
	if (iDoc->Model()->iValue==0)
		buttonRect.iBr.iX -= 2*(buttonRect.iBr.iX-buttonRect.iTl.iX)/3;
	else if (iDoc->Model()->iValue==1)
		{
		buttonRect.iTl.iX += (buttonRect.iBr.iX-buttonRect.iTl.iX)/3;
		buttonRect.iBr.iX -= (buttonRect.iBr.iX-buttonRect.iTl.iX)/3;
		}
	else
		buttonRect.iTl.iX += 2*(buttonRect.iBr.iX-buttonRect.iTl.iX)/3;
	aGc.DrawEllipse(buttonRect);
	//
	aGc.Reset();
	}

//
// COpButAppUi
//

class COpButAppUi : public CEikAppUi
    {
public:
    ~COpButAppUi();
private: // from CEikAppUi
    void ConstructL();
	void HandleCommandL(TInt aCommand);
	void HandleModelChangeL();
private:
    CTestContainer* iContainer;
	COpButModel* iModel;
    };

void COpButAppUi::HandleCommandL(TInt aCommand)
	{
	if (aCommand!=EEikCmdExit)
		Panic(EPanicUnexpectedCommand);
	TInt value=iContainer->Value();
	if (value!=iModel->iValue)
		{
		iModel->iValue=value;
		SaveL();
		}
	Exit();
	}
	
COpButAppUi::~COpButAppUi()
    {
	if (iDoorObserver)
		iDoorObserver->NotifyExit(MApaEmbeddedDocObserver::EKeepChanges);
    delete(iContainer);
    }
    
void COpButAppUi::ConstructL()
    {
    BaseConstructL(ENoAppResourceFile);
	CreateHotKeyControlL(R_EIK_EXITONLY_HOTKEYS);
    iContainer=new(ELeave) CTestContainer;
	iModel=((COpButDocument*)iDocument)->Model();
    iContainer->ConstructL(iModel->iValue,ClientRect());
    AddToStackL(iContainer);
    }

void COpButAppUi::HandleModelChangeL()
	{
	if (iContainer->Value()==iModel->iValue)
		return;
	iContainer->SetValue(iModel->iValue);
	iContainer->DrawNow();
	}

//
// COpButDocument - implementation
//

COpButDocument::COpButDocument(CEikApplication& aApp)
	:CEikDocument(aApp),
	iGlassScaleFacWidth(1000),
	iGlassScaleFacHeight(1000)
	{}

COpButDocument::~COpButDocument()
	{
	delete iModel;
	}

void COpButDocument::ConstructL()
	{
	iModel=new(ELeave) COpButModel;
	}

void COpButDocument::StoreL(CStreamStore& aStore,CStreamDictionary& aStreamDic) const
	{
	RStoreWriteStream stream;
	TStreamId streamId=stream.CreateLC(aStore);
	stream<< iModel->iValue;
	stream<< iGlassCropInTwips;
	stream.WriteInt32L(iGlassScaleFacWidth);
	stream.WriteInt32L(iGlassScaleFacHeight);
	stream.CommitL();
	CleanupStack::PopAndDestroy(); // stream
	aStreamDic.AssignL(KUidOpButApp,streamId);
	}

void COpButDocument::RestoreL(const CStreamStore& aStore,const CStreamDictionary& aStreamDic)
	{
	TStreamId headStreamId=aStreamDic.At(KUidOpButApp);
	RStoreReadStream stream;
	stream.OpenLC(aStore,headStreamId);
	stream>> iModel->iValue;
	stream>> iGlassCropInTwips;
	iGlassScaleFacWidth = stream.ReadInt32L();
	iGlassScaleFacHeight = stream.ReadInt32L();
	CleanupStack::PopAndDestroy(); // stream
	}
	
CEikAppUi* COpButDocument::CreateAppUiL()
	{
    return(new(ELeave) COpButAppUi);
	}

CApaDocument::TCapability COpButDocument::Capability()const
	{
	TCapability capability;
	capability.SetCanDrawGlass();
	return capability;
	}

CPicture* COpButDocument::GlassPictureL()
	{
	return new(ELeave) COpButGlassDoor(this);
	}

//
// COpButApplication
//

class COpButApplication : public CEikApplication
	{
private: // from CApaApplication
	CApaDocument* CreateDocumentL();
	TUid AppDllUid() const;
	TFileName ResourceFileName() const;
	};

TFileName COpButApplication::ResourceFileName() const
	{
	TPtrC empty;
	return(empty);
	}
	
CApaDocument* COpButApplication::CreateDocumentL()
	{
	COpButDocument* ret=new(ELeave) COpButDocument(*this);
	CleanupStack::PushL(ret);
	ret->ConstructL();
	CleanupStack::Pop();
	return(ret);
	}

TUid COpButApplication::AppDllUid() const
	{
	return(KUidOpButApp);
	}
	
//
// EXPORTed functions
//

EXPORT_C CApaApplication* NewApplication()
	{
	return(new COpButApplication);
	}

GLDEF_C TInt E32Dll(TDllReason)
	{
	return(KErrNone);
	}
