home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Pascal / BPASCAL.700 / D10 / OWLDEMOS.ZIP / GDIDEMO.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-10-01  |  27.8 KB  |  979 lines

  1. {************************************************}
  2. {                                                }
  3. {   Demo program                                 }
  4. {   Copyright (c) 1991 by Borland International  }
  5. {                                                }
  6. {************************************************}
  7.  
  8. program GDIDemo;
  9.  
  10. uses WinProcs, WinTypes, Objects, OWindows, ODialogs, Strings;
  11.  
  12. {$R GDIDEMO.RES}
  13.  
  14. { Menu bar constants }
  15. const
  16.   MenuID              = 100; { Resource ID of the menu }
  17.   QuitID              = 100; { File->Quit ID }
  18.   MoveToLineToDemoID  = 200; { Demo->MoveToDemo ID }
  19.   FontDemoID          = 202; { Demo->Font Demo ID }
  20.   BitBltDemoID        = 203; { Demo->BitBlt Demo ID }
  21.   ArtyDemoID          = 204; { Demo->Arty Demo ID }
  22.  
  23. { BitBlt demo constants }
  24. const
  25.   BackgroundID        = 100; { Bitmap ID of background bitmap }
  26.   ShipID              = 101; { Bitmap ID of Ship Bitmap }
  27.   MonoShipID          = 102; { Bitmap ID of Monochrome mask of ship }
  28.   BitmapSize          = 72;  { Size of Ship bitmap }
  29.  
  30. { Font demo constants }
  31. const
  32.   MaxNumFonts =  20; { Maximum number of fonts to be displayed in FontDemo }
  33.  
  34. { MoveToLineTo demo constants }
  35. const
  36.   MaxPoints   =  15; { Number of points to be drawn in MoveToLineToDemo }
  37.  
  38. { Arty demo constants }
  39. const
  40.    MaxLineCount  = 100;
  41.    MaxIconicLineCount = 5;
  42.    MaxColorDuration = 10;
  43.  
  44. function Min(X, Y: Integer): Integer;
  45. begin
  46.   if X > Y then Min := Y else Min := X;
  47. end;
  48.  
  49. { TBaseDemoWindow -------------------------------------------------- }
  50.  
  51. type
  52.   PBaseDemoWindow = ^TBaseDemoWindow;
  53.   TBaseDemoWindow = object(TWindow)
  54.     procedure TimerTick; virtual;
  55.   end;
  56.  
  57. { Trivial method that gets called whenever application receives a
  58.   WM_Timer.  Descendants will override this procedure if they need
  59.   timer messages.}
  60. procedure TBaseDemoWindow.TimerTick;
  61. begin
  62. end;
  63.  
  64. { TNoIconWindow --------------------------------------------------- }
  65.  
  66. type
  67.   PNoIconWindow = ^TNoIconWindow;
  68.   TNoIconWindow = object(TBaseDemoWindow)
  69.     procedure GetWindowClass(var AWndClass: TWndClass);  virtual;
  70.     function GetClassName: PChar;  virtual;
  71.   end;
  72.  
  73. { Alter the default window class record to make this window have
  74.   a black background and no "white box" icon.  }
  75. procedure TNoIconWindow.GetWindowClass(var AWndClass: TWndClass);
  76. begin
  77.   TBaseDemoWindow.GetWindowClass(AWndClass);
  78.   AWndClass.hbrBackground := GetStockObject(Black_Brush);
  79.   AWndClass.hIcon := 0;
  80. end;
  81.  
  82. { No need to call the ancestor's method here, since we want to
  83.   provide an entirely new window class name. }
  84. function TNoIconWindow.GetClassName: PChar;
  85. begin
  86.   GetClassName := 'NoIconWindow';
  87. end;
  88.  
  89. { TMoveToLineToWindow --------------------------------------------- }
  90.  
  91. type
  92.   TRPoint = record
  93.     X, Y: Real;
  94.   end;
  95.  
  96. type
  97.   PMoveToLineToWindow = ^TMoveToLineToWindow;
  98.   TMoveToLineToWindow = object(TBaseDemoWindow)
  99.     Points: array[0..MaxPoints] of TRPoint;
  100.     constructor Init(AParent: PWindowsObject; ATitle: PChar);
  101.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  102.   end;
  103.  
  104. constructor TMoveToLineToWindow.Init(AParent: PWindowsObject; ATitle: PChar);
  105. var
  106.   I: Integer;
  107.   StepAngle: Integer;
  108.   Radians: Real;
  109. begin
  110.   TBaseDemoWindow.Init(AParent, ATitle);
  111.   StepAngle := 360 div MaxPoints;
  112.   for I := 0 to MaxPoints - 1 do
  113.   begin
  114.     Radians := (StepAngle * I) * PI / 180;
  115.     Points[I].x := Cos(Radians);
  116.     Points[I].y := Sin(Radians);
  117.   end;
  118. end;
  119.  
  120. procedure TMoveToLinetoWindow.Paint(PaintDC: HDC;
  121.   var PaintInfo: TPaintStruct);
  122. var
  123.   TheRect: TRect;
  124.   I, J: Integer;
  125.   CenterX,
  126.   CenterY: Integer;
  127.   Radius,
  128.   StepAngle: Word;
  129.   Radians: real;
  130. begin
  131.   GetClientRect(HWindow,TheRect);
  132.   CenterX := TheRect.Right div 2;
  133.   CenterY := TheRect.Bottom div 2;
  134.   Radius := Min(CenterY, CenterX);
  135.   Ellipse(PaintDC,CenterX - Radius, CenterY - Radius, CenterX + Radius,
  136.     CenterY + Radius);
  137.   for I := 0 to MaxPoints - 1 do
  138.   begin
  139.     for J := I + 1 to MaxPoints - 1 do
  140.     begin
  141.       MoveTo(PaintDC, CenterX + Round(Points[I].X * Radius),
  142.     CenterY + Round(Points[I].Y * Radius));
  143.       LineTo(PaintDC, CenterX + Round(Points[J].X * Radius),
  144.     CenterY + Round(Points[J].Y * Radius));
  145.     end;
  146.   end;
  147. end;
  148.  
  149. { TFontWindow ------------------------------------------------------ }
  150.  
  151. type
  152.   FontInfoRec = record
  153.     Handle: HFont;  { Handle to logical font }
  154.     Height: Byte;   { Height of logical font in pixels }
  155.     Width: LongInt; { Width of name of the font in pixels }
  156.     Name: array[0..lf_FaceSize-1] of char; { Name of this font }
  157.   end;
  158.  
  159. const
  160.   FontUsers: Integer = 0;
  161. var
  162.   FontInfo: array[0..MaxNumFonts] of FontInfoRec;
  163.   NumFonts: Integer; { Number of system fonts available }
  164.   TheDC: HDC;
  165.  
  166. type
  167.   PFontWindow = ^TFontWindow;
  168.   TFontWindow = object(TBaseDemoWindow)
  169.     FontsHeight: LongInt;
  170.     FontsWidth: LongInt;
  171.     constructor Init(AParent: PWindowsObject; ATitle: PChar);
  172.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  173.     procedure Destroy; virtual;
  174.     procedure WMSize(var Msg: TMessage);
  175.       virtual wm_First + wm_Size;
  176.   end;
  177.  
  178. { EnumerateFont is a call back function.  It receives information
  179.   about system fonts.  It creates an example of each font by calling
  180.   CreateFont when MaxNumFonts have been processed, 0 is returned
  181.   notifying windows to stop sending information, otherwise 1 is
  182.   returned telling windows to send more information if available }
  183. function EnumerateFont(var LogFont: TLogFont; TextMetric: PTextMetric;
  184.   FontType: Integer; Data: PChar): Integer; export;
  185. var
  186.   OldFont: HFont;
  187. begin
  188.   { Create the font described by LogFont }
  189.   FontInfo[NumFonts].Handle := CreateFontIndirect(LogFont);
  190.   with LogFont do
  191.   begin
  192.     { Save the height of the font for positioning when drawing in
  193.       the window }
  194.     FontInfo[NumFonts].Height := lfHeight;
  195.     { Save the name of the font for drawing in the window }
  196.     StrCopy(FontInfo[NumFonts].Name, lfFaceName);
  197.     OldFont := SelectObject(TheDC, FontInfo[NumFonts].Handle);
  198.     FontInfo[NumFonts].Width := Word(GetTextExtent(TheDC, lfFaceName,
  199.       StrLen(lfFaceName)));
  200.     SelectObject(TheDC, OldFont);
  201.   end;
  202.   Inc(NumFonts);
  203.   if NumFonts > MaxNumFonts then
  204.     EnumerateFont := 0 { Don't send any more information }
  205.   else
  206.     EnumerateFont := 1; { Send more information if available }
  207. end;
  208.  
  209. { Collect all of the system fonts }
  210. procedure GetFontInfo;
  211. var
  212.   EnumProc: TFarProc;
  213. begin
  214.   if FontUsers = 0 then
  215.   begin
  216.     TheDC := GetDC(GetFocus);
  217.     NumFonts := 0;
  218.     { Create an instance of the call back function.  This allows
  219.       our program to refer to an exported function.  Otherwise the
  220.       Data segment will not be correct. }
  221.     EnumProc := MakeProcInstance(@EnumerateFont, HInstance);
  222.     { Gather information about all fonts that are allowable in our window (DC) }
  223.     EnumFonts(TheDC, nil, EnumProc, nil);
  224.     { Free the instance of our call back function }
  225.     FreeProcInstance(EnumProc);
  226.     ReleaseDC(GetFocus, TheDC);
  227.   end;
  228.   Inc(FontUsers);
  229. end;
  230.  
  231. { Release font information }
  232. procedure ReleaseFontInfo;
  233. var
  234.   I: Integer;
  235. begin
  236.   Dec(FontUsers);
  237.   if FontUsers = 0 then
  238.     for I := 0 to NumFonts - 1 do
  239.       DeleteObject(FontInfo[I].Handle);
  240. end;
  241.  
  242. { Initialize object and collect font information }
  243. constructor TFontWindow.Init(AParent: PWindowsObject; ATitle: PChar);
  244. var
  245.   I: Integer;
  246.  
  247. function Max(I, J: LongInt): LongInt;
  248. begin
  249.   if I > J then Max := I else Max := J;
  250. end;
  251.  
  252. begin
  253.   TBaseDemoWindow.Init(AParent, ATitle);
  254.   GetFontInfo;
  255.   Attr.Style := Attr.Style or ws_VScroll or ws_HScroll;
  256.   FontsHeight := 0;
  257.   FontsWidth := 0;
  258.   for I := 0 to NumFonts - 1 do
  259.   begin
  260.     Inc(FontsHeight, FontInfo[I].Height);
  261.     FontsWidth := Max(FontsWidth, FontInfo[I].Width);
  262.   end;
  263.   Scroller := New(PScroller, Init(@Self, 1, 1, 0, 0));
  264. end;
  265.  
  266. { Draw each font name in it's font in the Display context.  Each
  267.   line is incremented by the height of the font }
  268. procedure TFontWindow.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  269. var
  270.   I: Integer;
  271.   Position: Integer;
  272. begin
  273.   Position := 0;
  274.   for I := 0 to NumFonts - 1 do
  275.   begin
  276.     SelectObject(PaintDC, FontInfo[I].Handle);
  277.     TextOut(PaintDC, 10, Position, FontInfo[I].Name,
  278.       StrLen(FontInfo[I].Name));
  279.     Inc(Position, FontInfo[I].Height);
  280.   end;
  281. end;
  282.  
  283. procedure TFontWindow.Destroy;
  284. var
  285.   I: Integer;
  286. begin
  287.   TBaseDemoWindow.Destroy;
  288.   ReleaseFontInfo;
  289. end;
  290.  
  291. procedure TFontWindow.WMSize(var Msg: TMessage);
  292. begin
  293.   TWindow.WMSize(Msg);
  294.   if Scroller <> nil then
  295.     Scroller^.SetRange(FontsWidth - Msg.lParamLo + 10,
  296.       FontsHeight - Msg.lParamHi);
  297. end;
  298.  
  299. { TBitBltWindow ---------------------------------------------------- }
  300.  
  301. type
  302.   PBitBltWindow = ^TBitBltWindow;
  303.   TBitBltWindow = object(TNoIconWindow)
  304.     WindowSize: TPoint;
  305.     ScratchBitmap,
  306.     StretchedBkgnd,
  307.     Background,
  308.     MonoShip,
  309.     Ship: HBitmap;
  310.     OldX, OldY,
  311.     Delta,
  312.     X, Y: Integer;
  313.     CurClick: Integer;
  314.     constructor Init(AParent: PWindowsObject; ATitle: PChar);
  315.     destructor Done; virtual;
  316.     procedure WMSize(var Message: TMessage); virtual WM_Size;
  317.     procedure WMPaint(var Message: TMessage); virtual WM_Paint;
  318.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  319.     procedure SetupWindow; virtual;
  320.     procedure TimerTick; virtual;
  321.     procedure CalculateNewXY;
  322.   end;
  323.  
  324. { Initialize the bitblt demo window and allocate bitmaps }
  325. constructor TBitBltWindow.Init(AParent: PWindowsObject; ATitle: PChar);
  326. begin
  327.   TNoIconWindow.Init(AParent, ATitle);
  328.   Background := LoadBitmap(HInstance, MakeIntResource(BackgroundID));
  329.   Ship := LoadBitmap(HInstance, MakeIntResource(ShipID));
  330.   MonoShip := LoadBitmap(HInstance, MakeIntResource(MonoShipID));
  331.   ScratchBitmap := 0;
  332.   StretchedBkgnd := 0;
  333.   OldX := 0;
  334.   OldY := 0;
  335.   X := 0;
  336.   Y := 0;
  337.   Delta := 5;
  338.   CurClick := 1;
  339. end;
  340.  
  341. { Dispose of all used resources }
  342. destructor TBitBltWindow.Done;
  343. begin
  344.   DeleteObject(Background);
  345.   DeleteObject(Ship);
  346.   DeleteObject(MonoShip);
  347.   if ScratchBitmap <> 0 then DeleteObject(ScratchBitmap);
  348.   if StretchedBkgnd <> 0 then DeleteObject(StretchedBkgnd);
  349.   TNoIconWindow.Done;
  350. end;
  351.  
  352. { Allocate scratch bitmaps }
  353. procedure TBitBltWindow.SetupWindow;
  354. var
  355.   HandleDC: HDC;
  356. begin
  357.   TNoIconWindow.SetupWindow;
  358.   HandleDC := GetDC(HWindow);
  359.   ScratchBitmap := CreateCompatibleBitmap(HandleDC, 80, 80);
  360.   StretchedBkgnd := CreateCompatibleBitmap(HandleDC, 1000, 1000);
  361.   ReleaseDC(HWindow, HandleDC);
  362. end;
  363.  
  364. { Record the new size and stretch the background to it }
  365. procedure TBitBltWindow.WMSize(var Message: TMessage);
  366. var
  367.   HandleDC, MemDC, StretchedDC: HDC;
  368.   StretchObject, MemObject: THandle;
  369.   PS: TPaintStruct;
  370.   OldCur: HCursor;
  371. begin
  372.   TNoIconWindow.WMSize(Message);
  373.   WindowSize.X := Message.LParamLo;
  374.   WindowSize.Y := Message.LParamHi;
  375.  
  376.   HandleDC := GetDC(HWindow);
  377.  
  378.   { Create a stretched to fit background }
  379.   StretchedDC := CreateCompatibleDC(HandleDC);
  380.   MemDC := CreateCompatibleDC(HandleDC);
  381.   StretchObject := SelectObject(StretchedDC, StretchedBkgnd);
  382.   MemObject := SelectObject(MemDC, Background);
  383.   OldCur := SetCursor(LoadCursor(0, idc_Wait));
  384.   with WindowSize do
  385.     StretchBlt(StretchedDC, 0, 0, X, Y, MemDC, 0, 0, 100, 100, SrcCopy);
  386.   SetCursor(OldCur);
  387.   SelectObject(StretchedDC, StretchObject);
  388.   SelectObject(MemDC, MemObject);
  389.   DeleteDC(MemDC);
  390.   DeleteDC(StretchedDC);
  391.   ReleaseDC(HWindow, HandleDC);
  392. end;
  393.  
  394. { Need to ensure that the Old copy of the ship gets redrawn with
  395.   any paint messages. }
  396. procedure TBitBltWindow.WMPaint(var Message: TMessage);
  397. var
  398.   Rect: TRect;
  399. begin
  400.   Rect.Top := OldY;
  401.   Rect.Left := OldX;
  402.   Rect.Bottom := OldY+BitmapSize;
  403.   Rect.Right := OldX+BitmapSize;
  404.   InvalidateRect(HWindow, @Rect, False);
  405.   TNoIconWindow.WMPaint(Message);
  406. end;
  407.  
  408. procedure TBitBltWindow.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  409. var
  410.   MemDC: HDC;
  411.   MemObject: THandle;
  412. begin
  413.   MemDC := CreateCompatibleDC(PaintDC);
  414.   MemObject := SelectObject(MemDC, StretchedBkgnd);
  415.   with WindowSize do
  416.     BitBlt(PaintDC, 0, 0, X, Y, MemDC, 0, 0, SrcCopy);
  417.   SelectObject(MemDC, MemObject);
  418.   DeleteDC(MemDC);
  419. end;
  420.  
  421. { TimerTick deletes the old position of the saucer and blt's a new one }
  422. procedure TBitBltWindow.TimerTick;
  423. const
  424.   ClicksToSkip = 4;
  425. var
  426.   Bits, BackingStore, WindowDC: HDC;
  427.   SavedBitsObject, SavedStoreObject: THandle;
  428.   BX, BY, OX, OY, BH, BW: Integer;
  429. begin
  430.   { Make the saucer go slower then everyone else }
  431.   if CurClick < ClicksToSkip then
  432.   begin
  433.     Inc(CurClick);
  434.     Exit;
  435.   end
  436.   else CurClick := 1;
  437.  
  438.   TNoIconWindow.TimerTick;
  439.  
  440.   { Setup the DC's }
  441.   WindowDC := GetDC(HWindow);
  442.   Bits := CreateCompatibleDC(WindowDC);
  443.   BackingStore := CreateCompatibleDC(WindowDC);
  444.  
  445.   CalculateNewXY;
  446.  
  447.   { Calulate the offsets into and dimentions of the backing store }
  448.   BX := Min(X, OldX);
  449.   BY := Min(Y, OldY);
  450.   OX := Abs(X - BX);
  451.   OY := Abs(Y - BY);
  452.   BW := 72 + Abs(OldX - X);
  453.   BH := 72 + Abs(OldY - Y);
  454.  
  455.   { Create an image into the backing store the will that, when blt into
  456.     the window will both erase the old image and draw the new one. }
  457.   SavedStoreObject := SelectObject(BackingStore, ScratchBitmap);
  458.   SavedBitsObject := SelectObject(Bits, StretchedBkgnd);
  459.   BitBlt(BackingStore, 0, 0, BW, BH, Bits, BX, BY, srcCopy);
  460.   SelectObject(Bits, MonoShip);
  461.   BitBlt(BackingStore, OX, OY, 72, 72, Bits, 0, 0, SrcAnd);
  462.   SelectObject(Bits, Ship);
  463.   BitBlt(BackingStore, OX, OY, 72, 72, Bits, 0, 0, SrcPaint);
  464.  
  465.   { Blt the backing store to the window }
  466.   BitBlt(WindowDC, BX, BY, BW, BH, BackingStore, 0, 0, SrcCopy);
  467.  
  468.   { Clean up the DC's }
  469.   SelectObject(Bits, SavedBitsObject);
  470.   SelectObject(BackingStore, SavedStoreObject);
  471.   DeleteDC(Bits);
  472.   DeleteDC(BackingStore);
  473.   ReleaseDC(HWindow, WindowDC);
  474.  
  475.   OldX := X;
  476.   OldY := Y;
  477. end;
  478.  
  479. procedure TBitBltWindow.CalculateNewXY;
  480. begin
  481.   if WindowSize.X < BitmapSize then Exit;  { Don't move if too small }
  482.   if (X > WindowSize.X - BitmapSize) or (X < 0) then
  483.   begin
  484.     Delta := -Delta;
  485.     if X > WindowSize.X - BitmapSize then
  486.       X := WindowSize.X - BitmapSize - 5;
  487.   end;
  488.   X := X + Delta;
  489.   Y := Y + Integer(Random(10)) - 5;
  490.   if Y > WindowSize.Y - BitmapSize then Y := WindowSize.Y - BitmapSize
  491.   else if Y < 0 then Y := 0;
  492. end;
  493.  
  494. { TArtyWindow ------------------------------------------------------ }
  495.  
  496. type
  497.   TLineRec = record
  498.     LX1,LY1: Integer;
  499.     LX2,LY2: Integer;
  500.     Color: Longint;
  501.   end;
  502.  
  503.   PLineList = ^TLineList;
  504.   TLineList = array[1..MaxLineCount] of TLineRec;
  505.  
  506.   PList = ^TList;
  507.   TList = object(TObject)
  508.     Line: PLineList;
  509.     MaxLines,
  510.     Xmax, Ymax,
  511.     X1, Y1, X2, Y2,
  512.     MaxDelta,
  513.     ColorDuration,
  514.     IncrementCount,
  515.     DeltaX1, DeltaY1, DeltaX2, DeltaY2,
  516.     CurrentLine: Integer;
  517.     PenColor: Longint;
  518.     Paused: Boolean;
  519.     constructor Init(Max: Integer);
  520.     destructor Done;  virtual;
  521.     procedure AdjustX(var X, DeltaX: Integer);
  522.     procedure AdjustY(var Y, DeltaY: Integer);
  523.     procedure Draw(DC: HDC; a1, b1, a2, b2: Integer; lPenColor: Longint);
  524.     procedure DrawLine(DC: HDC; Index: Integer);  virtual;
  525.     procedure EraseLine(DC: HDC; Index: Integer); virtual;
  526.     procedure Redraw(DC: HDC);
  527.     procedure ResetLines;
  528.     procedure ScaleTo(NewXmax, NewYmax: Integer);
  529.     procedure SelectNewColor;
  530.     procedure SelectNewDeltaValues;
  531.     procedure LineTick(DC: HDC);
  532.   end;
  533.  
  534.   PQuadList = ^TQuadList;
  535.   TQuadList = object(TList)   { Quads draw 4 reflections of each line }
  536.     procedure DrawLine(DC: HDC; Index: Integer);  virtual;
  537.     procedure EraseLine(DC: HDC; Index: Integer);  virtual;
  538.   end;
  539.  
  540.   PArtyWindow = ^TArtyWindow;
  541.   TArtyWindow = object(TNoIconWindow)
  542.     List,
  543.     BigLineList,
  544.     IconicLineList : PList;
  545.     TextHeight: Integer;
  546.     Iconized : Boolean;
  547.     StaticControl: PStatic;
  548.     constructor Init(aParent: PWindowsObject; aTitle: PChar);
  549.     destructor Done;  virtual;
  550.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  551.     procedure WMLButtonDown(var Message: TMessage);
  552.       virtual wm_First + wm_LButtonDown;
  553.     procedure WMRButtonDown(var Message: TMessage);
  554.       virtual wm_First + wm_RButtonDown;
  555.     procedure WMSize(var Msg: TMessage);
  556.       virtual wm_First + wm_Size;
  557.     procedure TimerTick; virtual;
  558.   end;
  559.  
  560. { Initialize the list-of-lines object }
  561. constructor TList.Init(Max: Integer);
  562. begin
  563.   TObject.Init;
  564.   If Max > MaxLineCount then
  565.     Max := MaxLineCount;
  566.  
  567.   { Don't change MaxLines!  It will be used to free memory in Done}
  568.   MaxLines := Max;
  569.   GetMem(Line, SizeOf(TLineRec) * MaxLines);
  570.   CurrentLine := 1;
  571.   Xmax := 0;
  572.   Ymax := 0;
  573.   ColorDuration := MaxColorDuration;
  574.   IncrementCount := 0;
  575.   MaxDelta := 10;
  576.   PenColor := RGB(Random(256), Random(256), Random(256));
  577.   Paused := False;
  578. end;
  579.  
  580. destructor TList.Done;
  581. begin
  582.   FreeMem(Line, SizeOf(TLineRec) * MaxLines);
  583.   TObject.Done;
  584. end;
  585.  
  586. { Keep X within range, and reverse Delta if necessary to do so }
  587. procedure TList.AdjustX(var X, DeltaX: Integer);
  588. var
  589.   TestX: Integer;
  590. begin
  591.   TestX := X + DeltaX;
  592.   if (TestX < 1) or (TestX > Xmax) then
  593.   begin
  594.     TestX := X;
  595.     DeltaX := -DeltaX;
  596.   end;
  597.   X := TestX;
  598. end;
  599.  
  600. { Keep Y within range, and reverse Delta if necessary to do so }
  601. procedure TList.AdjustY(var Y,DeltaY: Integer);
  602. var
  603.   TestY: Integer;
  604. begin
  605.   TestY := Y + DeltaY;
  606.   if (TestY < 1) or (TestY > Ymax) then
  607.   begin
  608.     TestY := Y;
  609.     DeltaY := -DeltaY;
  610.   end;
  611.   Y := TestY;
  612. end;
  613.  
  614. { Clear the array of lines }
  615. procedure TList.ResetLines;
  616. var
  617.   StartX, StartY, I: Integer;
  618. begin
  619.   StartX := Xmax div 2;
  620.   StartY := Ymax div 2;
  621.   for I := 1 to MaxLines do
  622.     with Line^[I] do
  623.     begin
  624.       LX1 := StartX; LX2 := StartX;
  625.       LY1 := StartY; LY2 := StartY;
  626.       Color := 0;
  627.     end;
  628.   X1 := StartX;
  629.   X2 := StartX;
  630.   Y1 := StartY;
  631.   Y2 := StartY;
  632. end;
  633.  
  634. { Scale the old line coordinates to the new Xmax and Ymax coordinates.
  635.   The new Xmax and new Ymax are passed in as parameters so we can
  636.   calculate the scaling ratios. }
  637. procedure TList.ScaleTo(NewXmax, NewYMax: Integer);
  638. var
  639.   I: Integer;
  640.   RatioX, RatioY: Real;
  641. begin
  642.   if (Xmax = 0) or (Ymax = 0) then { at startup, Xmax and Ymax are zero }
  643.   begin
  644.     Xmax := NewXmax;
  645.     Ymax := NewYmax;
  646.     ResetLines;
  647.   end
  648.   else
  649.   begin
  650.     RatioX := NewXMax / Xmax;
  651.     RatioY := NewYmax / Ymax;
  652.     X1 := Trunc(X1 * RatioX);
  653.     X2 := Trunc(X2 * RatioX);
  654.     Y1 := Trunc(Y1 * RatioY);
  655.     Y2 := Trunc(Y2 * RatioY);
  656.     for I := 1 to MaxLines do
  657.       with Line^[I] do
  658.       begin
  659.     LX1 := Trunc(LX1 * RatioX);
  660.     LX2 := Trunc(LX2 * RatioX);
  661.     LY1 := Trunc(LY1 * RatioY);
  662.     LY2 := Trunc(LY2 * RatioY);
  663.       end;
  664.   end;
  665.   Xmax := NewXmax;
  666.   Ymax := NewYmax;
  667. end;
  668.  
  669. { The low-level Draw method of the object. }
  670. procedure TList.Draw(DC: HDC; a1, b1, a2, b2: Integer; lPenColor: Longint);
  671. var
  672.   OldPen: HPen;
  673. begin
  674.   OldPen := SelectObject(DC, CreatePen(PS_SOLID, 1, lPenColor));
  675.   MoveTo(DC, a1, b1);
  676.   LineTo(DC, a2, b2);
  677.   DeleteObject(SelectObject(DC, OldPen));
  678. end;
  679.  
  680. { The high-level Draw method of the object. }
  681. procedure TList.DrawLine(DC: HDC; Index: Integer);
  682. begin
  683.   with Line^[Index] do
  684.     Draw(DC, LX1, LY1, LX2, LY2, Color);
  685. end;
  686.  
  687. { The high-level draw which erases a line. }
  688. procedure TList.EraseLine(DC: HDC; Index: Integer);
  689. begin
  690.   with Line^[Index] do
  691.     Draw(DC, LX1, LY1, LX2, LY2, RGB(0, 0, 0));
  692. end;
  693.  
  694. { Redraw all the lines in the array. }
  695. procedure TList.Redraw(DC: HDC);
  696. var I: Integer;
  697. begin
  698.   for I := 1 to MaxLines do
  699.     DrawLine(DC, I);
  700. end;
  701.  
  702. { Reset the color counter and pick a random color. }
  703. procedure TList.SelectNewColor;
  704. begin
  705.   ColorDuration := MaxColorDuration;
  706.   PenColor := RGB(Random(256), Random(256), Random(256));
  707. end;
  708.  
  709. { Pick random directional deltas and reset the delta counter. }
  710. procedure TList.SelectNewDeltaValues;
  711. begin
  712.   DeltaX1 := Random(MaxDelta)-(MaxDelta Div 2);
  713.   DeltaX2 := Random(MaxDelta)-(MaxDelta Div 2);
  714.   DeltaY1 := Random(MaxDelta)-(MaxDelta Div 2);
  715.   DeltaY2 := Random(MaxDelta)-(MaxDelta Div 2);
  716.   IncrementCount := 2*(1+Random(10));
  717. end;
  718.  
  719. { Process the movement of one line. }
  720. procedure TList.LineTick(DC: HDC);
  721. begin
  722.     EraseLine(DC, CurrentLine);
  723.     if ColorDuration < 0 then SelectNewColor;
  724.     if IncrementCount=0 then SelectNewDeltaValues;
  725.     AdjustX(X1,DeltaX1); AdjustX(X2,DeltaX2);
  726.     AdjustY(Y1,DeltaY1); AdjustY(Y2,DeltaY2);
  727.     with Line^[CurrentLine] do
  728.     begin
  729.       LX1 := X1;  LX2 := X2;
  730.       LY1 := Y1;  LY2 := Y2;
  731.       Color := PenColor;
  732.     end;
  733.     DrawLine(DC, CurrentLine);
  734.     Inc(CurrentLine);
  735.     if CurrentLine > MaxLines then CurrentLine := 1;
  736.     Dec(ColorDuration);
  737.     Dec(IncrementCount);
  738. end;
  739.  
  740. { Draw the line and 3 reflections of it. }
  741. procedure TQuadList.DrawLine(DC: HDC; Index: Integer);
  742. begin
  743.   with Line^[Index] do
  744.   begin
  745.     Draw(DC,LX1,LY1,LX2,LY2,Color);
  746.     Draw(DC,Xmax-LX1,LY1,Xmax-LX2,LY2,Color);
  747.     Draw(DC,LX1,Ymax-LY1,LX2,Ymax-LY2,Color);
  748.     Draw(DC,Xmax-LX1,Ymax-LY1,Xmax-LX2,Ymax-LY2,Color);
  749.   end;
  750. end;
  751.  
  752. { Erase the line and 3 reflections of it. }
  753. procedure TQuadList.EraseLine(DC: HDC; Index: Integer);
  754. begin
  755.   with Line^[Index] do
  756.   begin
  757.     Draw(DC, LX1, LY1, LX2, LY2, RGB(0,0,0));
  758.     Draw(DC, Xmax-LX1, LY1,Xmax-LX2, LY2, RGB(0,0,0));
  759.     Draw(DC, LX1,Ymax-LY1, LX2, Ymax-LY2, RGB(0,0,0));
  760.     Draw(DC, Xmax-LX1, Ymax-LY1, Xmax-LX2, Ymax-LY2, RGB(0,0,0));
  761.   end;
  762. end;
  763.  
  764. constructor TArtyWindow.Init(AParent: PWindowsObject; ATitle: PChar);
  765. begin
  766.   TNoIconWindow.Init(AParent, ATitle);
  767.   StaticControl := New(PStatic,Init(@Self,100,
  768.     'Press Left Button to pause, Right Button to Clear',10,10,10,10,0));
  769.   Iconized := False;
  770.   TextHeight := 20;
  771.  
  772.   { Initialize two line list objects:
  773.       BigLineList is the 4-reflection artwork that is displayed in
  774.     a full sized window.  Mouse clicks will pause or clear
  775.     the display, and the line list will be scaled to the
  776.     new window coordinates when the window is resized.
  777.       IconicLineList is a smaller list implementing a single-line
  778.     quark to display in the iconized window region.  Since
  779.     mouse clicks are not sent to iconized windows, the icon
  780.     cannout be paused or cleared, and since there is only one
  781.     icon window size, scaling the lines to new coordinates
  782.     has no visual effect.
  783.     The List pointer will be toggled between the two line list
  784.     objects: when the window is iconized, List will point to the
  785.     IconicLineList object.  When the window is restored to full
  786.     size, List will be made to point to the BigLineList object.
  787.     This is so the window routines don't have to know which kind
  788.     of list they're dealing with.  Keyword: polymorphism.   }
  789.  
  790.   BigLineList := New(PQuadList, Init(MaxLineCount));
  791.   IconicLineList := New(PList, Init(MaxIconicLineCount));
  792.   List := BigLineList;
  793. end;
  794.  
  795. { Dispose of the objects that this window object created.  There's
  796.   no need to dispose the List pointer, since it will only point to
  797.   one of these two objects which are being disposed by their
  798.   primary pointers }
  799. destructor TArtyWindow.Done;
  800. begin
  801.   TNoIconWindow.Done;
  802.   Dispose(BigLineList, Done);
  803.   Dispose(IconicLineList, Done);
  804. end;
  805.  
  806. { When the window is resized, scale the line list to fit the new
  807.   window extent, or switch between full size and iconized window
  808.   states.  }
  809. procedure TArtyWindow.WMSize(var Msg: TMessage);
  810. var
  811.   NewXmax, NewYmax: Integer;
  812. begin
  813.   TNoIconWindow.WMSize(Msg);
  814.   { Force Windows to repaint the entire window region }
  815.   InvalidateRect(HWindow, nil, True);
  816.   NewXmax := Msg.LParamLo;
  817.   NewYmax := Msg.LParamHi;
  818.   if IsIconic(HWindow) then
  819.     if not Iconized then
  820.     begin
  821.       Iconized := True;
  822.       List := IconicLineList;
  823.     end
  824.     else
  825.   else
  826.   begin
  827.     if Iconized then
  828.     begin
  829.       Iconized := False;
  830.       List := BigLineList;
  831.     end;
  832.     Dec(NewYmax, TextHeight);  { allow room for the text at the bottom }
  833.   end;
  834.   List^.ScaleTo(NewXmax, NewYmax);  { scale the lines in the list }
  835.   MoveWindow(StaticControl^.HWindow, 0, NewYmax, NewXmax, TextHeight, True);
  836. end;
  837.  
  838. { Toggle the list object's Paused status.  Since the window will
  839.   not receive mouse clicks when iconized, this will not pause the
  840.   iconized lines display.  }
  841. procedure TArtyWindow.WMLButtonDown(var Message: TMessage);
  842. begin
  843.   List^.Paused := not List^.Paused;
  844. end;
  845.  
  846. { Clear the line list when the user presses the right mouse
  847.   button.  Same comments as above on iconized windows.  }
  848. procedure TArtyWindow.WMRButtonDown(var Message: TMessage);
  849. begin
  850.   InvalidateRect(HWindow,nil,True);
  851.   List^.ResetLines;
  852. end;
  853.  
  854. { When the window is resized, or some other window blots out part
  855.   of our client area, redraw the entire line list.  The PaintDC
  856.   is fetched before Paint is called and is released for us after
  857.   Paint is finished. }
  858. procedure TArtyWindow.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  859. begin
  860.   TNoIconWindow.Paint(PaintDC, PaintInfo);
  861.   List^.Redraw(PaintDC);
  862. end;
  863.  
  864. { Fetch a device context, pass it to the line list object, then
  865.   release the device context back to Windows.  }
  866. procedure TArtyWindow.TimerTick;
  867. var
  868.   DC: HDC;
  869. begin
  870.   if not List^.Paused then
  871.   begin
  872.     DC := GetDC(HWindow);
  873.     List^.LineTick(DC);
  874.     ReleaseDC(HWindow, DC);
  875.   end;
  876. end;
  877.  
  878. { TGDIDemoWindow --------------------------------------------------- }
  879.  
  880. type
  881.   PGDIDemoWindow = ^TGDIDemoWindow;
  882.   TGDIDemoWindow = object(TMDIWindow)
  883.     procedure SetupWindow; virtual;
  884.     procedure MoveToLineToDemo(var Msg: TMessage);
  885.       virtual cm_First + MoveToLineToDemoID;
  886.     procedure FontDemo(var Msg: TMessage);
  887.       virtual cm_First + FontDemoID;
  888.     procedure BitBltDemo(var Msg: TMessage);
  889.       virtual cm_First + BitBltDemoID;
  890.     procedure ArtyDemo(var Msg: TMessage);
  891.       virtual cm_First + ArtyDemoID;
  892.     procedure Quit(var Msg: TMessage);
  893.       virtual cm_First + QuitID;
  894.     procedure WMTimer(var Msg: TMessage);
  895.       virtual wm_First + wm_Timer;
  896.     procedure WMDestroy(var Msg: TMessage);
  897.       virtual wm_First + wm_Destroy;
  898.   end;
  899.  
  900. procedure TGDIDemoWindow.SetupWindow;
  901. var
  902.   Result: Integer;
  903. begin
  904.   TMDIWindow.SetupWindow;
  905.   Result := IDRetry;
  906.   while (SetTimer(hWIndow, 0, 50, nil) = 0) and (Result = IDRetry) do
  907.     Result := MessageBox(GetFocus,'Could not Create Timer', 'GDIDemo',
  908.       mb_RetryCancel);
  909.   if Result = IDCancel then PostQuitMessage(0);
  910. end;
  911.  
  912. procedure TGDIDemoWindow.MoveToLineToDemo(var Msg: TMessage);
  913. begin
  914.   Application^.MakeWindow(New(PMoveToLineToWindow, Init(@Self,
  915.     'MoveTo/LineTo Window')));
  916. end;
  917.  
  918. procedure TGDIDemoWindow.FontDemo(var Msg: TMessage);
  919. begin
  920.   Application^.MakeWindow(New(PFontWindow, Init(@Self, 'Font Window')));
  921. end;
  922.  
  923. procedure TGDIDemoWindow.BitBltDemo(var Msg: TMessage);
  924. begin
  925.   Application^.MakeWindow(New(PBitBltWindow, Init(@Self, 'BitBlt Window')));
  926. end;
  927.  
  928. procedure TGDIDemoWindow.ArtyDemo(var Msg: TMessage);
  929. begin
  930.   Application^.MakeWindow(New(PArtyWindow, Init(@Self, 'Arty Window')));
  931. end;
  932.  
  933. procedure TGDIDemoWindow.Quit(var Msg: TMessage);
  934. begin
  935.   CloseWindow;
  936. end;
  937.  
  938. { In response to WMTimer messages, each MDI child window's TimerTick
  939.   Method is called. }
  940. procedure TGDIDemoWindow.WMTimer(var Msg: TMessage);
  941.  
  942.   procedure ChildTimers(PChildWindow: PBaseDemoWindow); far;
  943.   begin
  944.     PChildWindow^.TimerTick;
  945.   end;
  946.  
  947. begin
  948.   ForEach(@ChildTimers);
  949. end;
  950.  
  951. procedure TGDIDemoWindow.WMDestroy(var Msg: TMessage);
  952. begin
  953.   KillTimer(HWindow, 0);
  954.   TMDIWindow.WMDestroy(Msg);
  955. end;
  956.  
  957. { TGDIDemoApp ------------------------------------------------------ }
  958.  
  959. type
  960.   TGDIDemoApp = object(TApplication)
  961.     procedure InitMainWindow; virtual;
  962.   end;
  963.  
  964. procedure TGDIDemoApp.InitMainWindow;
  965. begin
  966.   { Create a main window of type TGDIWindow. }
  967.   MainWindow := New(PGDIDemoWindow,
  968.     Init('GDI Demo', LoadMenu(HInstance,MakeIntResource(MenuID))));
  969. end;
  970.  
  971. var
  972.   GDIDemoApp: TGDIDemoApp;
  973.  
  974. begin
  975.   GDIDemoApp.Init('GDIDEMO');
  976.   GDIDemoApp.Run;
  977.   GDIDemoApp.Done;
  978. end.
  979.