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