#include "UnboundModeDemoIntMinerField.h" void __fastcall TIntMinerField::SetSchemeColors(void) { FOpenCellBkColor = SchemeColors[(int)FColorScheme][0]; FClosedCellBkColor = SchemeColors[(int)FColorScheme][1]; FFrameColor = SchemeColors[(int)FColorScheme][2]; FRectangleColor = SchemeColors[(int)FColorScheme][3]; } //--------------------------------------------------------------------------- TCellStateRec __fastcall TIntMinerField::GetCellState(int ACol, int ARow) { return (*(PCellStateRec)(int)((TcxGridTableView*)Views[0])-> ViewInfo->RecordsViewInfo->Items[ARow]->GetCellViewInfoByItem( ((TcxGridTableView*)Views[0])->Items[ACol])->Value ); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::AddPressedCell(int ACol, int ARow) { FPressedCells.Length++; FPressedCells[FPressedCells.Length - 1].x = ACol; FPressedCells[FPressedCells.Length - 1].y = ARow; } //--------------------------------------------------------------------------- bool __fastcall TIntMinerField::CheckFieldBounds(int AXPos, int AYPos) { bool Result = false; if((AXPos >=0) && (AYPos >=0) && (AXPos < FColCount) && (AYPos < FRowCount)) Result = true; return (Result); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::InitNewGame(void) { FRedCells.Length = 0; FColCount = FGameDifficulty.Width; FRowCount = FGameDifficulty.Height; BeginUpdate(); try { Width = FColCount * FCellWidth + 2; Height = FRowCount * FCellWidth + 2; Top = psBorder + biBoardHeight - psOuterFrameWidth; Left = psBorder; int par = ((TForm*)Owner)->ClientRect.Right - ((TForm*)Owner)->ClientRect.Left; par = ((TForm*)Owner)->Width - par - psOuterFrameWidth; ((TForm*)Owner)->Width = 2 * psBorder + Width + par; par = ((TForm*)Owner)->ClientRect.Bottom - ((TForm*)Owner)->ClientRect.Top; par = ((TForm*)Owner)->Height - par; ((TForm*)Owner)->Height = par + 2 * (psBorder - psOuterFrameWidth) + biBoardHeight + Height; ((TControlAccess*)Owner)->Resize(); if (!Enabled) Enabled = true; TcxGridColumn* GridColumn; for(int i = ((TcxGridTableView*)Views[0])->ColumnCount - 1; i == FColCount; i--) delete ((TcxGridTableView*)Views[0])->Columns[i]; for(int i=0; i < FGameDifficulty.Width; i++) { if (i >= ((TcxGridTableView*)Views[0])->ColumnCount) { GridColumn = ((TcxGridTableView*)Views[0])->CreateColumn(); GridColumn->MinWidth = FCellWidth; GridColumn->Width = FCellWidth; } } } __finally { EndUpdate(); } } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::UnpressAndInvalidate(void) { TCells CellsToInvalidate; CellsToInvalidate.Length = FPressedCells.Length; for(int i=0; i < FPressedCells.Length; i++) CellsToInvalidate[i] = FPressedCells[i]; FPressedCells.Length = 0; for(int i=0; i < CellsToInvalidate.Length; i++) InvalidateCell(CellsToInvalidate[i].x, CellsToInvalidate[i].y); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::InvalidateCells(const TCells AChangedCells, const TCells ARedCells) { for(int i=0; i < AChangedCells.Length; i++) InvalidateCell(AChangedCells[i].x, AChangedCells[i].y); for(int i=0; i < ARedCells.Length; i++) InvalidateCell(ARedCells[i].x, ARedCells[i].y); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::UpdateMinerFieldState(const TCells ARedCells) { FRedCells.Length = ARedCells.Length; for(int i=0; i < ARedCells.Length; i++) FRedCells[i] = ARedCells[i]; } //--------------------------------------------------------------------------- void AlignTextInCell(TCanvas* ACanvas, TRect Rect, String AStr, TAlignment Alignment = taCenter) { int Y = 3; int X = 1; switch(Alignment) { case taCenter: X = ((Rect.Right - Rect.Left) - ACanvas->TextWidth(AStr)) >> 1; break; case taLeftJustify: X = 1; break; case taRightJustify: X = ((Rect.Right - Rect.Left) - ACanvas->TextWidth(AStr)) -1; break; } ACanvas->TextOut(Rect.Left + X, Rect.Top + Y, AStr); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::DrawOpenedCell(TCanvas* ACanvas, TRect ARect, TCellStateRec ACellState) { ACanvas->Brush->Color = FOpenCellBkColor; ACanvas->FillRect(ARect); ACanvas->Pen->Style = psSolid; ACanvas->Pen->Color = FRectangleColor; ARect.Left--; ARect.Top--; ACanvas->Rectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom); ARect.Right--; ARect.Bottom--; ACanvas->Font->Style = TFontStyles() << fsBold; if(ACellState.SurroundNumber >= 1) ACanvas->Font->Color = FSurroundColors[ACellState.SurroundNumber-1]; Brush->Style = bsClear; if(ACellState.SurroundNumber != 0) AlignTextInCell(ACanvas, ARect, IntToStr(ACellState.SurroundNumber)); } void __fastcall TIntMinerField::DrawClosedCell(TCanvas* ACanvas, TRect ARect, TCellStateRec ACellState, int ACol, int ARow) { if(FGameStatus == gsLost) { if(IsExistsInArray(FRedCells, ACol, ARow)) { // red bomb on an empty background ACanvas->Brush->Color = FOpenCellBkColor; ACanvas->FillRect(ARect); ACanvas->Brush->Style = bsSolid; ACanvas->Brush->Color = clRed; ARect.Right--; ARect.Bottom--; ACanvas->FillRect(ARect); ACanvas->Brush->Style = bsClear; ARect.Left++; ARect.Top++; ARect.Right++; ARect.Bottom--; FImages->Draw(ACanvas, ARect.Left, ARect.Top, imRedBomb, true); return; } if(ACellState.SurroundNumber == -1) { ACanvas->Brush->Color = FOpenCellBkColor; ACanvas->FillRect(ARect); ACanvas->Pen->Style = psSolid; ACanvas->Pen->Color = FRectangleColor; ARect.Left--; ARect.Top--; ACanvas->Rectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom); ARect.Left = ARect.Left + 2; ARect.Top = ARect.Top + 2; ACanvas->Brush->Style = bsClear; FImages->Draw(ACanvas, ARect.Left, ARect.Top, imBomb, true); // bomb image } else Frame3D(ACanvas, ARect, FFrameColor, FOpenCellBkColor, 1); // unpressed } else if((FGameStatus == gsNew) || (FGameStatus == gsRun)) { if(IsExistsInArray(FPressedCells, ACol, ARow)) Frame3D(ACanvas, ARect, FOpenCellBkColor, FFrameColor, 1); // pressed else Frame3D(ACanvas, ARect, FFrameColor, FOpenCellBkColor, 1); // unpressed } if(FGameStatus == gsWon) { Frame3D(ACanvas, ARect, FFrameColor, FOpenCellBkColor, 1); // unpressed if(ACellState.SurroundNumber == -1) FImages->Draw(ACanvas, ARect.Left, ARect.Top, imBombMark, true); // bomb flag } } void __fastcall TIntMinerField::DrawBombMarkedCell(TCanvas* ACanvas, TRect ARect, TCellStateRec ACellState) { if(FGameStatus == gsLost) { if(ACellState.SurroundNumber == -1) { Frame3D(ACanvas, ARect, FFrameColor, FOpenCellBkColor, 1); // unpressed FImages->Draw(ACanvas, ARect.Left, ARect.Top, imBombMark, true); // bomb flag } else { // striked out bomb on an empty background ACanvas->Brush->Color = FOpenCellBkColor; ACanvas->FillRect(ARect); ACanvas->Pen->Style = psSolid; ACanvas->Pen->Color = FRectangleColor; ARect.Left--; ARect.Top--; ACanvas->Rectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom); ARect.Left = ARect.Left + 2; ARect.Top = ARect.Top + 2; ACanvas->Brush->Style = bsClear; FImages->Draw(ACanvas, ARect.Left, ARect.Top, imStruckOutBomb, true); } } else if((FGameStatus == gsRun) || (FGameStatus == gsWon) || (FGameStatus == gsNew)) { Frame3D(ACanvas, ARect, FFrameColor, FOpenCellBkColor, 1); // unpressed FImages->Draw(ACanvas, ARect.Left, ARect.Top, imBombMark, true); // bomb flag } } void __fastcall TIntMinerField::DrawQuestionMarkedCell(TCanvas* ACanvas, TRect ARect, TCellStateRec ACellState, int ACol, int ARow) { if(FGameStatus == gsWon) { if(ACellState.SurroundNumber == -1) { Frame3D(ACanvas, ARect, FFrameColor, FOpenCellBkColor, 1); // unpressed FImages->Draw(ACanvas, ARect.Left, ARect.Top, imBombMark, true); // bomb flag } } else if(FGameStatus == gsLost) { if(ACellState.SurroundNumber == -1) { ACanvas->Brush->Color = FClosedCellBkColor; ACanvas->FillRect(ARect); ACanvas->Pen->Style = psSolid; ACanvas->Pen->Color = FOpenCellBkColor; ARect.Left--; ARect.Top--; ACanvas->Rectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom); ARect.Left = ARect.Left + 2; ARect.Top = ARect.Top + 2; ACanvas->Brush->Style = bsClear; FImages->Draw(ACanvas, ARect.Left, ARect.Top, imBomb, true); // bomb on an empty background } else { Frame3D(ACanvas, ARect, FFrameColor, FOpenCellBkColor, 1); // unpressesd FImages->Draw(ACanvas, ARect.Left, ARect.Top, imQuestionMark, true); // question mark } } else if((FGameStatus == gsNew) || (FGameStatus == gsRun)) { if(!IsExistsInArray(FPressedCells, ACol, ARow)) Frame3D(ACanvas, ARect, FFrameColor, FOpenCellBkColor, 1); // unpresses else Frame3D(ACanvas, ARect, FOpenCellBkColor, FFrameColor, 1); // pressed FImages->Draw(ACanvas, ARect.Left, ARect.Top, imQuestionMark, true); // question mark } } void __fastcall TIntMinerField::DrawCell(const TCellStateRec ACellState, int ACol, int ARow, const TRect &ARect, Graphics::TCanvas* ACanvas) { String CellStr; ACanvas->Brush->Style = bsSolid; ACanvas->Brush->Color = FClosedCellBkColor; ACanvas->FillRect(ARect); switch (ACellState.CellState) { case csOpened: DrawOpenedCell(ACanvas, ARect, ACellState); break; case csClosed: DrawClosedCell(ACanvas, ARect, ACellState, ACol, ARow); break; case csBombMarked: DrawBombMarkedCell(ACanvas, ARect, ACellState); break; case csQuestionMarked: DrawQuestionMarkedCell(ACanvas, ARect, ACellState, ACol, ARow); break; }; } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::InvalidateCell(int ACol, int ARow) { TRect InvalidRect = ((TcxGridTableView*)Views[0])->ViewInfo->RecordsViewInfo->Items[ARow]->GetCellViewInfoByItem(((TcxGridTableView*)Views[0])->Items[ACol])->Bounds; Views[0]->Painter->Invalidate(InvalidRect); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::MouseDownHandler(System::TObject* Sender, Controls::TMouseButton Button, Classes::TShiftState Shift, int X, int Y) { int ACol, ARow; SetCaptureControl(Views[0]->Site); MouseToCell(X, Y, ACol, ARow); if((ACol == - 1) || (ARow == -1)) return; if((Shift == (TShiftState() << ssLeft << ssRight)) || (Shift == (TShiftState() << ssLeft << ssRight)) || (Shift == (TShiftState() << ssMiddle)) || (Shift == (TShiftState() << ssLeft << ssMiddle)) || (Shift == (TShiftState() << ssRight << ssMiddle))) { FireImageChanged(imAstonisment); FSurprised = true; for(int i=-1; i <=1; i++) for(int j=-1; j <=1; j++) if(CheckFieldBounds(ACol+i, ARow+j) && ( (CellState[ACol+i][ARow+j].CellState == csClosed) || (CellState[ACol+i][ARow+j].CellState == csQuestionMarked))) { AddPressedCell(ACol+i, ARow+j); InvalidateCell(ACol+i, ARow+j); }; return; }; if(Button == mbLeft) { FireImageChanged(imAstonisment); FSurprised = true; if((CellState[ACol][ARow].CellState == csClosed) || (CellState[ACol][ARow].CellState == csQuestionMarked)) { AddPressedCell(ACol, ARow); InvalidateCell(ACol, ARow); }; return; }; if(Button == mbRight) { if(CellState[ACol][ARow].CellState == csOpened) return; if(CellState[ACol][ARow].CellState == csClosed) { FireMinerFieldEvent(ACol, ARow, meBombMarkCell); FireSetMineCountEvent(mcDecMineCount); } else if((CellState[ACol][ARow].CellState == csBombMarked) && FQuestionMarkCell) { FireMinerFieldEvent(ACol, ARow, meQuestionMarkCell); FireSetMineCountEvent(mcIncMineCount); } else { FireMinerFieldEvent(ACol, ARow, meCloseCell); if(!FQuestionMarkCell) FireSetMineCountEvent(mcIncMineCount); }; InvalidateCell(ACol, ARow); }; } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::MouseMoveHandler(System::TObject* Sender, Classes::TShiftState Shift, int X, int Y) { int ACol, ARow; MouseToCell(X, Y, ACol, ARow); if((ACol == - 1) || (ARow == -1)) { if(FPressedCells.Length != 0) UnpressAndInvalidate(); if(FSurprised) { FireImageChanged(imSmile); FSurprised = false; }; return; }; if(Shift == (TShiftState() << ssLeft)) { if((CellState[ACol][ARow].CellState == csOpened)) { if(FPressedCells.Length != 0) { UnpressAndInvalidate(); InvalidateCell(ACol, ARow); }; } else if((CellState[ACol][ARow].CellState == csClosed) || (CellState[ACol][ARow].CellState == csQuestionMarked)) if(!IsExistsInArray(FPressedCells, ACol, ARow)) { UnpressAndInvalidate(); AddPressedCell(ACol, ARow); InvalidateCell(ACol, ARow); } return; } if((Shift == (TShiftState() << ssLeft << ssRight)) || (Shift == (TShiftState() << ssLeft << ssRight)) || (Shift == (TShiftState() << ssMiddle)) || (Shift == (TShiftState() << ssLeft << ssMiddle)) || (Shift == (TShiftState() << ssRight << ssMiddle))) { UnpressAndInvalidate(); for(int i=-1; i<=1; i++) for(int j=-1; j<=1; j++) if(CheckFieldBounds(ACol+i, ARow+j) && ((CellState[ACol+i][ARow+j].CellState == csClosed) || (CellState[ACol+i][ARow+j].CellState == csQuestionMarked))) { AddPressedCell(ACol+i, ARow+j); InvalidateCell(ACol+i, ARow+j); } } } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::MouseUpHandler(System::TObject* Sender, Controls::TMouseButton Button, Classes::TShiftState Shift, int X, int Y) { int ACol, ARow; SetCaptureControl(NULL); MouseToCell(X, Y, ACol, ARow); if((ACol == - 1) || (ARow == -1)) return; if(((Shift == (TShiftState() << ssLeft)) && (Button == mbRight)) || ((Shift == (TShiftState() << ssRight)) && (Button == mbLeft)) || (Button == mbMiddle)) { FireImageChanged(imSmile); FSurprised = false; UnpressAndInvalidate(); if(CellState[ACol][ARow].CellState == csOpened) FireMinerFieldEvent(ACol, ARow, meCheckSurround); return; }; if(Button == mbLeft) { FireImageChanged(imSmile); FSurprised = false; if(IsExistsInArray(FPressedCells, ACol, ARow)) { // BeginUpdate(); FireMinerFieldEvent(ACol, ARow, meOpenCell); // EndUpdate(); UnpressAndInvalidate(); }; return; }; if(Button == mbRight) UnpressAndInvalidate(); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::HandleEvMinerFieldChanged(System::TObject* Sender, TCells &AChangedCells, TCells &ARedCells) { InvalidateCells(AChangedCells, ARedCells); // AChangedCells.Length = 0; // ARedCells.Length = 0; } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::HandleEvGameStatusChanged(System::TObject* Sender, TGameStatus AGameStatus, const TGameDifficulty &AGameDifficulty, TCells &AChangedCells, TCells &ARedCells) { switch (AGameStatus) { case gsNew: { FGameStatus = gsNew; FGameDifficulty = AGameDifficulty; InitNewGame(); }; break; case gsRun: FGameStatus = gsRun; break; case gsLost: { FGameStatus = gsLost; UpdateMinerFieldState(ARedCells); InvalidateCells(AChangedCells, ARedCells); Views[0]->Painter->Invalidate(); Enabled = false; }; break; case gsWon: { FGameStatus = gsWon; UpdateMinerFieldState(ARedCells); InvalidateCells(AChangedCells, ARedCells); Views[0]->Painter->Invalidate(); Enabled = false; }; break; }; ARedCells.Length = 0; AChangedCells.Length = 0; FireGameStatusChanged(Sender, AGameStatus, AGameDifficulty); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::SetColorScheme(const UnboundModeDemoTypesH::TColorScheme Value) { FColorScheme = Value; SetSchemeColors(); Views[0]->Painter->Invalidate(); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::SetNumberColors(void) { FSurroundColors.Length = 8; FSurroundColors[0] = clBlue; FSurroundColors[1] = clGreen; FSurroundColors[2] = clRed; FSurroundColors[3] = clNavy; FSurroundColors[4] = clPurple; FSurroundColors[5] = clBlue; FSurroundColors[6] = clBlue; FSurroundColors[7] = clGray; } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::FireMinerFieldEvent(int ACol, int ARow, TMinerFieldActionEventType AMinerFieldActionEventType) { if(FOnMinerFieldAction != NULL) FOnMinerFieldAction(this, ACol, ARow, AMinerFieldActionEventType); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::FireNewGameEvent(void) { if(FCreateNewGameEvent != NULL) FCreateNewGameEvent(this); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::FireImageChanged(int AImageIndex) { if(FOnImageChanged != NULL) FOnImageChanged(this, AImageIndex); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::FireSetMineCountEvent(TMineCountChangedEventType AMineCountChangedEventType) { if(FMineCountChanged != NULL) FMineCountChanged(this, AMineCountChangedEventType); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::FireGameStatusChanged(System::TObject* Sender, TGameStatus AGameStatus, const TGameDifficulty &AGameDifficulty) { if(FGameStatusChanged != NULL) FGameStatusChanged(Sender, AGameStatus, AGameDifficulty); } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::MouseToCell(int X, int Y, int &ACol, int &ARow) { TcxCustomGridHitTest* AHitTest; ACol = -1; ARow = -1; AHitTest = ViewInfo->GetHitTest(X, Y); if(dynamic_cast(AHitTest)) { ACol = ((TcxGridRecordCellHitTest*)AHitTest)->Item->Index; ARow = ((TcxGridRecordCellHitTest*)AHitTest)->GridRecord->Index; } } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::CustomDrawCellHandler(Cxgridcustomtableview::TcxCustomGridTableView* Sender, Cxgraphics::TcxCanvas* ACanvas, Cxgridcustomtableview::TcxGridTableDataCellViewInfo* AViewInfo, bool &ADone) { TCellStateRec CellRec; int ACol = AViewInfo->Item->Index; int ARow = AViewInfo->RecordViewInfo->Index; TRect DrawRect = AViewInfo->Bounds; int vType = VarType(AViewInfo->Value); if((vType == varEmpty) || (vType == varNull)) return; CellRec = *(PCellStateRec)(int)AViewInfo->Value; DrawCell(CellRec, ACol, ARow, DrawRect, ACanvas->Canvas); ADone = true; } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::SetGridViewOptions(TcxGridTableView* GridView) { GridView->OptionsData->Editing = false; GridView->OptionsData->Inserting = false; GridView->OptionsData->Deleting = false; GridView->OptionsView->GroupByBox = false; GridView->OptionsView->GridLines = glNone; GridView->OptionsView->FocusRect = false; GridView->OptionsSelection->CellSelect = false; GridView->OptionsSelection->HideSelection = false; GridView->OptionsSelection->InvertSelect = false; GridView->OptionsView->Header = false; } //--------------------------------------------------------------------------- __fastcall TIntMinerField::TIntMinerField(Classes::TComponent* AOwner, TMinerField* AMinerField) : TcxCustomGrid(AOwner) { LookAndFeel->NativeStyle = false; TcxGridTableView* GridView = (TcxGridTableView*)CreateView(__classid(TcxGridTableViewNoScrollBars)); TcxGridLevel* Level = Levels->Add(); Level->GridView = GridView; FMinerFieldDataSource = new TMinerFieldDataSource(); MinerField = AMinerField; MinerField->OnMinerFieldChanged = FMinerFieldDataSource->HandleEvMinerFieldChanged; MinerField->OnGameStatusChanged = FMinerFieldDataSource->HandleEvGameStatusChanged; FMinerFieldDataSource->OnMinerFieldChanged = HandleEvMinerFieldChanged; FMinerFieldDataSource->OnGameStatusChanged = HandleEvGameStatusChanged; GridView->DataController->CustomDataSource = FMinerFieldDataSource; SetGridViewOptions(GridView); GridView->OnCustomDrawCell = CustomDrawCellHandler; GridView->OnMouseDown = MouseDownHandler; GridView->OnMouseUp = MouseUpHandler; GridView->OnMouseMove = MouseMoveHandler; OnMinerFieldAction = MinerField->HandleMinerFieldActionEvent; FCellWidth = GridView->ViewInfo->RecordsViewInfo->RowHeight; FColorScheme = csBlue; SetNumberColors(); SetSchemeColors(); } //--------------------------------------------------------------------------- __fastcall TIntMinerField::~TIntMinerField(void) { FOnMinerFieldAction = NULL; FMineCountChanged = NULL; FOnImageChanged = NULL; FGameStatusChanged = NULL; FPressedCells.Length = 0; FRedCells.Length = 0; delete FMinerFieldDataSource; } //--------------------------------------------------------------------------- void __fastcall TIntMinerField::CreateNewGame(void) { FireNewGameEvent(); InitNewGame(); } //--------------------------------------------------------------------------- TMetaClass* __fastcall TcxGridTableViewNoScrollBars::GetControllerClass(void) { return(__classid(TcxGridTableControllerNoScrollBars)); } //--------------------------------------------------------------------------- void __fastcall TcxGridTableControllerNoScrollBars::InitScrollBarsParameters(void) { } //---------------------------------------------------------------------------