home *** CD-ROM | disk | FTP | other *** search
- {************************************************}
- { }
- { ObjectWindows Chess Demo }
- { Board managment unit }
- { Copyright (c) 1992 by Borland International }
- { }
- {************************************************}
-
- unit OWBoard;
-
- interface
-
- uses WinProcs, WinTypes, Objects, OWindows, ODialogs, OWChPiec, ChessDll,
- OWChDlgs, OWConst;
-
- type
- PChessBoard = ^TChessBoard;
- TChessBoard = object(TWindow)
- Game: HChess;
- Squares: array [1..8,1..8] of PChessPiece;
- Pieces: TCollection;
- BoardBitmap: HBitmap;
- WhiteColor: TColorRef;
- BlackColor: TColorRef;
- WhiteBrush: HBrush;
- BlackBrush: HBrush;
- SquareWidth: Word;
- Dragger: PChessPiece; { if <> nil, we're dragging it }
- QSquare: TLocation; { if <> (0,0), we're in right-click query }
- BoardDC, DragDC: HDC;
- BoardOldBM, DragBM : HBitmap;
- ValidMoves,
- OpponentMoves,
- ScratchMoves: array [0..(28*16+1)] of TMove;
- CoverDlg: PCoverDlg;
- GameOver: Boolean;
- { Setup and shutdown }
- constructor Init(AParent: PWindowsObject; GH: HChess);
- destructor Done; virtual;
- function GetClassName: PChar; virtual;
- procedure GetWindowClass(var WC: TWndClass); virtual;
- procedure ResetBoard(GH: HChess);
- procedure SetGameOver(IsOver: Boolean);
-
- { Board display }
- function IdealWidth: Word;
- procedure InitBoardBitmap;
- procedure DrawBoard;
- procedure DrawValidMoves(DC: HDC);
- procedure Paint(DC: HDC; var PS: TPaintStruct); virtual;
- procedure WMEraseBkgnd(var Msg: TMessage);
- virtual wm_First + wm_EraseBkgnd;
- procedure WMSize(var Msg: TMessage);
- virtual wm_First + wm_Size;
- procedure Cover(DoIt: Boolean);
-
- { Conversions }
- function PieceFromPoint(Pt: TPoint): PChessPiece;
- procedure SquareFromPoint(Pt: TPoint; var Sq: TLocation);
- procedure SquareToRect(Sq: TLocation; var R: TRect);
-
- { Piece management }
- procedure InsertPiece(Sq: TLocation; P: PChessPiece);
- function RemovePiece(Sq: TLocation): PChessPiece;
- procedure ExecuteMove(const Move: TMove);
- procedure RetractMove(const Move: TMove);
- procedure ResetValidMoves;
-
- { Piece dragging routines }
- procedure CancelDrag;
- procedure WMSetCursor(var Msg: TMessage);
- virtual wm_First + wm_SetCursor;
- procedure WMLButtonDown(var Msg: TMessage);
- virtual wm_First + wm_LButtonDown;
- procedure WMMouseMove(var Msg: TMessage);
- virtual wm_First + wm_MouseMove;
- procedure WMLButtonUp(var Msg: TMessage);
- virtual wm_First + wm_LButtonUp;
-
- { Right mouse queries valid moves to square or of piece }
- procedure WMRButtonDown(var Msg: TMessage);
- virtual wm_First + wm_RButtonDown;
- procedure WMRButtonUp(var Msg: TMessage);
- virtual wm_First + wm_RButtonUp;
- end;
-
- PBoardFrame = ^TBoardFrame;
- TBoardFrame = object(TWindow)
- Board: PChessBoard;
- FrameWidth: Integer;
- FontWidth, FontHeight: Integer;
- constructor Init(AParent: PWindowsObject; ABoard: PChessBoard);
- function GetClassName: PChar; virtual;
- procedure GetWindowClass(var WC: TWndClass); virtual;
- procedure SetupWindow; virtual;
- function IdealWidth: Integer;
- procedure Paint(DC: HDC; var PS: TPaintStruct); virtual;
- procedure WMMove(var Msg: TMessage);
- virtual wm_First + wm_Move;
- procedure WMSize(var Msg: TMessage);
- virtual wm_First + wm_Size;
- end;
-
- function OtherPlayer(Color: TColor): TColor;
-
- implementation
-
- uses OWUtils, Strings, BWCC;
-
- function OtherPlayer(Color: TColor): TColor;
- begin
- if Color = cWhite then
- OtherPlayer := cBlack
- else
- OtherPlayer := cWhite;
- end;
-
- constructor TChessBoard.Init(AParent: PWindowsObject; GH: HChess);
- begin
- inherited Init(AParent, nil);
- with Attr do
- begin
- X := 0;
- Y := 0;
- W := 200;
- H := 200;
- Style := ws_Child or ws_ClipChildren{or ws_Border};
- { NOT ws_Visible - the parent window will resize us }
- { to the ideal width and then show us. }
- end;
- BoardBitmap := 0;
- DragDC := 0;
- BoardDC := CreateMemoryDC;
- Dragger := nil;
- GameOver := False;
- Word(QSquare) := 0;
- WhiteColor := XApp^.GetAppProfileRGB(
- 'Board','WhiteColor',RGB(255,255,255));
- WhiteBrush := CreateSolidBrush(WhiteColor);
- BlackColor := XApp^.GetAppProfileRGB(
- 'Board','BlackColor',RGB(255,0,0));
- BlackBrush := CreateSolidBrush(BlackColor);
- Pieces.Init(32, 4); { Growth allows for edited boards with > 32 pieces }
- ResetBoard(GH);
- CoverDlg := New(PCoverDlg, Init(@Self, PChar(dlgCoverBoard)));
- if not ChessSettings.CoverBoard then
- CoverDlg^.Lock;
- end;
-
- destructor TChessBoard.Done;
- var
- Temp: array [0..15] of Char;
- begin
- inherited Done;
- Pieces.Done;
- if BoardDC <> 0 then
- begin
- SelectObject(BoardDC, BoardOldBM);
- DeleteDC(BoardDC);
- end;
- if DragDC <> 0 then
- begin
- DeleteObject(SelectObject(DragDC, DragBM));
- DeleteDC(DragDC);
- end;
- if BoardBitmap <> 0 then
- DeleteObject(BoardBitmap);
- DeleteObject(WhiteBrush);
- DeleteObject(BlackBrush);
- XApp^.WriteAppProfileRGB('Board','WhiteColor',WhiteColor);
- XApp^.WriteAppProfileRGB('Board','BlackColor',BlackColor);
- end;
-
- function TChessBoard.GetClassName: PChar;
- begin
- GetClassName := 'TPWOWLChessBoard';
- end;
-
- procedure TChessBoard.GetWindowClass(var WC: TWndClass);
- begin
- inherited GetWindowClass(WC);
- WC.Style := cs_ByteAlignWindow;
- WC.hCursor := 0;
- end;
-
- procedure TChessBoard.ResetBoard(GH: HChess);
- procedure DoResize(P : PChessPiece); far;
- var
- R: TRect;
- S: TLocation;
- begin
- P^.GetSquare(S);
- SquareToRect(S, R);
- P^.SetRect(R);
- end;
- var
- TempBoard: TBoard;
- Square: TLocation;
- begin
- Game := GH;
- Pieces.FreeAll;
- FillChar(Squares, SizeOf(Squares), 0);
-
- GetBoard(Game, TempBoard);
-
- SquareWidth := Attr.W div 8;
- for Square.X := 1 to 8 do
- for Square.Y := 1 to 8 do
- if (TempBoard[Square.X, Square.Y].Piece <> pEmpty) then
- begin
- Squares[Square.X,Square.Y] := New(PChessPiece,
- Init(@Self, TempBoard[Square.X, Square.Y], Square));
- Pieces.Insert(Squares[Square.X,Square.Y]);
- end;
- ResetValidMoves;
- GameOver := False;
- if HWindow <> 0 then
- begin
- Pieces.ForEach(@DoResize);
- DrawBoard;
- InvalidateRect(HWindow, nil, False);
- end;
- end;
-
- procedure TChessBoard.SetGameOver(IsOver: Boolean);
- begin
- if GameOver <> IsOver then
- begin
- GameOver := IsOver;
- DrawBoard;
- InvalidateRect(HWindow, nil, False);
- end;
- end;
-
- function TChessBoard.IdealWidth: Word;
- var
- Best: Word;
- procedure CheckBitmapSize(P: PChessPiece); far;
- begin
- if Best < P^.BitSize.X then Best := P^.BitSize.X;
- if Best < P^.BitSize.Y then Best := P^.BitSize.Y;
- end;
- begin
- Best := 0;
- Pieces.ForEach(@CheckBitmapSize);
- IdealWidth := (Best + 4) * 8;
- end;
-
- procedure TChessBoard.InitBoardBitmap;
- var
- DC: HDC;
- begin
- if BoardBitmap <> 0 then
- begin
- SelectObject(BoardDC, BoardOldBM);
- DeleteObject(BoardBitmap);
- end;
-
- DC := GetDC(HWindow);
- BoardBitmap := CreateCompatibleBitmap(DC, Attr.W, Attr.H);
- ReleaseDC(HWindow, DC);
- BoardOldBM := SelectObject(BoardDC, BoardBitmap);
- SquareWidth := Attr.W div 8;
- end;
-
- procedure TChessBoard.DrawBoard;
- var
- OldBrush, SquareBrush : HBrush;
- X, Y: Integer;
- OldFont: HFont;
- LF: TLogFont;
-
- procedure DoPaint(P: PChessPiece); far;
- begin
- P^.Paint(BoardDC);
- end;
-
- begin
- OldBrush := SelectObject(BoardDC, WhiteBrush);
- PatBlt(BoardDC, 0, 0, Attr.W, Attr.H, PatCopy);
-
- SelectObject(BoardDC, BlackBrush);
- for Y := 0 to 7 do
- for X := 0 to 7 do
- if Odd(X + Y) then
- PatBlt(BoardDC, X * SquareWidth, Y * SquareWidth,
- SquareWidth, SquareWidth, PatCopy);
-
- if GameOver then
- begin
- SaveDC(BoardDC);
- SetBkMode(BoardDC, Transparent);
- SetTextColor(BoardDC, RGB(128,128,128));
- FillChar(LF, SizeOf(LF), 0);
- with LF do
- begin
- lfHeight := SquareWidth * 2;
- lfWidth := SquareWidth;
- lfWeight := FW_Bold;
- lfOutPrecision := out_Character_Precis;
- lfQuality := Proof_Quality;
- if LoWord(GetVersion) = $0003 then
- StrCopy(lfFaceName, 'Tms Rmn')
- else
- StrCopy(lfFaceName, 'Times New Roman');
- end;
- OldFont := SelectObject(BoardDC, CreateFontIndirect(LF));
- TextOut(BoardDC,
- Attr.W div 2 - LoWord(GetTextExtent(BoardDC, 'GAME', 4)) div 2,
- SquareWidth * 2, 'GAME', 4);
- TextOut(BoardDC,
- Attr.W div 2 - LoWord(GetTextExtent(BoardDC, 'OVER', 4)) div 2,
- SquareWidth * 4, 'OVER', 4);
- DeleteObject(SelectObject(BoardDC, OldFont));
- RestoreDC(BoardDC, -1);
- end;
-
- SelectObject(BoardDC, OldBrush);
- Pieces.ForEach(@DoPaint);
- end;
-
- { Because of the way the board paints from a memory bitmap, we don't
- need the window to erase the background before we paint. }
- procedure TChessBoard.WMEraseBkgnd(var Msg: TMessage);
- begin
- Msg.Result := 1;
- end;
-
- procedure TChessBoard.DrawValidMoves(DC: HDC);
-
- procedure TestAndInvert(Test, Show: TLocation);
- var
- R: TRect;
- begin
- if Word(Test) = Word(QSquare) then
- begin
- SquareToRect(Show, R);
- InvertRect(DC, R);
- end;
- end;
-
- var
- X : Integer;
- begin
- if Squares[QSquare.X, QSquare.Y] <> nil then
- { Show where this piece can move to }
- begin
- X := 0;
- while (X <= High(ValidMoves)) and
- (ValidMoves[X].Change.Piece <> pEmpty) do
- begin
- with ValidMoves[X].Change do
- TestAndInvert(Source, Dest);
- Inc(X);
- end;
- X := 0;
- while (X <= High(ValidMoves)) and
- (OpponentMoves[X].Change.Piece <> pEmpty) do
- begin
- with OpponentMoves[X].Change do
- TestAndInvert(Source, Dest);
- Inc(X);
- end;
- end
- else
- { Show what pieces can move to this square }
- begin
- X := 0;
- while (X <= High(ValidMoves)) and
- (ValidMoves[X].Change.Piece <> pEmpty) do
- begin
- with ValidMoves[X].Change do
- TestAndInvert(Dest, Source);
- Inc(X);
- end;
- X := 0;
- while (X <= High(OpponentMoves)) and
- (OpponentMoves[X].Change.Piece <> pEmpty) do
- begin
- with OpponentMoves[X].Change do
- TestAndInvert(Dest, Source);
- Inc(X);
- end;
- end;
- end;
-
-
- procedure TChessBoard.Paint(DC: HDC; var PS: TPaintStruct);
- procedure CheckPieces(P: PChessPiece); far;
- var
- Sq: TLocation;
- OldBrush: HBrush;
- begin
- if P^.NeedRedraw then
- begin
- P^.GetSquare(Sq);
- if Odd(Sq.X + Sq.Y) then
- OldBrush := SelectObject(BoardDC, WhiteBrush)
- else
- OldBrush := SelectObject(BoardDC, BlackBrush);
- with P^.Rect do
- PatBlt(BoardDC, Left, Top, Right - Left, Bottom - Top, PatCopy);
- SelectObject(BoardDC, OldBrush);
- P^.Paint(BoardDC);
- end;
- end;
- begin
- Pieces.ForEach(@CheckPieces);
- with PS.rcPaint do
- BitBlt(DC, Left, Top, Right - Left, Bottom - Top,
- BoardDC, Left, Top, SrcCopy);
- if Dragger <> nil then
- Dragger^.Paint(DC);
- if Word(QSquare) <> 0 then
- DrawValidMoves(DC);
- end;
-
- procedure TChessBoard.WMSize(var Msg: TMessage);
-
- procedure DoResize(P : PChessPiece); far;
- var
- R: TRect;
- S: TLocation;
- begin
- P^.GetSquare(S);
- SquareToRect(S, R);
- P^.SetRect(R);
- end;
-
- begin
- inherited WMSize(Msg);
- SquareWidth := Attr.W div 8;
- InitBoardBitmap;
- Pieces.ForEach(@DoResize);
- DrawBoard;
- if CoverDlg^.HWindow <> 0 then
- SetWindowPos(CoverDlg^.HWindow, 0, SquareWidth div 2,
- SquareWidth div 2,
- Attr.W - SquareWidth,
- Attr.H - SquareWidth,
- swp_NoActivate or swp_NoZOrder);
- end;
-
- procedure TChessBoard.Cover(DoIt: Boolean);
- begin
- if(CoverDlg <> nil) and
- (CoverDlg^.HWindow <> 0) then
- if DoIt then
- CoverDlg^.Show(sw_Show)
- else
- CoverDlg^.Show(sw_Hide);
- end;
-
- function TChessBoard.PieceFromPoint(Pt: TPoint): PChessPiece;
- function DoHitTest(P: PChessPiece): Boolean; far;
- begin
- DoHitTest := P^.HitTest(Pt);
- end;
- begin
- PieceFromPoint := PChessPiece(Pieces.FirstThat(@DoHitTest));
- end;
-
- procedure TChessBoard.SquareFromPoint(Pt: TPoint; var Sq: TLocation);
- var
- Temp: Shortint;
- begin
- Temp := (Pt.X div SquareWidth) + 1;
- if Temp in [1..8] then
- Sq.X := Temp
- else
- begin
- Word(Sq) := 0;
- Exit;
- end;
- Temp := (Attr.H - Pt.Y) div SquareWidth + 1;
- if Temp in [1..8] then
- Sq.Y := Temp
- else
- Word(Sq) := 0;
- end;
-
- procedure TChessBoard.SquareToRect(Sq: TLocation; var R: TRect);
- begin
- R.Left := (Sq.X - 1) * SquareWidth;
- R.Right := R.Left + SquareWidth;
- R.Top := Attr.H - (Sq.Y * SquareWidth);
- R.Bottom := R.Top + SquareWidth;
- end;
-
- procedure TChessBoard.ExecuteMove(const Move: TMove);
-
- function CreatePromote(P: TPiece; Dest: TLocation): PChessPiece;
- var { This function creates the piece specified by }
- X: TSquare; { P using color info from the piece already on }
- begin { on the board at Dest. This is for }
- X.Piece := P; { Pawn Promotion moves only. }
- X.Color := Squares[Dest.X, Dest.Y]^.Color;
- InsertPiece(Dest, New(PChessPiece, Init(@Self, X, Dest)));
- end;
-
- begin
- if Move.Change.Piece = pEmpty then Exit;
- with Move, Move.Change do
- begin
- InsertPiece(Dest, RemovePiece(Source)); { Also deletes what's at dest }
- case Move.Kind of
- kEnPassant : Dispose(RemovePiece(EPCapture), Done);
- kCastling : InsertPiece(RookDest, RemovePiece(RookSource));
- kPawnPromote: CreatePromote(Piece, Dest);
- end;
- end;
- end;
-
- procedure TChessBoard.RetractMove(const Move: TMove);
- procedure CreatePiece(P: TPiece; Color: Boolean; Dest: TLocation);
- var
- X: TSquare;
- begin
- X.Piece := P;
- X.Color := TColor(Color);
- InsertPiece(Dest, New(PChessPiece, Init(@Self, X, Dest)));
- end;
- var
- Color: Boolean; { Color of opponent }
- begin
- if Move.Change.Piece = pEmpty then Exit;
- with Move, Move.Change do
- begin
- Color := not Boolean(Squares[Dest.X, Dest.Y]^.Color);
- InsertPiece(Source, RemovePiece(Dest)); {Back out of destination }
- case Move.Kind of
- kNormal : if Capture then CreatePiece(Contents, Color, Dest);
- kEnPassant : CreatePiece(Contents, Color, EPCapture);
- kCastling : InsertPiece(RookSource, RemovePiece(RookDest));
- kPawnPromote:
- begin
- if Capture then CreatePiece(Contents, not Color, Dest);
- CreatePiece(pPawn, Color, Source);
- end;
- end;
- end;
- end;
-
-
- procedure TChessBoard.ResetValidMoves;
- var
- Chg: TChange;
- PlayerColor: TColor;
- EmptyMove: TMove;
-
- procedure DoValids(P : PChessPiece); far;
- begin
- if P^.Color = PlayerColor then
- P^.ResetValidMoves(ValidMoves) { piece gets its moves from list }
- else
- begin
- P^.ResetValidMoves(EmptyMove); { clear opponent's move lists }
- if ChessSettings.ShowAttacks then
- P^.CheckJeopardy(ValidMoves)
- else
- P^.CheckJeopardy(EmptyMove);
- end;
- end;
-
- procedure DoJeopardies(P : PChessPiece); far;
- begin
- if P^.Color = PlayerColor then
- P^.CheckJeopardy(OpponentMoves);
- end;
-
- begin
- Chg.Piece := pEmpty;
- Word(Chg.Source) := 0;
- Word(Chg.Dest) := 0;
- FillChar(EmptyMove, SizeOf(EmptyMove), 0);
- PlayerColor := GetPlayer(Game);
- if ChessSettings.ShowJeopardies or
- ChessSettings.RightClickHints then
- begin
- { Switch players to see which opponent pieces attack ours }
- SetPlayer(Game, OtherPlayer(PlayerColor));
- GetValidMoves(Game, Chg, OpponentMoves);
- SetPlayer(Game, PlayerColor);
- if ChessSettings.ShowJeopardies then
- Pieces.ForEach(@DoJeopardies);
- end
- else
- begin
- OpponentMoves[0] := EmptyMove; { Clear the jeopardy lists }
- Pieces.ForEach(@DoJeopardies);
- end;
- { Now see what moves our pieces can make }
- GetValidMoves(Game, Chg, ValidMoves);
- Pieces.ForEach(@DoValids);
- end;
-
- procedure TChessBoard.WMSetCursor(var Msg: TMessage);
- var
- P: TPoint;
- X: PChessPiece;
- begin
- DefWndProc(Msg);
- if Msg.Result = 0 then
- begin
- GetCursorPos(P);
- ScreenToClient(HWindow, P);
- X := PieceFromPoint(P);
- if (X <> nil) and X^.CanDrag and (not GameOver) then
- SetCursor(X^.GetCursor)
- else
- SetCursor(LoadCursor(0, PChar(idc_Arrow)));
- end;
- end;
-
- procedure TChessBoard.CancelDrag;
- var
- NewSq, OldSq : TLocation;
- P: TPoint;
- Chg: TChange;
- R: TRect;
- begin
- if Dragger <> nil then
- begin
- Word(NewSq) := 0; { 0,0 = off board or invalid }
- Longint(P) := 0;
- R := Dragger^.Rect;
- Dragger^.GetSquare(OldSq);
- Dragger^.DragEnd(DragDC, P, NewSq, Chg);
- InvalidateRect(HWindow, @R, False);
- InsertPiece(OldSq, Dragger); { Go back to original square }
- Dragger := nil;
- ReleaseCapture;
- DeleteObject(SelectObject(DragDC, DragBM));
- DeleteDC(DragDC);
- DragDC := 0;
- end;
- end;
-
- procedure TChessBoard.WMLButtonDown(var Msg: TMessage);
- var
- R: TRect;
- Sq: TLocation;
- DC: HDC;
- begin
- if (Dragger = nil) and not GameOver then
- begin
- Dragger := PieceFromPoint(TPoint(Msg.LParam));
- if (Dragger <> nil) then
- if Dragger^.CanDrag then
- begin
- Dragger^.GetSquare(Sq);
- RemovePiece(Sq);
- UpdateWindow(HWindow);
- SetCapture(HWindow);
- DC := GetDC(HWindow);
- DragDC := CreateCompatibleDC(DC);
- DragBM := SelectObject(DragDC,
- CreateCompatibleBitmap(DC, Attr.W, Attr.H));
- BitBlt(DragDC, 0, 0, Attr.W, Attr.H, BoardDC, 0, 0, SrcCopy);
- R := Dragger^.Rect;
- Dragger^.DragBegin(DragDC, TPoint(Msg.LParam));
- UnionRect(R, R, Dragger^.Rect);
- with R do
- BitBlt(DC, Left, Top, Right - Left, Bottom - Top,
- DragDC, Left, Top, SrcCopy);
- ReleaseDC(HWindow, DC);
- end
- else
- begin
- Dragger := nil;
- MessageBeep(0);
- end;
- end;
- DefWndProc(Msg);
- end;
-
- procedure TChessBoard.WMMouseMove(var Msg: TMessage);
- var
- R: TRect;
- Sq: TLocation;
- DC: HDC;
- begin
- if not GameOver then
- if Dragger <> nil then
- begin
- GetClientRect(HWindow, R);
- if PtInRect(R, TPoint(Msg.LParam)) then
- begin
- SquareFromPoint(TPoint(Msg.LParam), Sq);
- with Dragger^.Rect do
- BitBlt(DragDC, Left, Top, Right - Left, Bottom - Top,
- BoardDC, Left, Top, SrcCopy);
- R := Dragger^.Rect;
- Dragger^.DragContinue(DragDC, TPoint(Msg.LParam), Sq);
- UnionRect(R, R, Dragger^.Rect);
- DC := GetDC(HWindow);
- with R do
- BitBlt(DC, Left, Top, Right - Left, Bottom - Top,
- DragDC, Left, Top, SrcCopy);
- ReleaseDC(HWindow, DC);
- end
- else
- begin
- Dragger^.DragHide;
- InvalidateRect(HWindow, @Dragger^.Rect, False);
- SetCursor(LoadCursor(HInstance, PChar(curNo)));
- end;
- end;
- if Word(QSquare) <> 0 then
- begin
- Sq := QSquare;
- GetClientRect(HWindow, R);
- if PtInRect(R, TPoint(Msg.LParam)) then
- SquareFromPoint(TPoint(Msg.LParam), QSquare)
- else
- Word(QSquare) := 0;
- if Word(Sq) <> Word(QSquare) then
- InvalidateRect(HWindow, nil, False);
- end;
- DefWndProc(Msg);
- end;
-
- procedure TChessBoard.WMLButtonUp(var Msg: TMessage);
- var
- NewSq, OldSq: TLocation;
- R: TRect;
- Chg: TChange;
- ValidMove: Boolean;
- PlayerColor : TColor;
- Error : TChessError;
- begin
- if Dragger <> nil then
- begin
- GetClientRect(HWindow, R);
- with Dragger^.Rect do
- BitBlt(DragDC, Left, Top, Right - Left, Bottom - Top,
- BoardDC, Left, Top, SrcCopy);
- if PtInRect(R, TPoint(Msg.LParam)) then
- SquareFromPoint(TPoint(Msg.LParam), NewSq)
- else
- begin
- NewSq.X := 0; { 0 = off board or invalid }
- NewSq.Y := 0;
- end;
- R := Dragger^.Rect;
- Dragger^.GetSquare(OldSq);
- ValidMove := Dragger^.DragEnd(DragDC, TPoint(Msg.LParam), NewSq, Chg);
- InvalidateRect(HWindow, @R, False);
- InsertPiece(OldSq, Dragger); { Go back to original square }
- ReleaseCapture;
- DeleteObject(SelectObject(DragDC, DragBM));
- DeleteDC(DragDC);
- DragDC := 0;
- if ValidMove and Dragger^.NeedPawnPromote then
- begin
- CoverDlg^.Lock;
- SendMessage(Parent^.HWindow, am_ChoosePawnPromote, 0, Longint(@Chg));
- CoverDlg^.UnLock;
- end;
- Dragger := nil;
- { am_SubmitMove will return a boolean accept/reject response }
- if ValidMove and
- LongBool(SendMessage(Parent^.HWindow, am_SubmitMove, 0, Longint(@Chg))) then
- begin
- { Update the pieces to reflect the attacks of the moved piece in
- its new position. }
- ResetValidMoves;
- end;
- UpdateWindow(HWindow);
- end;
- DefWndProc(Msg);
- end;
-
- procedure TChessBoard.InsertPiece(Sq: TLocation; P: PChessPiece);
- var
- R: TRect;
- begin
- if Squares[Sq.X,Sq.Y] = P then Exit;
- if (Squares[Sq.X,Sq.Y] <> nil) then
- Dispose(RemovePiece(Sq), Done);
- Pieces.Insert(P);
- P^.SetSquare(Sq);
- Squares[Sq.X, Sq.Y] := P;
- SquareToRect(Sq, R);
- P^.SetRect(R);
- P^.Paint(BoardDC);
- InvalidateRect(HWindow, @R, False);
- end;
-
- function TChessBoard.RemovePiece(Sq: TLocation): PChessPiece;
- var
- OldBrush: HBrush;
- R: TRect;
- begin
- RemovePiece := nil;
- if Squares[Sq.X,Sq.Y] <> nil then
- begin
- RemovePiece := Squares[Sq.X,Sq.Y];
- Pieces.Delete(Squares[Sq.X,Sq.Y]);
- Squares[Sq.X,Sq.Y] := nil;
-
- if Odd(Sq.X + Sq.Y) then
- OldBrush := SelectObject(BoardDC, WhiteBrush)
- else
- OldBrush := SelectObject(BoardDC, BlackBrush);
- SquareToRect(Sq, R);
- with R do
- PatBlt(BoardDC, Left, Top, Right - Left, Bottom - Top, PatCopy);
- SelectObject(BoardDC, OldBrush);
- InvalidateRect(HWindow, @R, False);
- end;
- end;
-
- procedure TChessBoard.WMRButtonDown(var Msg: TMessage);
- var
- R: TRect;
- OldQ : TLocation;
- begin
- if ChessSettings.RightClickHints then
- begin
- OldQ := QSquare;
- GetClientRect(HWindow, R);
- if PtInRect(R, TPoint(Msg.LParam)) then
- SquareFromPoint(TPoint(Msg.LParam), QSquare)
- else
- Word(QSquare) := 0;
- if Word(OldQ) <> Word(QSquare) then
- InvalidateRect(HWindow, nil, False);
- SetCapture(HWindow);
- end;
- DefWndProc(Msg);
- end;
-
- procedure TChessBoard.WMRButtonUp(var Msg: TMessage);
- begin
- if ChessSettings.RightClickHints then
- begin
- if Word(QSquare) <> 0 then
- InvalidateRect(HWindow, nil, False);
- FillChar(QSquare, SizeOf(QSquare), 0);
- ReleaseCapture;
- end;
- DefWndProc(Msg);
- end;
-
-
- constructor TBoardFrame.Init(AParent: PWindowsObject;
- ABoard: PChessBoard);
- begin
- inherited Init(AParent, nil);
- Attr.Style := ws_Child or ws_ClipSiblings;
- Board := ABoard;
- FrameWidth := 5; { arbitrary - This will be calculated in SetupWindow }
- end;
-
- function TBoardFrame.GetClassName: PChar;
- begin
- GetClassName := 'TPWChessBoardFrame';
- end;
-
- procedure TBoardFrame.GetWindowClass(var WC: TWndClass);
- var
- LB: TLogBrush;
- begin
- inherited GetWindowClass(WC);
- with WC do
- begin
- Style := cs_ByteAlignWindow;
- GetObject(BWCCGetPattern, SizeOf(LB), @LB);
- hbrBackground := CreateBrushIndirect(LB);
- hCursor := 0;
- end;
- end;
-
- procedure TBoardFrame.SetupWindow;
- var
- DC : HDC;
- OldFont: HFont;
- TM: TTextMetric;
- begin
- inherited SetupWindow;
- DC := GetDC(0);
- OldFont := SelectObject(DC, GetStockObject(ANSI_Fixed_Font));
- GetTextMetrics(DC, TM);
- SelectObject(DC, OldFont);
- ReleaseDC(0, DC);
- FontWidth := TM.tmMaxCharWidth;
- FontHeight := TM.tmHeight;
- if FontWidth < FontHeight then
- FrameWidth := FontHeight
- else
- FrameWidth := FontWidth;
- Inc(FrameWidth);
- end;
-
- function TBoardFrame.IdealWidth: Integer;
- begin
- IdealWidth := FrameWidth * 2 + Board^.IdealWidth + 6;
- end;
-
- procedure TBoardFrame.Paint(DC: HDC; var PS: TPaintStruct);
- var
- X, Sq: Integer;
- S: array [0..2] of Char;
- Point: array [0..4] of TPoint;
- OldPen: HPen;
- R: TRect;
- begin
- GetClientRect(HWindow, R);
- {White}
- OldPen := SelectObject(DC, CreatePen(ps_Solid, 1, RGB(255,255,255)));
- FillChar(Point, SizeOf(Point), 0);
- Point[0].X := R.Right-1;
- Point[2].Y := R.Bottom;
- PolyLine(DC, Point, 3);
- Point[0].X := R.Right - FrameWidth - 1;
- Point[0].Y := FrameWidth + 1;
- Point[1].X := Point[0].X;
- Point[1].Y := Point[0].X;
- Point[2].X := FrameWidth + 1;
- Point[2].Y := Point[0].X;
- PolyLine(DC, Point, 3);
- {Neutral grey}
- DeleteObject(SelectObject(DC, CreatePen(ps_Solid, 2, RGB(192,192,192))));
- Point[0].X := R.Right - FrameWidth - 2;
- Point[0].Y := FrameWidth + 3;
- Point[1].X := Point[0].X;
- Point[1].Y := Point[0].X;
- Point[2].X := Point[0].Y - 1;
- Point[2].Y := Point[0].X;
- Point[3].X := Point[2].X;
- Point[3].Y := Point[2].X;
- Point[4].X := Point[0].X;
- Point[4].Y := Point[2].X;
- PolyLine(DC, Point, 5);
- {Dark grey}
- DeleteObject(SelectObject(DC, CreatePen(ps_Solid, 1, RGB(128,128,128))));
- Point[0].X := R.Right - FrameWidth - 2;
- Point[0].Y := FrameWidth;
- Point[1].X := Point[0].Y;
- Point[1].Y := Point[0].Y;
- Point[2].X := Point[0].Y;
- Point[2].Y := Point[0].X + 1;
- PolyLine(DC, Point, 3);
- Point[0].X := R.Right-1;
- Point[0].Y := 1;
- Point[1].X := R.Right-1;
- Point[1].Y := R.Bottom-1;
- Point[2].X := 0;
- Point[2].Y := R.Bottom-1;
- PolyLine(DC, Point, 3);
- DeleteObject(SelectObject(DC, OldPen));
- Sq := Board^.SquareWidth;
- SetBkMode(DC, Transparent);
- SetTextColor(DC, 0);
- S[1] := #0;
- for X := 0 to 7 do
- begin
- S[0] := Char(Ord('8')-X);
- TextOut(DC, FrameWidth div 2 - FontWidth div 2,
- FrameWidth + 2 + (X * Sq) + (Sq div 2 - FontHeight div 2),
- S, 1);
- S[0] := Char(Ord('A')+X);
- TextOut(DC, FrameWidth + (X*Sq) + (Sq div 2 - FontWidth div 2),
- FrameWidth + 4 + Sq*8 + FrameWidth div 2 - FontHeight div 2,
- S, 1);
- end;
- end;
-
- procedure TBoardFrame.WMMove(var Msg: TMessage);
- var
- P: TPoint;
- begin
- DefWndProc(Msg);
- P.X := FrameWidth + 3;
- P.Y := P.X;
- ClientToScreen(HWindow, P);
- ScreenToClient(Parent^.HWindow, P);
- SetWindowPos(Board^.HWindow,0,P.X,P.Y,0,0, swp_NoSize or swp_NoZOrder);
- end;
-
- procedure TBoardFrame.WMSize(var Msg: TMessage);
- var
- P: TPoint;
- begin
- DefWndProc(Msg);
- P.X := FrameWidth + 3;
- P.Y := P.X;
- ClientToScreen(HWindow, P);
- ScreenToClient(Parent^.HWindow, P);
- SetWindowPos(Board^.HWindow, 0, P.X, P.Y,
- LoWord(Msg.LParam) - 2 * (FrameWidth + 3),
- HiWord(Msg.LParam) - 2 * (FrameWidth + 3),
- swp_NoActivate or swp_NoZOrder);
- end;
-
- end.