home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l040 / 10.ddi / CHESS.ZIP / OWBOARD.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-10-27  |  27.1 KB  |  997 lines

  1. {************************************************}
  2. {                                                }
  3. {   ObjectWindows Chess Demo                     }
  4. {   Board managment unit                         }
  5. {   Copyright (c) 1992 by Borland International  }
  6. {                                                }
  7. {************************************************}
  8.  
  9. unit OWBoard;
  10.  
  11. interface
  12.  
  13. uses WinProcs, WinTypes, Objects, OWindows, ODialogs, OWChPiec, ChessDll,
  14.   OWChDlgs, OWConst;
  15.  
  16. type
  17.   PChessBoard = ^TChessBoard;
  18.   TChessBoard = object(TWindow)
  19.     Game: HChess;
  20.     Squares: array [1..8,1..8] of PChessPiece;
  21.     Pieces: TCollection;
  22.     BoardBitmap: HBitmap;
  23.     WhiteColor: TColorRef;
  24.     BlackColor: TColorRef;
  25.     WhiteBrush: HBrush;
  26.     BlackBrush: HBrush;
  27.     SquareWidth: Word;
  28.     Dragger: PChessPiece;    { if <> nil, we're dragging it }
  29.     QSquare: TLocation;      { if <> (0,0), we're in right-click query }
  30.     BoardDC, DragDC: HDC;
  31.     BoardOldBM, DragBM : HBitmap;
  32.     ValidMoves,
  33.     OpponentMoves,
  34.     ScratchMoves: array [0..(28*16+1)] of TMove;
  35.     CoverDlg: PCoverDlg;
  36.     GameOver: Boolean;
  37.     { Setup and shutdown }
  38.     constructor Init(AParent: PWindowsObject; GH: HChess);
  39.     destructor Done; virtual;
  40.     function  GetClassName: PChar; virtual;
  41.     procedure GetWindowClass(var WC: TWndClass); virtual;
  42.     procedure ResetBoard(GH: HChess);
  43.     procedure SetGameOver(IsOver: Boolean);
  44.  
  45.     { Board display }
  46.     function  IdealWidth: Word;
  47.     procedure InitBoardBitmap;
  48.     procedure DrawBoard;
  49.     procedure DrawValidMoves(DC: HDC);
  50.     procedure Paint(DC: HDC; var PS: TPaintStruct); virtual;
  51.     procedure WMEraseBkgnd(var Msg: TMessage);
  52.       virtual wm_First + wm_EraseBkgnd;
  53.     procedure WMSize(var Msg: TMessage);
  54.       virtual wm_First + wm_Size;
  55.     procedure Cover(DoIt: Boolean);
  56.  
  57.     { Conversions }
  58.     function  PieceFromPoint(Pt: TPoint): PChessPiece;
  59.     procedure SquareFromPoint(Pt: TPoint; var Sq: TLocation);
  60.     procedure SquareToRect(Sq: TLocation; var R: TRect);
  61.  
  62.     { Piece management }
  63.     procedure InsertPiece(Sq: TLocation; P: PChessPiece);
  64.     function  RemovePiece(Sq: TLocation): PChessPiece;
  65.     procedure ExecuteMove(const Move: TMove);
  66.     procedure RetractMove(const Move: TMove);
  67.     procedure ResetValidMoves;
  68.  
  69.     { Piece dragging routines }
  70.     procedure CancelDrag;
  71.     procedure WMSetCursor(var Msg: TMessage);
  72.       virtual wm_First + wm_SetCursor;
  73.     procedure WMLButtonDown(var Msg: TMessage);
  74.       virtual wm_First + wm_LButtonDown;
  75.     procedure WMMouseMove(var Msg: TMessage);
  76.       virtual wm_First + wm_MouseMove;
  77.     procedure WMLButtonUp(var Msg: TMessage);
  78.       virtual wm_First + wm_LButtonUp;
  79.  
  80.     { Right mouse queries valid moves to square or of piece }
  81.     procedure WMRButtonDown(var Msg: TMessage);
  82.       virtual wm_First + wm_RButtonDown;
  83.     procedure WMRButtonUp(var Msg: TMessage);
  84.       virtual wm_First + wm_RButtonUp;
  85.   end;
  86.  
  87.   PBoardFrame = ^TBoardFrame;
  88.   TBoardFrame = object(TWindow)
  89.     Board: PChessBoard;
  90.     FrameWidth: Integer;
  91.     FontWidth, FontHeight: Integer;
  92.     constructor Init(AParent: PWindowsObject; ABoard: PChessBoard);
  93.     function  GetClassName: PChar; virtual;
  94.     procedure GetWindowClass(var WC: TWndClass); virtual;
  95.     procedure SetupWindow; virtual;
  96.     function  IdealWidth: Integer;
  97.     procedure Paint(DC: HDC; var PS: TPaintStruct); virtual;
  98.     procedure WMMove(var Msg: TMessage);
  99.       virtual wm_First + wm_Move;
  100.     procedure WMSize(var Msg: TMessage);
  101.       virtual wm_First + wm_Size;
  102.   end;
  103.  
  104.   function OtherPlayer(Color: TColor): TColor;
  105.  
  106. implementation
  107.  
  108. uses OWUtils, Strings, BWCC;
  109.  
  110. function OtherPlayer(Color: TColor): TColor;
  111. begin
  112.   if Color = cWhite then
  113.     OtherPlayer := cBlack
  114.   else
  115.     OtherPlayer := cWhite;
  116. end;
  117.  
  118. constructor TChessBoard.Init(AParent: PWindowsObject; GH: HChess);
  119. begin
  120.   inherited Init(AParent, nil);
  121.   with Attr do
  122.   begin
  123.     X := 0;
  124.     Y := 0;
  125.     W := 200;
  126.     H := 200;
  127.     Style := ws_Child or ws_ClipChildren{or ws_Border};
  128.         { NOT ws_Visible - the parent window will resize us  }
  129.         { to the ideal width and then show us.               }
  130.   end;
  131.   BoardBitmap := 0;
  132.   DragDC := 0;
  133.   BoardDC := CreateMemoryDC;
  134.   Dragger := nil;
  135.   GameOver := False;
  136.   Word(QSquare) := 0;
  137.   WhiteColor := XApp^.GetAppProfileRGB(
  138.                        'Board','WhiteColor',RGB(255,255,255));
  139.   WhiteBrush := CreateSolidBrush(WhiteColor);
  140.   BlackColor := XApp^.GetAppProfileRGB(
  141.                        'Board','BlackColor',RGB(255,0,0));
  142.   BlackBrush := CreateSolidBrush(BlackColor);
  143.   Pieces.Init(32, 4);  { Growth allows for edited boards with > 32 pieces }
  144.   ResetBoard(GH);
  145.   CoverDlg := New(PCoverDlg, Init(@Self, PChar(dlgCoverBoard)));
  146.   if not ChessSettings.CoverBoard then
  147.     CoverDlg^.Lock;
  148. end;
  149.  
  150. destructor TChessBoard.Done;
  151. var
  152.   Temp: array [0..15] of Char;
  153. begin
  154.   inherited Done;
  155.   Pieces.Done;
  156.   if BoardDC <> 0 then
  157.   begin
  158.     SelectObject(BoardDC, BoardOldBM);
  159.     DeleteDC(BoardDC);
  160.   end;
  161.   if DragDC <> 0 then
  162.   begin
  163.     DeleteObject(SelectObject(DragDC, DragBM));
  164.     DeleteDC(DragDC);
  165.   end;
  166.   if BoardBitmap <> 0 then
  167.     DeleteObject(BoardBitmap);
  168.   DeleteObject(WhiteBrush);
  169.   DeleteObject(BlackBrush);
  170.   XApp^.WriteAppProfileRGB('Board','WhiteColor',WhiteColor);
  171.   XApp^.WriteAppProfileRGB('Board','BlackColor',BlackColor);
  172. end;
  173.  
  174. function  TChessBoard.GetClassName: PChar;
  175. begin
  176.   GetClassName := 'TPWOWLChessBoard';
  177. end;
  178.  
  179. procedure TChessBoard.GetWindowClass(var WC: TWndClass);
  180. begin
  181.   inherited GetWindowClass(WC);
  182.   WC.Style := cs_ByteAlignWindow;
  183.   WC.hCursor := 0;
  184. end;
  185.  
  186. procedure TChessBoard.ResetBoard(GH: HChess);
  187.   procedure DoResize(P : PChessPiece); far;
  188.   var
  189.     R: TRect;
  190.     S: TLocation;
  191.   begin
  192.     P^.GetSquare(S);
  193.     SquareToRect(S, R);
  194.     P^.SetRect(R);
  195.   end;
  196. var
  197.   TempBoard: TBoard;
  198.   Square: TLocation;
  199. begin
  200.   Game := GH;
  201.   Pieces.FreeAll;
  202.   FillChar(Squares, SizeOf(Squares), 0);
  203.  
  204.   GetBoard(Game, TempBoard);
  205.  
  206.   SquareWidth := Attr.W div 8;
  207.   for Square.X := 1 to 8 do
  208.     for Square.Y := 1 to 8 do
  209.       if (TempBoard[Square.X, Square.Y].Piece <> pEmpty) then
  210.       begin
  211.         Squares[Square.X,Square.Y] := New(PChessPiece,
  212.              Init(@Self, TempBoard[Square.X, Square.Y], Square));
  213.         Pieces.Insert(Squares[Square.X,Square.Y]);
  214.       end;
  215.   ResetValidMoves;
  216.   GameOver := False;
  217.   if HWindow <> 0 then
  218.   begin
  219.     Pieces.ForEach(@DoResize);
  220.     DrawBoard;
  221.     InvalidateRect(HWindow, nil, False);
  222.   end;
  223. end;
  224.  
  225. procedure TChessBoard.SetGameOver(IsOver: Boolean);
  226. begin
  227.   if GameOver <> IsOver then
  228.   begin
  229.     GameOver := IsOver;
  230.     DrawBoard;
  231.     InvalidateRect(HWindow, nil, False);
  232.   end;
  233. end;
  234.  
  235. function TChessBoard.IdealWidth: Word;
  236. var
  237.   Best: Word;
  238.   procedure CheckBitmapSize(P: PChessPiece); far;
  239.   begin
  240.     if Best < P^.BitSize.X then Best := P^.BitSize.X;
  241.     if Best < P^.BitSize.Y then Best := P^.BitSize.Y;
  242.   end;
  243. begin
  244.   Best := 0;
  245.   Pieces.ForEach(@CheckBitmapSize);
  246.   IdealWidth := (Best + 4) * 8;
  247. end;
  248.  
  249. procedure TChessBoard.InitBoardBitmap;
  250. var
  251.   DC: HDC;
  252. begin
  253.   if BoardBitmap <> 0 then
  254.   begin
  255.     SelectObject(BoardDC, BoardOldBM);
  256.     DeleteObject(BoardBitmap);
  257.   end;
  258.  
  259.   DC := GetDC(HWindow);
  260.   BoardBitmap := CreateCompatibleBitmap(DC, Attr.W, Attr.H);
  261.   ReleaseDC(HWindow, DC);
  262.   BoardOldBM := SelectObject(BoardDC, BoardBitmap);
  263.   SquareWidth := Attr.W div 8;
  264. end;
  265.  
  266. procedure TChessBoard.DrawBoard;
  267. var
  268.   OldBrush, SquareBrush : HBrush;
  269.   X, Y: Integer;
  270.   OldFont: HFont;
  271.   LF: TLogFont;
  272.  
  273.   procedure DoPaint(P: PChessPiece); far;
  274.   begin
  275.     P^.Paint(BoardDC);
  276.   end;
  277.  
  278. begin
  279.   OldBrush := SelectObject(BoardDC, WhiteBrush);
  280.   PatBlt(BoardDC, 0, 0, Attr.W, Attr.H, PatCopy);
  281.  
  282.   SelectObject(BoardDC, BlackBrush);
  283.   for Y := 0 to 7 do
  284.     for X := 0 to 7 do
  285.       if Odd(X + Y) then
  286.         PatBlt(BoardDC, X * SquareWidth, Y * SquareWidth,
  287.                       SquareWidth, SquareWidth, PatCopy);
  288.  
  289.   if GameOver then
  290.   begin
  291.     SaveDC(BoardDC);
  292.     SetBkMode(BoardDC, Transparent);
  293.     SetTextColor(BoardDC, RGB(128,128,128));
  294.     FillChar(LF, SizeOf(LF), 0);
  295.     with LF do
  296.     begin
  297.       lfHeight := SquareWidth * 2;
  298.       lfWidth := SquareWidth;
  299.       lfWeight := FW_Bold;
  300.       lfOutPrecision := out_Character_Precis;
  301.       lfQuality := Proof_Quality;
  302.       if LoWord(GetVersion) = $0003 then
  303.         StrCopy(lfFaceName, 'Tms Rmn')
  304.       else
  305.         StrCopy(lfFaceName, 'Times New Roman');
  306.     end;
  307.     OldFont := SelectObject(BoardDC, CreateFontIndirect(LF));
  308.     TextOut(BoardDC,
  309.             Attr.W div 2 - LoWord(GetTextExtent(BoardDC, 'GAME', 4)) div 2,
  310.             SquareWidth * 2, 'GAME', 4);
  311.     TextOut(BoardDC,
  312.             Attr.W div 2 - LoWord(GetTextExtent(BoardDC, 'OVER', 4)) div 2,
  313.             SquareWidth * 4, 'OVER', 4);
  314.     DeleteObject(SelectObject(BoardDC, OldFont));
  315.     RestoreDC(BoardDC, -1);
  316.   end;
  317.  
  318.   SelectObject(BoardDC, OldBrush);
  319.   Pieces.ForEach(@DoPaint);
  320. end;
  321.  
  322. { Because of the way the board paints from a memory bitmap, we don't
  323.   need the window to erase the background before we paint.  }
  324. procedure TChessBoard.WMEraseBkgnd(var Msg: TMessage);
  325. begin
  326.   Msg.Result := 1;
  327. end;
  328.  
  329. procedure TChessBoard.DrawValidMoves(DC: HDC);
  330.  
  331.   procedure TestAndInvert(Test, Show: TLocation);
  332.   var
  333.     R: TRect;
  334.   begin
  335.     if Word(Test) = Word(QSquare) then
  336.     begin
  337.       SquareToRect(Show, R);
  338.       InvertRect(DC, R);
  339.     end;
  340.   end;
  341.  
  342. var
  343.   X : Integer;
  344. begin
  345.   if Squares[QSquare.X, QSquare.Y] <> nil then
  346.     { Show where this piece can move to }
  347.   begin
  348.     X := 0;
  349.     while (X <= High(ValidMoves)) and
  350.           (ValidMoves[X].Change.Piece <> pEmpty) do
  351.     begin
  352.       with ValidMoves[X].Change do
  353.         TestAndInvert(Source, Dest);
  354.       Inc(X);
  355.     end;
  356.     X := 0;
  357.     while (X <= High(ValidMoves)) and
  358.           (OpponentMoves[X].Change.Piece <> pEmpty) do
  359.     begin
  360.       with OpponentMoves[X].Change do
  361.         TestAndInvert(Source, Dest);
  362.       Inc(X);
  363.     end;
  364.   end
  365.   else
  366.     { Show what pieces can move to this square }
  367.   begin
  368.     X := 0;
  369.     while (X <= High(ValidMoves)) and
  370.           (ValidMoves[X].Change.Piece <> pEmpty) do
  371.     begin
  372.       with ValidMoves[X].Change do
  373.         TestAndInvert(Dest, Source);
  374.       Inc(X);
  375.     end;
  376.     X := 0;
  377.     while (X <= High(OpponentMoves)) and
  378.           (OpponentMoves[X].Change.Piece <> pEmpty) do
  379.     begin
  380.       with OpponentMoves[X].Change do
  381.         TestAndInvert(Dest, Source);
  382.       Inc(X);
  383.     end;
  384.   end;
  385. end;
  386.  
  387.  
  388. procedure TChessBoard.Paint(DC: HDC; var PS: TPaintStruct);
  389.   procedure CheckPieces(P: PChessPiece); far;
  390.   var
  391.     Sq: TLocation;
  392.     OldBrush: HBrush;
  393.   begin
  394.     if P^.NeedRedraw then
  395.     begin
  396.       P^.GetSquare(Sq);
  397.       if Odd(Sq.X + Sq.Y) then
  398.         OldBrush := SelectObject(BoardDC, WhiteBrush)
  399.       else
  400.         OldBrush := SelectObject(BoardDC, BlackBrush);
  401.       with P^.Rect do
  402.         PatBlt(BoardDC, Left, Top, Right - Left, Bottom - Top, PatCopy);
  403.       SelectObject(BoardDC, OldBrush);
  404.       P^.Paint(BoardDC);
  405.     end;
  406.   end;
  407. begin
  408.   Pieces.ForEach(@CheckPieces);
  409.   with PS.rcPaint do
  410.     BitBlt(DC, Left, Top, Right - Left, Bottom - Top,
  411.            BoardDC, Left, Top, SrcCopy);
  412.   if Dragger <> nil then
  413.     Dragger^.Paint(DC);
  414.   if Word(QSquare) <> 0 then
  415.     DrawValidMoves(DC);
  416. end;
  417.  
  418. procedure TChessBoard.WMSize(var Msg: TMessage);
  419.  
  420.   procedure DoResize(P : PChessPiece); far;
  421.   var
  422.     R: TRect;
  423.     S: TLocation;
  424.   begin
  425.     P^.GetSquare(S);
  426.     SquareToRect(S, R);
  427.     P^.SetRect(R);
  428.   end;
  429.  
  430. begin
  431.   inherited WMSize(Msg);
  432.   SquareWidth := Attr.W div 8;
  433.   InitBoardBitmap;
  434.   Pieces.ForEach(@DoResize);
  435.   DrawBoard;
  436.   if CoverDlg^.HWindow <> 0 then
  437.     SetWindowPos(CoverDlg^.HWindow, 0, SquareWidth div 2,
  438.                                        SquareWidth div 2,
  439.                                        Attr.W - SquareWidth,
  440.                                        Attr.H - SquareWidth,
  441.                                        swp_NoActivate or swp_NoZOrder);
  442. end;
  443.  
  444. procedure TChessBoard.Cover(DoIt: Boolean);
  445. begin
  446.   if(CoverDlg <> nil) and
  447.     (CoverDlg^.HWindow <> 0) then
  448.     if DoIt then
  449.       CoverDlg^.Show(sw_Show)
  450.     else
  451.       CoverDlg^.Show(sw_Hide);
  452. end;
  453.  
  454. function TChessBoard.PieceFromPoint(Pt: TPoint): PChessPiece;
  455.   function DoHitTest(P: PChessPiece): Boolean; far;
  456.   begin
  457.     DoHitTest := P^.HitTest(Pt);
  458.   end;
  459. begin
  460.   PieceFromPoint := PChessPiece(Pieces.FirstThat(@DoHitTest));
  461. end;
  462.  
  463. procedure TChessBoard.SquareFromPoint(Pt: TPoint; var Sq: TLocation);
  464. var
  465.   Temp: Shortint;
  466. begin
  467.   Temp := (Pt.X div SquareWidth) + 1;
  468.   if Temp in [1..8] then
  469.     Sq.X := Temp
  470.   else
  471.   begin
  472.     Word(Sq) := 0;
  473.     Exit;
  474.   end;
  475.   Temp := (Attr.H - Pt.Y) div SquareWidth + 1;
  476.   if Temp in [1..8] then
  477.     Sq.Y := Temp
  478.   else
  479.     Word(Sq) := 0;
  480. end;
  481.  
  482. procedure TChessBoard.SquareToRect(Sq: TLocation; var R: TRect);
  483. begin
  484.   R.Left   := (Sq.X - 1) * SquareWidth;
  485.   R.Right  := R.Left + SquareWidth;
  486.   R.Top    := Attr.H - (Sq.Y * SquareWidth);
  487.   R.Bottom := R.Top + SquareWidth;
  488. end;
  489.  
  490. procedure TChessBoard.ExecuteMove(const Move: TMove);
  491.  
  492.   function  CreatePromote(P: TPiece; Dest: TLocation): PChessPiece;
  493.   var                    { This function creates the piece specified by }
  494.     X: TSquare;          { P using color info from the piece already on }
  495.   begin                  { on the board at Dest.  This is for           }
  496.     X.Piece := P;        { Pawn Promotion moves only.                   }
  497.     X.Color := Squares[Dest.X, Dest.Y]^.Color;
  498.     InsertPiece(Dest, New(PChessPiece, Init(@Self, X, Dest)));
  499.   end;
  500.  
  501. begin
  502.   if Move.Change.Piece = pEmpty then Exit;
  503.   with Move, Move.Change do
  504.   begin
  505.     InsertPiece(Dest, RemovePiece(Source)); { Also deletes what's at dest }
  506.     case Move.Kind of
  507.       kEnPassant  : Dispose(RemovePiece(EPCapture), Done);
  508.       kCastling   : InsertPiece(RookDest, RemovePiece(RookSource));
  509.       kPawnPromote: CreatePromote(Piece, Dest);
  510.     end;
  511.   end;
  512. end;
  513.  
  514. procedure TChessBoard.RetractMove(const Move: TMove);
  515.   procedure CreatePiece(P: TPiece; Color: Boolean; Dest: TLocation);
  516.   var
  517.     X: TSquare;
  518.   begin
  519.     X.Piece := P;
  520.     X.Color := TColor(Color);
  521.     InsertPiece(Dest, New(PChessPiece, Init(@Self, X, Dest)));
  522.   end;
  523. var
  524.   Color: Boolean;   { Color of opponent }
  525. begin
  526.   if Move.Change.Piece = pEmpty then Exit;
  527.   with Move, Move.Change do
  528.   begin
  529.     Color := not Boolean(Squares[Dest.X, Dest.Y]^.Color);
  530.     InsertPiece(Source, RemovePiece(Dest)); {Back out of destination }
  531.     case Move.Kind of
  532.       kNormal     : if Capture then CreatePiece(Contents, Color, Dest);
  533.       kEnPassant  : CreatePiece(Contents, Color, EPCapture);
  534.       kCastling   : InsertPiece(RookSource, RemovePiece(RookDest));
  535.       kPawnPromote:
  536.         begin
  537.           if Capture then CreatePiece(Contents, not Color, Dest);
  538.           CreatePiece(pPawn, Color, Source);
  539.         end;
  540.     end;
  541.   end;
  542. end;
  543.  
  544.  
  545. procedure TChessBoard.ResetValidMoves;
  546. var
  547.   Chg: TChange;
  548.   PlayerColor: TColor;
  549.   EmptyMove: TMove;
  550.  
  551.   procedure DoValids(P : PChessPiece); far;
  552.   begin
  553.     if P^.Color = PlayerColor then
  554.       P^.ResetValidMoves(ValidMoves)  { piece gets its moves from list }
  555.     else
  556.     begin
  557.       P^.ResetValidMoves(EmptyMove);  { clear opponent's move lists }
  558.       if ChessSettings.ShowAttacks then
  559.         P^.CheckJeopardy(ValidMoves)
  560.       else
  561.         P^.CheckJeopardy(EmptyMove);
  562.     end;
  563.   end;
  564.  
  565.   procedure DoJeopardies(P : PChessPiece); far;
  566.   begin
  567.     if P^.Color = PlayerColor then
  568.       P^.CheckJeopardy(OpponentMoves);
  569.   end;
  570.  
  571. begin
  572.   Chg.Piece := pEmpty;
  573.   Word(Chg.Source) := 0;
  574.   Word(Chg.Dest) := 0;
  575.   FillChar(EmptyMove, SizeOf(EmptyMove), 0);
  576.   PlayerColor := GetPlayer(Game);
  577.   if ChessSettings.ShowJeopardies or
  578.      ChessSettings.RightClickHints then
  579.   begin
  580.     { Switch players to see which opponent pieces attack ours }
  581.     SetPlayer(Game, OtherPlayer(PlayerColor));
  582.     GetValidMoves(Game, Chg, OpponentMoves);
  583.     SetPlayer(Game, PlayerColor);
  584.     if ChessSettings.ShowJeopardies then
  585.       Pieces.ForEach(@DoJeopardies);
  586.   end
  587.   else
  588.   begin
  589.     OpponentMoves[0] := EmptyMove;    { Clear the jeopardy lists }
  590.     Pieces.ForEach(@DoJeopardies);
  591.   end;
  592.   { Now see what moves our pieces can make }
  593.   GetValidMoves(Game, Chg, ValidMoves);
  594.   Pieces.ForEach(@DoValids);
  595. end;
  596.  
  597. procedure TChessBoard.WMSetCursor(var Msg: TMessage);
  598. var
  599.   P: TPoint;
  600.   X: PChessPiece;
  601. begin
  602.   DefWndProc(Msg);
  603.   if Msg.Result = 0 then
  604.   begin
  605.     GetCursorPos(P);
  606.     ScreenToClient(HWindow, P);
  607.     X := PieceFromPoint(P);
  608.     if (X <> nil) and X^.CanDrag and (not GameOver) then
  609.       SetCursor(X^.GetCursor)
  610.     else
  611.       SetCursor(LoadCursor(0, PChar(idc_Arrow)));
  612.   end;
  613. end;
  614.  
  615. procedure TChessBoard.CancelDrag;
  616. var
  617.   NewSq, OldSq : TLocation;
  618.   P: TPoint;
  619.   Chg: TChange;
  620.   R: TRect;
  621. begin
  622.   if Dragger <> nil then
  623.   begin
  624.     Word(NewSq) := 0;     { 0,0 = off board or invalid }
  625.     Longint(P) := 0;
  626.     R := Dragger^.Rect;
  627.     Dragger^.GetSquare(OldSq);
  628.     Dragger^.DragEnd(DragDC, P, NewSq, Chg);
  629.     InvalidateRect(HWindow, @R, False);
  630.     InsertPiece(OldSq, Dragger);  { Go back to original square }
  631.     Dragger := nil;
  632.     ReleaseCapture;
  633.     DeleteObject(SelectObject(DragDC, DragBM));
  634.     DeleteDC(DragDC);
  635.     DragDC := 0;
  636.   end;
  637. end;
  638.  
  639. procedure TChessBoard.WMLButtonDown(var Msg: TMessage);
  640. var
  641.    R: TRect;
  642.   Sq: TLocation;
  643.   DC: HDC;
  644. begin
  645.   if (Dragger = nil) and not GameOver then
  646.   begin
  647.     Dragger := PieceFromPoint(TPoint(Msg.LParam));
  648.     if (Dragger <> nil) then
  649.       if Dragger^.CanDrag then
  650.       begin
  651.         Dragger^.GetSquare(Sq);
  652.         RemovePiece(Sq);
  653.         UpdateWindow(HWindow);
  654.         SetCapture(HWindow);
  655.         DC := GetDC(HWindow);
  656.         DragDC := CreateCompatibleDC(DC);
  657.         DragBM := SelectObject(DragDC,
  658.                     CreateCompatibleBitmap(DC, Attr.W, Attr.H));
  659.         BitBlt(DragDC, 0, 0, Attr.W, Attr.H, BoardDC, 0, 0, SrcCopy);
  660.         R := Dragger^.Rect;
  661.         Dragger^.DragBegin(DragDC, TPoint(Msg.LParam));
  662.         UnionRect(R, R, Dragger^.Rect);
  663.         with R do
  664.           BitBlt(DC, Left, Top, Right - Left, Bottom - Top,
  665.                  DragDC, Left, Top, SrcCopy);
  666.         ReleaseDC(HWindow, DC);
  667.       end
  668.       else
  669.       begin
  670.         Dragger := nil;
  671.         MessageBeep(0);
  672.       end;
  673.   end;
  674.   DefWndProc(Msg);
  675. end;
  676.  
  677. procedure TChessBoard.WMMouseMove(var Msg: TMessage);
  678. var
  679.    R: TRect;
  680.   Sq: TLocation;
  681.   DC: HDC;
  682. begin
  683.   if not GameOver then
  684.     if Dragger <> nil then
  685.     begin
  686.       GetClientRect(HWindow, R);
  687.       if PtInRect(R, TPoint(Msg.LParam)) then
  688.       begin
  689.         SquareFromPoint(TPoint(Msg.LParam), Sq);
  690.         with Dragger^.Rect do
  691.           BitBlt(DragDC, Left, Top, Right - Left, Bottom - Top,
  692.                  BoardDC, Left, Top, SrcCopy);
  693.         R := Dragger^.Rect;
  694.         Dragger^.DragContinue(DragDC, TPoint(Msg.LParam), Sq);
  695.         UnionRect(R, R, Dragger^.Rect);
  696.         DC := GetDC(HWindow);
  697.         with R do
  698.           BitBlt(DC, Left, Top, Right - Left, Bottom - Top,
  699.                  DragDC, Left, Top, SrcCopy);
  700.         ReleaseDC(HWindow, DC);
  701.       end
  702.       else
  703.       begin
  704.         Dragger^.DragHide;
  705.         InvalidateRect(HWindow, @Dragger^.Rect, False);
  706.         SetCursor(LoadCursor(HInstance, PChar(curNo)));
  707.       end;
  708.     end;
  709.   if Word(QSquare) <> 0 then
  710.   begin
  711.     Sq := QSquare;
  712.     GetClientRect(HWindow, R);
  713.     if PtInRect(R, TPoint(Msg.LParam)) then
  714.       SquareFromPoint(TPoint(Msg.LParam), QSquare)
  715.     else
  716.       Word(QSquare) := 0;
  717.     if Word(Sq) <> Word(QSquare) then
  718.       InvalidateRect(HWindow, nil, False);
  719.   end;
  720.   DefWndProc(Msg);
  721. end;
  722.  
  723. procedure TChessBoard.WMLButtonUp(var Msg: TMessage);
  724. var
  725.   NewSq, OldSq: TLocation;
  726.   R: TRect;
  727.   Chg: TChange;
  728.   ValidMove: Boolean;
  729.   PlayerColor : TColor;
  730.   Error : TChessError;
  731. begin
  732.   if Dragger <> nil then
  733.   begin
  734.     GetClientRect(HWindow, R);
  735.     with Dragger^.Rect do
  736.       BitBlt(DragDC, Left, Top, Right - Left, Bottom - Top,
  737.              BoardDC, Left, Top, SrcCopy);
  738.     if PtInRect(R, TPoint(Msg.LParam)) then
  739.       SquareFromPoint(TPoint(Msg.LParam), NewSq)
  740.     else
  741.     begin
  742.       NewSq.X := 0;     { 0 = off board or invalid }
  743.       NewSq.Y := 0;
  744.     end;
  745.     R := Dragger^.Rect;
  746.     Dragger^.GetSquare(OldSq);
  747.     ValidMove := Dragger^.DragEnd(DragDC, TPoint(Msg.LParam), NewSq, Chg);
  748.     InvalidateRect(HWindow, @R, False);
  749.     InsertPiece(OldSq, Dragger);  { Go back to original square }
  750.     ReleaseCapture;
  751.     DeleteObject(SelectObject(DragDC, DragBM));
  752.     DeleteDC(DragDC);
  753.     DragDC := 0;
  754.     if ValidMove and Dragger^.NeedPawnPromote then
  755.     begin
  756.       CoverDlg^.Lock;
  757.       SendMessage(Parent^.HWindow, am_ChoosePawnPromote, 0, Longint(@Chg));
  758.       CoverDlg^.UnLock;
  759.     end;
  760.     Dragger := nil;
  761.             { am_SubmitMove will return a boolean accept/reject response }
  762.     if ValidMove and
  763.        LongBool(SendMessage(Parent^.HWindow, am_SubmitMove, 0, Longint(@Chg))) then
  764.     begin
  765.         { Update the pieces to reflect the attacks of the moved piece in
  766.           its new position.  }
  767.       ResetValidMoves;
  768.     end;
  769.     UpdateWindow(HWindow);
  770.   end;
  771.   DefWndProc(Msg);
  772. end;
  773.  
  774. procedure TChessBoard.InsertPiece(Sq: TLocation; P: PChessPiece);
  775. var
  776.   R: TRect;
  777. begin
  778.   if Squares[Sq.X,Sq.Y] = P then Exit;
  779.   if (Squares[Sq.X,Sq.Y] <> nil) then
  780.     Dispose(RemovePiece(Sq), Done);
  781.   Pieces.Insert(P);
  782.   P^.SetSquare(Sq);
  783.   Squares[Sq.X, Sq.Y] := P;
  784.   SquareToRect(Sq, R);
  785.   P^.SetRect(R);
  786.   P^.Paint(BoardDC);
  787.   InvalidateRect(HWindow, @R, False);
  788. end;
  789.  
  790. function TChessBoard.RemovePiece(Sq: TLocation): PChessPiece;
  791. var
  792.   OldBrush: HBrush;
  793.   R: TRect;
  794. begin
  795.   RemovePiece := nil;
  796.   if Squares[Sq.X,Sq.Y] <> nil then
  797.   begin
  798.     RemovePiece := Squares[Sq.X,Sq.Y];
  799.     Pieces.Delete(Squares[Sq.X,Sq.Y]);
  800.     Squares[Sq.X,Sq.Y] := nil;
  801.  
  802.     if Odd(Sq.X + Sq.Y) then
  803.       OldBrush := SelectObject(BoardDC, WhiteBrush)
  804.     else
  805.       OldBrush := SelectObject(BoardDC, BlackBrush);
  806.     SquareToRect(Sq, R);
  807.     with R do
  808.       PatBlt(BoardDC, Left, Top, Right - Left, Bottom - Top, PatCopy);
  809.     SelectObject(BoardDC, OldBrush);
  810.     InvalidateRect(HWindow, @R, False);
  811.   end;
  812. end;
  813.  
  814. procedure TChessBoard.WMRButtonDown(var Msg: TMessage);
  815. var
  816.   R: TRect;
  817.   OldQ : TLocation;
  818. begin
  819.   if ChessSettings.RightClickHints then
  820.   begin
  821.     OldQ := QSquare;
  822.     GetClientRect(HWindow, R);
  823.     if PtInRect(R, TPoint(Msg.LParam)) then
  824.       SquareFromPoint(TPoint(Msg.LParam), QSquare)
  825.     else
  826.       Word(QSquare) := 0;
  827.     if Word(OldQ) <> Word(QSquare) then
  828.       InvalidateRect(HWindow, nil, False);
  829.     SetCapture(HWindow);
  830.   end;
  831.   DefWndProc(Msg);
  832. end;
  833.  
  834. procedure TChessBoard.WMRButtonUp(var Msg: TMessage);
  835. begin
  836.   if ChessSettings.RightClickHints then
  837.   begin
  838.     if Word(QSquare) <> 0 then
  839.       InvalidateRect(HWindow, nil, False);
  840.     FillChar(QSquare, SizeOf(QSquare), 0);
  841.     ReleaseCapture;
  842.   end;
  843.   DefWndProc(Msg);
  844. end;
  845.  
  846.  
  847. constructor TBoardFrame.Init(AParent: PWindowsObject;
  848.                               ABoard: PChessBoard);
  849. begin
  850.   inherited Init(AParent, nil);
  851.   Attr.Style := ws_Child or ws_ClipSiblings;
  852.   Board := ABoard;
  853.   FrameWidth := 5;  { arbitrary - This will be calculated in SetupWindow }
  854. end;
  855.  
  856. function  TBoardFrame.GetClassName: PChar;
  857. begin
  858.   GetClassName := 'TPWChessBoardFrame';
  859. end;
  860.  
  861. procedure TBoardFrame.GetWindowClass(var WC: TWndClass);
  862. var
  863.   LB: TLogBrush;
  864. begin
  865.   inherited GetWindowClass(WC);
  866.   with WC do
  867.   begin
  868.     Style := cs_ByteAlignWindow;
  869.     GetObject(BWCCGetPattern, SizeOf(LB), @LB);
  870.     hbrBackground := CreateBrushIndirect(LB);
  871.     hCursor := 0;
  872.   end;
  873. end;
  874.  
  875. procedure TBoardFrame.SetupWindow;
  876. var
  877.   DC : HDC;
  878.   OldFont: HFont;
  879.   TM: TTextMetric;
  880. begin
  881.   inherited SetupWindow;
  882.   DC := GetDC(0);
  883.   OldFont := SelectObject(DC, GetStockObject(ANSI_Fixed_Font));
  884.   GetTextMetrics(DC, TM);
  885.   SelectObject(DC, OldFont);
  886.   ReleaseDC(0, DC);
  887.   FontWidth := TM.tmMaxCharWidth;
  888.   FontHeight := TM.tmHeight;
  889.   if FontWidth < FontHeight then
  890.     FrameWidth := FontHeight
  891.   else
  892.     FrameWidth := FontWidth;
  893.   Inc(FrameWidth);
  894. end;
  895.  
  896. function TBoardFrame.IdealWidth: Integer;
  897. begin
  898.   IdealWidth := FrameWidth * 2 + Board^.IdealWidth + 6;
  899. end;
  900.  
  901. procedure TBoardFrame.Paint(DC: HDC; var PS: TPaintStruct);
  902. var
  903.   X, Sq: Integer;
  904.   S: array [0..2] of Char;
  905.   Point: array [0..4] of TPoint;
  906.   OldPen: HPen;
  907.   R: TRect;
  908. begin
  909.   GetClientRect(HWindow, R);
  910.   {White}
  911.   OldPen := SelectObject(DC, CreatePen(ps_Solid, 1, RGB(255,255,255)));
  912.   FillChar(Point, SizeOf(Point), 0);
  913.   Point[0].X := R.Right-1;
  914.   Point[2].Y := R.Bottom;
  915.   PolyLine(DC, Point, 3);
  916.   Point[0].X := R.Right - FrameWidth - 1;
  917.   Point[0].Y := FrameWidth + 1;
  918.   Point[1].X := Point[0].X;
  919.   Point[1].Y := Point[0].X;
  920.   Point[2].X := FrameWidth + 1;
  921.   Point[2].Y := Point[0].X;
  922.   PolyLine(DC, Point, 3);
  923.   {Neutral grey}
  924.   DeleteObject(SelectObject(DC, CreatePen(ps_Solid, 2, RGB(192,192,192))));
  925.   Point[0].X := R.Right - FrameWidth - 2;
  926.   Point[0].Y := FrameWidth + 3;
  927.   Point[1].X := Point[0].X;
  928.   Point[1].Y := Point[0].X;
  929.   Point[2].X := Point[0].Y - 1;
  930.   Point[2].Y := Point[0].X;
  931.   Point[3].X := Point[2].X;
  932.   Point[3].Y := Point[2].X;
  933.   Point[4].X := Point[0].X;
  934.   Point[4].Y := Point[2].X;
  935.   PolyLine(DC, Point, 5);
  936.   {Dark grey}
  937.   DeleteObject(SelectObject(DC, CreatePen(ps_Solid, 1, RGB(128,128,128))));
  938.   Point[0].X := R.Right - FrameWidth - 2;
  939.   Point[0].Y := FrameWidth;
  940.   Point[1].X := Point[0].Y;
  941.   Point[1].Y := Point[0].Y;
  942.   Point[2].X := Point[0].Y;
  943.   Point[2].Y := Point[0].X + 1;
  944.   PolyLine(DC, Point, 3);
  945.   Point[0].X := R.Right-1;
  946.   Point[0].Y := 1;
  947.   Point[1].X := R.Right-1;
  948.   Point[1].Y := R.Bottom-1;
  949.   Point[2].X := 0;
  950.   Point[2].Y := R.Bottom-1;
  951.   PolyLine(DC, Point, 3);
  952.   DeleteObject(SelectObject(DC, OldPen));
  953.   Sq := Board^.SquareWidth;
  954.   SetBkMode(DC, Transparent);
  955.   SetTextColor(DC, 0);
  956.   S[1] := #0;
  957.   for X := 0 to 7 do
  958.   begin
  959.     S[0] := Char(Ord('8')-X);
  960.     TextOut(DC, FrameWidth div 2 - FontWidth div 2,
  961.                 FrameWidth + 2 + (X * Sq) + (Sq div 2 - FontHeight div 2),
  962.                 S, 1);
  963.     S[0] := Char(Ord('A')+X);
  964.     TextOut(DC, FrameWidth + (X*Sq) + (Sq div 2 - FontWidth div 2),
  965.                 FrameWidth + 4 + Sq*8 + FrameWidth div 2 - FontHeight div 2,
  966.                 S, 1);
  967.   end;
  968. end;
  969.  
  970. procedure TBoardFrame.WMMove(var Msg: TMessage);
  971. var
  972.   P: TPoint;
  973. begin
  974.   DefWndProc(Msg);
  975.   P.X := FrameWidth + 3;
  976.   P.Y := P.X;
  977.   ClientToScreen(HWindow, P);
  978.   ScreenToClient(Parent^.HWindow, P);
  979.   SetWindowPos(Board^.HWindow,0,P.X,P.Y,0,0, swp_NoSize or swp_NoZOrder);
  980. end;
  981.  
  982. procedure TBoardFrame.WMSize(var Msg: TMessage);
  983. var
  984.   P: TPoint;
  985. begin
  986.   DefWndProc(Msg);
  987.   P.X := FrameWidth + 3;
  988.   P.Y := P.X;
  989.   ClientToScreen(HWindow, P);
  990.   ScreenToClient(Parent^.HWindow, P);
  991.   SetWindowPos(Board^.HWindow, 0, P.X, P.Y,
  992.                LoWord(Msg.LParam) - 2 * (FrameWidth + 3),
  993.                HiWord(Msg.LParam) - 2 * (FrameWidth + 3),
  994.                swp_NoActivate or swp_NoZOrder);
  995. end;
  996.  
  997. end.