📄 bossview.cpp
字号:
// bossview.cpp
//
// Copyright (c) 1998 Symbian Ltd. All rights reserved.
#include "bossview.h"
#include "bosseng.h"
#include <coemain.h>
const TInt KBossScrollIncrements=4; // 4 increments
#define KBossScrollTime TTimeIntervalMicroSeconds32(50000) // 0.05 sec
/*
CBossScroller - private definition
*/
class CBossScroller : public CActive
{
public:
// construct/destruct
CBossScroller(CBossView* aView, RWindow& aWindow);
void ConstructL();
~CBossScroller();
// requester functions
void StartL(TInt aOldBlankRow, TInt aOldBlankCol, TInt aNewBlankRow, TInt aNewBlankCol);
private: // from CActive
void DoCancel();
void RunL();
private:
void DoIncrement(); // do a scrolling increment and wait for next
private:
RTimer iTimer;
CBossView* iView;
RWindow& iWindow;
// incremental scrolling calculations
TInt iOldBlankRow;
TInt iOldBlankCol;
TInt iNewBlankRow;
TInt iNewBlankCol;
TRect iBoundingRect;
TPoint iVectorNeeded;
TInt iScalarNeeded;
TInt iScalarIncrement;
TPoint iUnitVector;
TInt iScalarDone;
};
/*
CBossView
*/
EXPORT_C CBossView::CBossView(TBossPuzzle* aModel)
: iModel(aModel)
{
}
EXPORT_C CBossView::CBossView()
{
}
EXPORT_C void CBossView::ConstructL(MGraphicsDeviceMap* aDeviceMap)
{
SetDeviceMapL(aDeviceMap);
}
CBossView::~CBossView()
{
SetDeviceMapL(0);
}
// constants
#define KBossTileSizeInTwips TPoint(480,480) // 1/3 inch square
#define KBossTileBorderInTwips TPoint(40,40) // 2 points
#define KBossBoardMarginInTwips TPoint(120,120) // 6 points = 1/12 inch
// handy utility function
TPoint operator*(TInt aScale, const TPoint& aPoint)
{ return TPoint(aScale*aPoint.iX, aScale*aPoint.iY); }
EXPORT_C void CBossView::SetDeviceMapL(MGraphicsDeviceMap* aDeviceMap)
{
//constant declarations
_LIT(KFontArial,"Arial");
// check for significant change
const TPoint p(10000,10000);
if (iDeviceMap && aDeviceMap && aDeviceMap->TwipsToPixels(p)==iDeviceMap->TwipsToPixels(p))
return;
// release old font
ReleaseTileFont();
// set new device map
iDeviceMap=aDeviceMap;
// quit if no map
if (!iDeviceMap)
return;
// tile size
iTileSizeInPixels=iDeviceMap->TwipsToPixels(KBossTileSizeInTwips);
iTileBorderInPixels=iDeviceMap->TwipsToPixels(KBossTileBorderInTwips);
// board margin and size
iBoardMarginInPixels=iDeviceMap->TwipsToPixels(KBossBoardMarginInTwips);
iBoardSizeInPixels=4*iTileSizeInPixels+2*iBoardMarginInPixels;
TFontSpec bossTileFontSpec (KFontArial, 12*20); // 12 points = 1/6 inch
bossTileFontSpec.iTypeface.SetIsProportional(ETrue); // Arial is proportional
// tile font
User::LeaveIfError(iDeviceMap->GetNearestFontInTwips(iTileFont,bossTileFontSpec));
}
void CBossView::GetBoardRect(TRect& aBoardRect) const
{
aBoardRect=TRect(iTopLeft, iBoardSizeInPixels.AsSize());
}
void CBossView::DrawBackground(const TRect& aRect) const
{
TRect boardOuterRect;
GetBoardRect(boardOuterRect);
iGc->SetPenStyle(CGraphicsContext::ENullPen);
iGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
iGc->SetBrushColor(KRgbGray);
if (boardOuterRect.iBr.iX < aRect.iBr.iX) // fill to the right
{
TRect r(TPoint(boardOuterRect.iBr.iX, boardOuterRect.iTl.iY),
TPoint(aRect.iBr.iX, boardOuterRect.iBr.iY));
iGc->DrawRect(r);
}
if (boardOuterRect.iBr.iY < aRect.iBr.iY) // fill below, and below-right if needed
{
TRect r(TPoint(boardOuterRect.iTl.iX, boardOuterRect.iBr.iY), aRect.iBr);
iGc->DrawRect(r);
}
}
void CBossView::DrawBoard() const
{
// calculate rectangle to draw into
TRect boardOuterRect;
GetBoardRect(boardOuterRect);
TRect boardInnerRect=boardOuterRect;
boardInnerRect.Shrink(iBoardMarginInPixels.AsSize()-TSize(1,1));
// draw board border
iGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
iGc->SetBrushColor(KRgbDarkGray);
iGc->SetPenStyle(CGraphicsContext::ENullPen);
iGc->DrawRect(TRect(boardOuterRect.iTl, TPoint(boardOuterRect.iBr.iX, boardInnerRect.iTl.iY)));
iGc->DrawRect(TRect(TPoint(boardOuterRect.iTl.iX,boardInnerRect.iBr.iY),boardOuterRect.iBr));
iGc->DrawRect(TRect(TPoint(boardOuterRect.iTl.iX,boardInnerRect.iTl.iY),TPoint(boardInnerRect.iTl.iX,boardInnerRect.iBr.iY)));
iGc->DrawRect(TRect(TPoint(boardInnerRect.iBr.iX,boardInnerRect.iTl.iY),TPoint(boardOuterRect.iBr.iX,boardInnerRect.iBr.iY)));
// draw highlights
iGc->SetBrushStyle(CGraphicsContext::ENullBrush);
iGc->SetPenStyle(CGraphicsContext::ESolidPen);
iGc->SetPenColor(KRgbBlack);
iGc->DrawRect(boardOuterRect);
iGc->SetPenColor(KRgbWhite);
iGc->DrawRect(boardInnerRect);
}
void CBossView::GetTileRect(TRect& aTileRect, TInt aRow, TInt aCol) const
{
TPoint tileTopLeft=iTopLeft+iBoardMarginInPixels;
aTileRect=
TRect(
tileTopLeft+TPoint(aCol*iTileSizeInPixels.iX,aRow*iTileSizeInPixels.iY),
iTileSizeInPixels.AsSize()
);
}
TInt CBossView::GetTileFromXY(const TPoint& aPoint, TInt& aRow, TInt& aCol)
{
// a truly crass implementation - scan all tiles - should optimize to exploit obvious geometry
for (aRow=0; aRow<4; aRow++)
{
for (aCol=0; aCol<4; aCol++)
{
TRect tileRect;
GetTileRect(tileRect, aRow, aCol);
if (tileRect.Contains(aPoint))
return KErrNone;
}
}
return KErrNotFound;
}
void CBossView::DrawTile(TInt aRow, TInt aCol) const
{
//constant declarations
_LIT(KNumFormat,"%d");
// tile or blank
TRect tileRect;
GetTileRect(tileRect, aRow, aCol);
if (iModel->Tile(aRow,aCol)!=0) // real tile
{
iGc->UseFont(iTileFont);
// draw rectangle
iGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
iGc->SetBrushColor(KRgbGray);
iGc->SetPenStyle(CGraphicsContext::ESolidPen);
iGc->SetPenColor(KRgbBlack);
iGc->DrawRect(tileRect);
iGc->SetPenColor(KRgbWhite);
iGc->DrawLine(TPoint(tileRect.iTl.iX,tileRect.iBr.iY-2),tileRect.iTl);
iGc->DrawLine(tileRect.iTl,TPoint(tileRect.iBr.iX-1,tileRect.iTl.iY));
tileRect.Shrink(iTileBorderInPixels.AsSize());
iGc->SetBrushColor(KRgbWhite);
iGc->SetPenColor(KRgbBlack);
// draw number
TInt ascent=
(tileRect.Height() - iTileFont->HeightInPixels())/2 +
iTileFont->AscentInPixels();
// draw text in rectangle
TBuf<2> number;
number.Format(KNumFormat,TInt(iModel->Tile(aRow,aCol)));
iGc->DrawText(number, tileRect, ascent, CGraphicsContext::ECenter, 0);
iGc->DiscardFont();
}
else // blank
{
iGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
iGc->SetBrushColor(KRgbGray);
iGc->SetPenStyle(CGraphicsContext::ENullPen);
iGc->DrawRect(tileRect);
}
}
EXPORT_C void CBossView::GetOriginalSizeInTwips(TSize& aSize) const
{
TPoint size=4*KBossTileSizeInTwips+2*KBossBoardMarginInTwips;
aSize=size.AsSize();
}
EXPORT_C TSize CBossView::GetSizeInPixels() const
{
return iBoardSizeInPixels.AsSize();
}
void CBossView::ReleaseTileFont()
{
if (iTileFont)
{
iDeviceMap->ReleaseFont(iTileFont);
iTileFont=0;
}
}
EXPORT_C void CBossView::Draw(CGraphicsContext& aGc, const TRect& aRect, const TPoint& aTopLeft) const
{
// remember values
CBossView* mutableThis=(CBossView*) this;
mutableThis->iGc=&aGc;
mutableThis->iTopLeft=aTopLeft;
// draw components
DrawBackground(aRect);
DrawBoard();
for (TInt row=0; row<4; row++)
for (TInt col=0; col<4; col++)
DrawTile(row,col);
}
/*
CBossControl
*/
EXPORT_C CBossControl::CBossControl(TBossPuzzle* aModel, CBossView* aView, MBossControlObserver* aObserver)
: iModel(aModel), iView(aView), iObserver(aObserver)
{
}
EXPORT_C CBossControl::CBossControl()
{
}
EXPORT_C void CBossControl::ConstructL(const CCoeControl* aParent, const TRect& aRect)
{
// create window - a lodger control
CreateWindowL(aParent);
SetRect(aRect);
// create scroller
iScroller=new (ELeave) CBossScroller(iView, Window());
iScroller->ConstructL();
// go for it
ActivateL();
}
CBossControl::~CBossControl()
{
delete iScroller;
}
void CBossControl::Draw(const TRect& /* aRect */) const
{
// clear board altogether
CWindowGc& gc=SystemGc();
iView->Draw(gc, Rect(), TPoint(0,0));
}
void CBossControl::HandlePointerEventL(const TPointerEvent& aPointerEvent)
{
switch (aPointerEvent.iType)
{
case TPointerEvent::EButton1Down:
{
TInt row, col;
TInt err=iView->GetTileFromXY(aPointerEvent.iPosition, row, col);
if (err!=KErrNone)
break;
iObserver->BCOMove(row, col);
}
default:
break;
}
}
TKeyResponse CBossControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
{
if (aType!=EEventKey)
return EKeyWasNotConsumed;
switch(aKeyEvent.iCode)
{
case EKeyLeftArrow:
iObserver->BCOMove(TBossPuzzle::ELeft);
break;
case EKeyRightArrow:
iObserver->BCOMove(TBossPuzzle::ERight);
break;
case EKeyUpArrow:
iObserver->BCOMove(TBossPuzzle::EUp);
break;
case EKeyDownArrow:
iObserver->BCOMove(TBossPuzzle::EDown);
break;
default:
return EKeyWasNotConsumed;
}
return EKeyWasConsumed;
}
EXPORT_C void CBossControl::MoveTile(TInt aOldBlankRow, TInt aOldBlankCol, TInt aNewBlankRow, TInt aNewBlankCol) const
{
iScroller->StartL(aOldBlankRow, aOldBlankCol, aNewBlankRow, aNewBlankCol);
}
EXPORT_C void CBossControl::FinishMove() const
{
iScroller->Cancel();
}
/*
CBossScroller
*/
CBossScroller::CBossScroller(CBossView* aView, RWindow& aWindow)
: CActive(CActive::EPriorityStandard), iView(aView), iWindow(aWindow)
{
CActiveScheduler::Add(this);
}
void CBossScroller::ConstructL()
{
User::LeaveIfError(iTimer.CreateLocal());
}
CBossScroller::~CBossScroller()
{
Cancel();
iTimer.Close();
}
void CBossScroller::StartL(TInt aOldBlankRow, TInt aOldBlankCol, TInt aNewBlankRow, TInt aNewBlankCol)
{
// cancel any existing scroll, just in case - but shouldn't be necessary!
Cancel();
// remember parameters
iOldBlankRow=aOldBlankRow;
iOldBlankCol=aOldBlankCol;
iNewBlankRow=aNewBlankRow;
iNewBlankCol=aNewBlankCol;
// old and new rectangles
TRect oldBlankRect;
iView->GetTileRect(oldBlankRect, aOldBlankRow, aOldBlankCol);
TRect newBlankRect;
iView->GetTileRect(newBlankRect, aNewBlankRow, aNewBlankCol);
// bounding rectangle for scroll action
iBoundingRect=oldBlankRect;
iBoundingRect.BoundingRect(newBlankRect);
// tile scrolls from new-blank to old-blank - get vector between them
iVectorNeeded=oldBlankRect.iTl-newBlankRect.iTl;
iScalarNeeded=iVectorNeeded.iX==0 ? iVectorNeeded.iY : iVectorNeeded.iX;
if (iScalarNeeded < 0)
iScalarNeeded = -iScalarNeeded;
iScalarIncrement=iScalarNeeded / KBossScrollIncrements;
if (iScalarIncrement * KBossScrollIncrements < iScalarNeeded)
iScalarIncrement+=1;
// calculate unit vector in direction of scroll
iUnitVector=TPoint(0,0);
if (iVectorNeeded.iX > 0) iUnitVector.iX=1;
if (iVectorNeeded.iX < 0) iUnitVector.iX=-1;
if (iVectorNeeded.iY > 0) iUnitVector.iY=1;
if (iVectorNeeded.iY < 0) iUnitVector.iY=-1;
// nothing done yet
iScalarDone=0;
// do first incremental scroll
DoIncrement();
}
void CBossScroller::DoIncrement()
{
// do first incremental scroll
iScalarDone+=iScalarIncrement;
TInt increment=iScalarIncrement;
if (iScalarDone > iScalarNeeded)
{
increment-=iScalarDone-iScalarNeeded;
iScalarDone=iScalarNeeded;
}
// scroll the tile
iWindow.Scroll(iBoundingRect, increment * iUnitVector);
// retro-draw the exposed part of the blank, now
CWindowGc* gc=(CWindowGc*) (iView->iGc);
gc->Activate(iWindow);
iWindow.BeginRedraw(iBoundingRect); // clip to invalid region from scroll
iView->DrawTile(iNewBlankRow, iNewBlankCol);
iWindow.EndRedraw();
gc->Deactivate();
// quit if finished
if (iScalarDone==iScalarNeeded)
return;
// wait for a short while if not
iTimer.After(iStatus, KBossScrollTime);
SetActive();
}
void CBossScroller::DoCancel()
{
// stop waiting
iTimer.Cancel();
// make sure drawing is in sync
CWindowGc* gc=(CWindowGc*) (iView->iGc);
gc->Activate(iWindow);
iWindow.Invalidate(iBoundingRect); // invalidate old and new tiles
iWindow.BeginRedraw(iBoundingRect);
iView->DrawTile(iOldBlankRow, iOldBlankCol); // tile
iView->DrawTile(iNewBlankRow, iNewBlankCol); // blank
iWindow.EndRedraw();
gc->Deactivate();
}
void CBossScroller::RunL()
{
DoIncrement();
}
// required as a DLL
EXPORT_C TInt E32Dll(TDllReason)
{
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -