home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TVLIFE.ZIP / TVLIFE.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1992-02-16  |  10.9 KB  |  423 lines

  1. PROGRAM TVLife;
  2.  
  3. {                        Turbo Vision Life  v1.0                         }
  4. {                            by Ben Ziegler                              }
  5. {                          February 16, 1992                             }
  6. {                                                                        }
  7. {  TVLife is a simple program that illustrates a few of Turbo Visions's  }
  8. {  features:  1) how to use the Idle event to execute background tasks,  }
  9. {  and 2) how to incorporate menus inside of Twindows.  It is merely     }
  10. {  meant to be a demonstration program for Turbo Pascal v6.0             }
  11. {                                                                        }
  12. {  Send any questions or comments to:                                    }
  13. {                                                                        }
  14. {     Ben Ziegler                  Internet Email Address:               }
  15. {     4010 Terrace Dr              bpz4r@virginia.edu                    }
  16. {     Annandale, VA  22003         (email valid until May 1992)          }
  17.  
  18.  
  19. {$R-,S-}                          { This will speed up program execution }
  20.  
  21. USES Objects, Drivers, Views, Menus, App;
  22.  
  23. CONST
  24.   cmLife        = 101;            { Opens a Life window           }
  25.   cmIdle        = 102;            { issued when TV is Idle        }
  26.   cmStart       = 103;            { Starts a Life window running  }
  27.   cmStop        = 104;            { Stops a Life window           }
  28.   cmClearBoard  = 105;            { Clears the Life Board         }
  29.   cmRandom      = 106;            { Randomly fills the Life Board }
  30.   cmHighRes     = 107;            { Set Screen to VGA 43/50 Lines }
  31.   cmLowRes      = 108;            { Set Screen to 25 Lines        }
  32.  
  33.   Xm            = 80;             { Max X Size of Life Window     }
  34.   Ym            = 48;             { Max Y Size of Life Window     }
  35.  
  36. TYPE
  37.   Board         = array[1..Xm, 1..Ym] of byte;
  38.  
  39.   TMyApp        = object(TApplication)
  40.     constructor Init;
  41.     procedure   HandleEvent(var Event: TEvent); virtual;
  42.     procedure   InitMenuBar; virtual;
  43.     procedure   InitStatusLine; virtual;
  44.     procedure   idle; virtual;
  45.     procedure   DoLife;
  46.     procedure   HighRes;
  47.     procedure   LowRes;
  48.   end;
  49.  
  50.   PMyMenuBar    = ^TMyMenuBar;
  51.   TMyMenuBar    = object(TMenuBar)
  52.      function   GetPalette: PPalette; virtual;
  53.   end;
  54.  
  55.   PLifeInterior = ^TLifeInterior;
  56.   TLifeInterior = object(Tview)
  57.     OldB        : ^Board;
  58.     mx,my       : integer;
  59.     running     : boolean;
  60.     constructor Init(var Bounds: TRect);
  61.     procedure   HandleEvent(var Event:TEvent); virtual;
  62.     procedure   Iterate(var o : Board);
  63.     procedure   InitBoard(var b : Board);
  64.     procedure   ClearBoard(var b : Board);
  65.     procedure   Update; virtual;
  66.     procedure   Draw; virtual;
  67.   end;
  68.  
  69.   PLifeView     = ^TLifeView;
  70.   TLifeView     = object(TWindow)
  71.     MyInterior  : PLifeInterior;
  72.     MB          : PMyMenuBar;
  73.     constructor Init(Bounds:Trect; s : string; num:integer);
  74.     procedure   handleevent(var event : Tevent); virtual;
  75.     procedure   SizeLimits(var Min, Max: TPoint); virtual;
  76.     end;
  77.  
  78. { ************* }
  79. { TLifeInterior }
  80. { ************* }
  81.  
  82. CONSTRUCTOR TLifeInterior.Init(var Bounds: TRect);
  83. BEGIN
  84.    TView.Init(Bounds);
  85.    GrowMode  := gfGrowHiX + gfGrowHiY;
  86.    Options   := Options OR ofFramed;
  87.    EventMask := $FFFF;                   { Listen for all types of events }
  88.    mx        := 0;
  89.    my        := 0;
  90.  
  91.    NEW(OldB);
  92.    InitBoard(OldB^);
  93. end;
  94.  
  95. PROCEDURE TLifeInterior.InitBoard(var b : Board);
  96. VAR
  97.    x,y,i : integer;
  98. BEGIN
  99.    FOR x := 1 TO Xm DO
  100.       FOR y := 1 TO Ym DO
  101.          b[x,y] := 0;
  102.    Randomize;
  103.    FOR i := 1 TO 999 DO BEGIN
  104.       x := Random(Xm-2)+2;
  105.       y := Random(Ym-2)+2;
  106.       b[x,y] := 1;
  107.       END;
  108. END;
  109.  
  110. PROCEDURE TLifeInterior.ClearBoard(var b : Board);
  111. VAR
  112.    x,y   : integer;
  113. BEGIN
  114.    FOR x := 1 TO Xm DO
  115.       FOR y := 1 TO Ym DO
  116.          b[x,y] := 0;
  117. END;
  118.  
  119. PROCEDURE TLifeInterior.Draw;
  120. VAR
  121.    x,y   : integer;
  122.    R     : TRect;
  123.    ex,ey : integer;
  124.    B     : array[0..2047] of word;    { Buffer used to speed up Draw }
  125. BEGIN
  126.    GetExtent(R);
  127.    ex := R.B.X+1;
  128.    ey := R.B.Y+1;
  129.  
  130.    FOR y := 2 TO ey DO BEGIN
  131.       FOR x := 2 TO ex DO BEGIN
  132.          IF OldB^[x,y]=0 THEN BEGIN
  133.             MoveChar(B[x-2], #32, GetColor(2), 1);
  134.             END
  135.          ELSE BEGIN
  136.             MoveChar(B[x-2], #9, GetColor(2), 1);
  137.             END;
  138.          END;
  139.       WriteLine(0, y-2, Size.X, 1, B);
  140.       END;
  141. END;
  142.  
  143. PROCEDURE TLifeInterior.Iterate(var o : Board);
  144. VAR
  145.    x,y,num : integer;
  146.    n       : Board;
  147. BEGIN
  148.    n := o;
  149.  
  150.    FOR x := 2 TO Xm-1 DO
  151.       FOR y := 2 TO Ym-1 DO BEGIN
  152.          { Find number of neighbors }
  153.          num := o[x-1,y-1] + o[x,y-1] + o[x+1,y-1]
  154.               + o[x-1,y]              + o[x+1,y]
  155.               + o[x-1,y+1] + o[x,y+1] + o[x+1,y+1];
  156.          IF o[x,y]=1 THEN
  157.             IF ((num=2) OR (num=3)) THEN n[x,y] := 1
  158.                ELSE n[x,y] := 0;
  159.          IF o[x,y]=0 THEN
  160.             IF num=3 THEN n[x,y] := 1   { Birth = 3! }
  161.                ELSE n[x,y] := 0;
  162.          END;
  163.  
  164.    o := n;
  165. END;
  166.  
  167. PROCEDURE TLifeInterior.Update;
  168. BEGIN
  169.    Iterate(OldB^);
  170.    Draw;
  171. END;
  172.  
  173. PROCEDURE TLifeInterior.HandleEvent(var event : Tevent);
  174. VAR
  175.    p,o : Tpoint;
  176. BEGIN
  177.    tview.handleevent(event);
  178.    IF event.what = evCommand THEN
  179.       CASE event.command OF
  180.          cmStart : running := TRUE;
  181.          cmStop  : running := FALSE;
  182.          end;
  183.    IF event.what = evBroadCast THEN
  184.       IF event.command = cmIdle THEN BEGIN
  185.          IF running THEN Update;
  186.          END;
  187.    IF event.what = evCommand THEN
  188.       IF event.command = cmClearBoard THEN BEGIN
  189.          ClearBoard(OldB^);
  190.          Draw;
  191.          ClearEvent(event);
  192.          END;
  193.    IF event.what = evCommand THEN
  194.       IF event.command = cmRandom THEN BEGIN
  195.          InitBoard(OldB^);
  196.          Draw;
  197.          ClearEvent(event);
  198.          END;
  199.  
  200.    IF (event.what AND (evMouseDown OR evMouseAuto)) <> 0 THEN BEGIN
  201.          o := event.where;
  202.          MakeLocal(o, p);
  203.          p.x := p.x+2;
  204.          p.y := p.y+2;
  205.          IF (mx<>p.x) OR (my<>p.y) THEN BEGIN
  206.             OldB^[p.x, p.y] := 1-OldB^[p.x, p.y];
  207.             Draw;
  208.             mx := p.x;
  209.             my := p.y;
  210.             END;
  211.          END;
  212. END;
  213.  
  214.  
  215. { ********* }
  216. { TLifeView }
  217. { ********* }
  218.  
  219. CONSTRUCTOR TLifeView.Init(Bounds:Trect; s : string; num:integer);
  220. VAR
  221.    R : TRect;
  222. BEGIN
  223.    Twindow.init(Bounds, s, num);
  224.  
  225.    GetExtent(R);
  226.    R.Grow(-1,-1);
  227.    R.B.Y := R.A.Y + 1;
  228.    MB := New(PMyMenuBar, Init(R, NewMenu(
  229.      NewSubMenu('~A~ction', hcNoContext, NewMenu(
  230.        NewItem('~S~tart', 'Alt-S', kbAltS, cmStart, hcNoContext,
  231.        NewItem('Sto~p~', 'Alt-P', kbAltP, cmStop, hcNoContext,
  232.        NewItem('~C~lear Board', 'Alt-C', kbAltC, cmClearBoard, hcNoContext,
  233.        NewItem('~R~andomize', 'Alt-R', kbAltR, cmRandom, hcNoContext,
  234.        NewLine(
  235.        NewItem('Close ~W~indow', 'Alt-F3', kbAltF3, cmClose, hcNoContext,
  236.        nil))))))),
  237.      nil)
  238.    )));
  239.    Insert(MB);
  240.  
  241.    GetClipRect(Bounds);
  242.    Bounds.Grow(-1,-2);
  243.    Bounds.B.y := Bounds.b.y + 1;
  244.    MyInterior := New(PLifeInterior, Init(Bounds));
  245.    Insert(MyInterior);
  246.  
  247.    Options := Options OR (ofFirstClick OR ofTileable);
  248.    dragmode := $F0;                     { Can't move window off screen }
  249. END;
  250.  
  251. PROCEDURE TLifeView.HandleEvent(var event : Tevent);
  252. VAR
  253.    HelloThere : pointer;
  254. BEGIN
  255.    { NOTE:  HelloThere must come before twindow.he or CRASH! }
  256.    HelloThere := Message(MyInterior, event.what, event.command, nil);
  257.    Twindow.HandleEvent(event);
  258. END;
  259.  
  260. PROCEDURE TLifeView.SizeLimits(var Min, Max: TPoint);
  261. CONST
  262.    MyMin : TPoint = (X: 28; Y: 11);
  263. VAR
  264.    R     : TRect;
  265. BEGIN
  266.    Desktop^.GetExtent(R);
  267.    Min := MyMin;
  268.    Max := R.B;
  269. END;
  270.  
  271.  
  272. { ********** }
  273. { TMyMenuBar }
  274. { ********** }
  275.  
  276. FUNCTION TMyMenuBar.GetPalette: PPalette;
  277. CONST
  278.    CMyStuff = #4#3#6#5#6#7;
  279.    PMyStuff : string[Length(CMyStuff)] = CMyStuff;
  280. BEGIN
  281.    GetPalette := @PMyStuff;
  282. END;
  283.  
  284. { ****** }
  285. { TMyApp }
  286. { ****** }
  287.  
  288. PROCEDURE Tile;
  289. VAR
  290.    R: TRect;
  291. BEGIN
  292.    Desktop^.GetExtent(R);
  293.    Desktop^.Tile(R);
  294. END;
  295.  
  296. PROCEDURE Cascade;
  297. VAR
  298.    R: TRect;
  299. BEGIN
  300.    Desktop^.GetExtent(R);
  301.    Desktop^.Cascade(R);
  302. END;
  303.  
  304. PROCEDURE TMyApp.HandleEvent(var Event: TEvent);
  305. BEGIN
  306.   TApplication.HandleEvent(Event);
  307.   IF Event.What = evCommand THEN BEGIN
  308.     CASE Event.Command OF
  309.       cmLife    : DoLife;
  310.       cmTile    : Tile;
  311.       cmCascade : Cascade;
  312.       cmHighRes : HighRes;
  313.       cmLowRes  : LowRes;
  314.     ELSE
  315.       Exit;
  316.     END;
  317.     ClearEvent(Event);
  318.   END;
  319. END;
  320.  
  321. PROCEDURE TMyApp.InitMenuBar;
  322. VAR
  323.    R: TRect;
  324. BEGIN
  325.   GetExtent(R);
  326.   R.B.Y := R.A.Y + 1;
  327.   MenuBar := New(PMenuBar, Init(R, NewMenu(
  328.     NewSubMenu('~F~ile', hcNoContext, NewMenu(
  329.       NewItem('~L~ife Window', 'F9', kbF9, cmLife, hcNoContext,
  330.       NewLine(
  331.       NewItem('E~x~it', 'Alt-X', kbAltX, cmQuit, hcNoContext,
  332.       nil)))),
  333.     NewSubMenu('~W~indow', hcNoContext, NewMenu(
  334.       NewItem('~N~ext', 'F6', kbF6, cmNext, hcNoContext,
  335.       NewItem('~Z~oom', 'F5', kbF5, cmZoom, hcNoContext,
  336.       NewItem('~T~ile', '', 0, cmTile, 0,
  337.       NewItem('~C~ascade', '', 0, cmCascade, 0,
  338.       NewItem('~H~igh Res', 'Alt-H', kbAltH, cmHighRes, 0,
  339.       NewItem('~L~ow Res', 'Alt-L', kbAltL, cmLowRes, 0,
  340.       nil))))))),
  341.     nil)
  342.   ))));
  343. END;
  344.  
  345. PROCEDURE TMyApp.InitStatusLine;
  346. VAR
  347.    R: TRect;
  348. BEGIN
  349.   GetExtent(R);
  350.   R.A.Y := R.B.Y - 1;
  351.   StatusLine := New(PStatusLine, Init(R,
  352.     NewStatusDef(0, $FFFF,
  353.       NewStatusKey('', kbF10, cmMenu,
  354.       NewStatusKey('~Alt-X~ Exit', kbAltX, cmQuit,
  355.       NewStatusKey('~F9~ Life Window', kbF9, cmLife,
  356.       NewStatusKey('~Alt-F3~ Close', kbAltF3, cmClose,
  357.       nil)))),
  358.     nil)
  359.   ));
  360. END;
  361.  
  362. PROCEDURE TMyApp.DoLife;
  363. VAR
  364.    R    : TRect;
  365.    R2   : TRect;
  366.    Life : PLifeView;
  367. BEGIN
  368.    GetExtent(R2);
  369.    R.Assign(0, 0, 28, 11);
  370.    R.Move(Random(R2.B.X-29), Random(R2.B.Y-12));
  371.    Life := New(PLifeView, Init(R, 'Life', 0));
  372.    Desktop^.Insert(Life);
  373. END;
  374.  
  375. PROCEDURE TMyApp.Idle;
  376. VAR
  377.    HelloThere : pointer;
  378.  
  379. FUNCTION IsTileable(P: PView): Boolean; far;
  380. BEGIN
  381.    IsTileable := P^.Options and ofTileable <> 0;
  382. END;
  383.  
  384. BEGIN
  385.    TApplication.Idle;
  386.    IF Desktop^.FirstThat(@IsTileable) <> NIL THEN
  387.       EnableCommands([cmTile, cmCascade])
  388.    ELSE
  389.       DisableCommands([cmTile, cmCascade]);
  390.  
  391.    HelloThere := Message(DeskTop, evBroadcast, cmIdle, nil);
  392. end;
  393.  
  394. PROCEDURE TMyApp.HighRes;
  395. BEGIN
  396.    SetScreenMode(ScreenMode OR smFont8x8);
  397.    DisableCommands([cmHighRes]);
  398.    EnableCommands([cmLowRes]);
  399. END;
  400.  
  401. PROCEDURE TMyApp.LowRes;
  402. BEGIN
  403.    SetScreenMode(ScreenMode AND NOT smFont8x8);
  404.    DisableCommands([cmLowRes]);
  405.    EnableCommands([cmHighRes]);
  406. END;
  407.  
  408. CONSTRUCTOR TMyApp.Init;
  409. BEGIN
  410.    Tapplication.init;
  411.    DisableCommands([cmLowRes]);
  412. END;
  413.  
  414.  
  415. VAR
  416.    MyApp: TMyApp;
  417.  
  418. BEGIN
  419.   MyApp.Init;
  420.   MyApp.Run;
  421.   MyApp.Done;
  422. END.
  423.