// TMENU0.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <coeaui.h>
#include <coemain.h>
#include <coecntrl.h>
#include <e32keys.h>
#include <basched.h>

#include "tmenuasi.h"

class MTestMenuObserver
	{
public:
	virtual void MenuSelectionMade(TInt aSelection)=0;
	};

//
// class CTestMenu
//

class CTestMenu : public CCoeControl
	{
public:
    inline CTestMenu(MTestMenuObserver* aObserver) { iObserver=aObserver; }
private: // framework
    TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);
private:
    MTestMenuObserver* iObserver;
    };

TKeyResponse CTestMenu::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
    {
	if (aType==EEventKey)
		{
	    TInt modifiers=aKeyEvent.iModifiers;
	    TInt code=aKeyEvent.iCode;
	    if ((modifiers&EAllStdModifiers)==EModifierCtrl)
	        {
	        iObserver->MenuSelectionMade(code);
	        return(EKeyWasConsumed);
	        }
		}
    return(EKeyWasNotConsumed);
    }
    
//
// class CMessageControl
//

enum TMessageControlFontStyle
    {
    EStyleElementBold,
    EStyleElementItalic,
    EStyleElementUnderline,
    EStyleElementStrikethrough
    };

class CMessageControl : public CCoeControl
    {
public:
    ~CMessageControl();
    void ConstructL();
    void ToggleFontStyleL(TMessageControlFontStyle aStyleElement);
    void SetMessage(const TDesC& aMessage);
private: // framework
    TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);
    void HandlePointerEventL(const TPointerEvent& aPointerEvent);
    void Draw(const TRect& aRect) const;
	void FocusChanged(TDrawNow aDrawNow);
private: // new functions
    void DrawBorder() const;
    void SetFontL(const TFontSpec& aFontSpec);
    void DrawMessage() const;
    void DrawMessageNow() const;
private:
    TBuf<40> iMessage;
    TFontSpec iFontSpec;
    TFontUnderline iFontUnderline;
    TFontStrikethrough iFontStrikethrough;
    CFbsFont* iFont;
    };

void CMessageControl::ConstructL()
    {
    CreateWindowL();
    SetExtentL(TPoint(20,20),TSize(600,200));
    TFontSpec spec(_L("Arial"),220);
    SetFontL(spec);
    ActivateL();
    }

CMessageControl::~CMessageControl()
    {
    iCoeEnv->ReleaseScreenFont(iFont);
    }

void CMessageControl::SetFontL(const TFontSpec& aFontSpec)
    {
    CFbsFont* font=iCoeEnv->CreateScreenFontL(aFontSpec);
    iCoeEnv->ReleaseScreenFont(iFont); // after previous line succeeds
    iFont=font;
    iFontSpec=aFontSpec;
    }

void CMessageControl::ToggleFontStyleL(TMessageControlFontStyle aStyleElement)
    {
    TFontSpec spec=iFontSpec;
    TBool doSet=EFalse;
    switch (aStyleElement)
        {
    case EStyleElementBold:
        spec.iFontStyle.SetStrokeWeight(spec.iFontStyle.StrokeWeight()? EStrokeWeightNormal: EStrokeWeightBold);
        doSet=ETrue;
        break;
    case EStyleElementItalic:
        spec.iFontStyle.SetPosture(spec.iFontStyle.Posture()? EPostureUpright: EPostureItalic);
        doSet=ETrue;
        break;
    case EStyleElementUnderline:
        iFontUnderline=(iFontUnderline? EUnderlineOff: EUnderlineOn);
        break;
    case EStyleElementStrikethrough:
        iFontStrikethrough=(iFontStrikethrough? EStrikethroughOff: EStrikethroughOn);
        }
    if (doSet)
        SetFontL(spec); // otherwise change effective at Draw time
    }

void CMessageControl::HandlePointerEventL(const TPointerEvent& aPointerEvent)
    {
    iMessage.Format(_L("Pointer event %d at (%d,%d)"),aPointerEvent.iType,aPointerEvent.iPosition.iX,aPointerEvent.iPosition.iY);
    DrawMessageNow();
    }

void CMessageControl::FocusChanged(TDrawNow aDrawNow)
	{
    if (aDrawNow)
        {
        ActivateGc();
        DrawBorder();
        DeactivateGc();
        }
    }

void CMessageControl::DrawBorder() const
	{
    CWindowGc& gc=SystemGc();
    TRect rect=Rect();
    gc.DrawRect(rect);
    if (!IsFocused())
        gc.SetPenColor(KRgbWhite);
    rect.Shrink(1,1);
    gc.DrawRect(rect);
    rect.Shrink(1,1);
    gc.DrawRect(rect);
	}

void CMessageControl::Draw(const TRect& /*aRect*/) const
    {
    DrawBorder();
    DrawMessage();
    }

void CMessageControl::DrawMessage() const
    {
    TRect rect=Rect();
    rect.Shrink(3,3);
    TInt ascent=(rect.iBr.iY-rect.iTl.iY-iFont->HeightInPixels())/2 + iFont->AscentInPixels();
    CWindowGc& gc=SystemGc();
    gc.SetPenColor(KRgbBlack);
	gc.UseFont(iFont);
    if (iFontUnderline)
        gc.SetUnderlineStyle(iFontUnderline);
    if (iFontStrikethrough)
        gc.SetStrikethroughStyle(iFontStrikethrough);
    gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
    gc.DrawText(iMessage,rect,ascent,CGraphicsContext::ECenter);
    }

void CMessageControl::DrawMessageNow() const
    {
	ActivateGc();
	DrawMessage();
	DeactivateGc();
    }

void CMessageControl::SetMessage(const TDesC& aMessage)
    {
    iMessage=aMessage;
    DrawMessageNow();
    }

TKeyResponse CMessageControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
    {
    if (aType!=EEventKey)
	    return(EKeyWasConsumed);
	TInt modifiers=aKeyEvent.iModifiers;
	TInt code=aKeyEvent.iCode;
	iMessage.Format(_L("Key 0x%x, modifier 0x%x"),code,modifiers);
	DrawMessageNow();
	if ((modifiers&EAllStdModifiers)==(EModifierShift|EModifierCtrl))
       {
        TPoint pos=Position();
        switch (code)
            {
        case EKeyLeftArrow:
            pos.iX--;
            break;
        case EKeyRightArrow:
            pos.iX++;
            break;
        case EKeyUpArrow:
            pos.iY--;
            break;
        case EKeyDownArrow:
            pos.iY++;
            break;
        default:
            goto exit;
            }
        SetPosition(pos);
        }
exit:
    return(EKeyWasConsumed);
    }

//
// class CTestAppUi
//

class CTestAppUi : public CCoeAppUi, public MTestMenuObserver
    {
public:
    ~CTestAppUi();
    void ConstructL();
private: // from MTestMenuObserver
    void MenuSelectionMade(TInt aSelection);
private: // from CCoeAppUi
	void HandleApplicationSpecificEventL(TInt aType,const TWsEvent& aEvent);
private: // new functions
    void ToggleBold();
    void ToggleUnderline();
    void ToggleItalic();
    void ToggleStrikethrough();
	void SendAsiMessageL(TMenuAsiEventSend aEvent);
	void SendMessageL(const TDesC8& aTextMsg);
private:
    CMessageControl* iMessageControl;
    CTestMenu* iMenu;
    };

CTestAppUi::~CTestAppUi()
    {
    delete(iMessageControl);
    delete(iMenu);
    }
    
void CTestAppUi::ToggleBold()
    {
    iMessageControl->ToggleFontStyleL(EStyleElementBold);
    }
    
void CTestAppUi::ToggleItalic()
    {
    iMessageControl->ToggleFontStyleL(EStyleElementItalic);
    }
    
void CTestAppUi::ToggleUnderline()
    {
    iMessageControl->ToggleFontStyleL(EStyleElementUnderline);
    }
    
void CTestAppUi::ToggleStrikethrough()
    {
    iMessageControl->ToggleFontStyleL(EStyleElementStrikethrough);
    }
    
void CTestAppUi::SendMessageL(const TDesC8& aTextMsg)
	{
	RWsSession& wsSession=iCoeEnv->WsSession();
	TInt wgId=wsSession.FindWindowGroupIdentifier(0,TMenu1GroupName,0);
	if (wgId>0)
		User::LeaveIfError(wsSession.SendMessageToWindowGroup(wgId,KNullUid,aTextMsg));
	else
		iMessageControl->SetMessage(_L("TMenu1 is not running"));
	}

void CTestAppUi::HandleApplicationSpecificEventL(TInt aType,const TWsEvent& aEvent)
	{
	switch (aType)
		{
	case EReplyWindowAdded:
		iMessageControl->SetMessage(_L("Window added"));
		return;
	case EReplyFailedToAddWindow:
		iMessageControl->SetMessage(_L("Failed to add window"));
		return;
	case EReplyWindowRemoved:
		iMessageControl->SetMessage(_L("Window removed"));
		return;
	case EReplyNoWindowToRemove:
		iMessageControl->SetMessage(_L("No window to remove"));
		return;
	case EReplyWindowsCounted:
    	TBuf<40> message;
    	message.Format(_L("Number of windows: %d"),*(TInt*)aEvent.EventData());
    	iMessageControl->SetMessage(message);
		}
	}

void CTestAppUi::SendAsiMessageL(TMenuAsiEventSend aEvent)
	{
	RWsSession& wsSession=iCoeEnv->WsSession();
	TInt wgId=wsSession.FindWindowGroupIdentifier(0,TMenu1GroupName);
	if (wgId<=0)
		{
		iMessageControl->SetMessage(_L("TMenu1 is not running"));
		return;
		}
	TWsEvent wsEvent;
	wsEvent.SetType(aEvent);
	*(TInt*)wsEvent.EventData()=iCoeEnv->RootWin().Identifier();
	User::LeaveIfError(wsSession.SendEventToWindowGroup(wgId,wsEvent));
	}

void CTestAppUi::MenuSelectionMade(TInt aSelection)
    {
    switch (aSelection)
        {
	case CTRL('a'):
		SendAsiMessageL(ESendAddWindow);
		return;
    case CTRL('b'):
        ToggleBold();
        break;
	case CTRL('c'):
		SendAsiMessageL(ESendCountWindows);
		return;
    case CTRL('i'):
        ToggleItalic();
        break;
	case CTRL('m'):
		SendMessageL(_L8("Greetings from TMenu0"));
		return;
	case CTRL('o'):
		iCoeEnv->BringOwnerToFront();
		break;
	case CTRL('r'):
		SendAsiMessageL(ESendRemoveWindow);
		return;
    case CTRL('s'):
        ToggleStrikethrough();
        break;
    case CTRL('u'):
        ToggleUnderline();
        break;
        }
    TBuf<40> message;
    message.Format(_L("Menu command Ctrl+%c chosen"),aSelection+'A'-1);
    iMessageControl->SetMessage(message);
    if (aSelection==CTRL('e'))
        {
		iCoeEnv->Flush(200000);
        CBaActiveScheduler::Exit();
        }
    }
    
void CTestAppUi::ConstructL()
    {
    CCoeAppUi::ConstructL();
    iMessageControl=new(ELeave) CMessageControl;
    iMessageControl->ConstructL();
    AddToStackL(iMessageControl);
    iMenu=new(ELeave) CTestMenu(this);
    AddToStackL(iMenu,ECoeStackPriorityMenu,ECoeStackFlagRefusesFocus);
    }

//
// Main
//

void ConstructAppL(CCoeEnv* aCoe)
    { // runs inside a TRAP harness
    aCoe->ConstructL();
    CTestAppUi* appUi=new(ELeave) CTestAppUi;
    aCoe->SetAppUi(appUi);
    appUi->ConstructL();
    }

#if defined(__WINS__)
EXPORT_C TInt EntryPoint(TAny*)
#else
GLDEF_C TInt E32Main()
#endif
    {
    CCoeEnv* coe=new CCoeEnv;
    TRAPD(err,ConstructAppL(coe));
    if (!err)
        coe->ExecuteD();
    return(err);
    }

#if defined(__WINS__)
GLDEF_C TInt E32Dll(TDllReason)
	{
	return(KErrNone);
	}
#endif
