home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 14 / CDACTUAL.iso / cdactual / demobin / share / program / Pascal / TVDMX.ZIP / TVGIZMA.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1993-04-01  |  19.4 KB  |  767 lines

  1.  
  2. {■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■}
  3. {                            }
  4. {    tvGIZMA   --Turbo Vision Accessories        }
  5. {                            }
  6. {    Copyright (c) 1992,93   Randolph Beck        }
  7. {                P.O. Box  56-0487    }
  8. {                Orlando, FL 32856    }
  9. {                CIS:  72361,753        }
  10. {                            }
  11. {■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■}
  12.  
  13. Unit tvGIZMA;
  14.  
  15. {$D-,B-,O+,R-,V-,X+ }
  16.  
  17. interface
  18.  
  19. uses
  20.     Dos, Crt, Objects, Drivers, Memory, Dialogs, Menus,
  21.     HistList, Views, App, MsgBox, RSet, DmxGizma;
  22.  
  23. const
  24.     BeepOn       : boolean = TRUE;    { allows beeping from cmBeep event }
  25.     PreserveScreen : boolean = TRUE;    { restores screen after done }
  26.  
  27.     SoundIndOn        = ' ON';    { On & Off must be the same length }
  28.     SoundIndOff        = 'OFF';
  29.     VideoIndHi        = '43/50';    { Hi & Low must be the same length }
  30.     VideoIndLow        = '   25';
  31.  
  32. type
  33.     PAppA        = ^TAppA;
  34.     PLtdFrame        = ^TLtdFrame;
  35.     PLtdWindow        = ^TLtdWindow;
  36.     PTimeView        = ^TTimeView;
  37.     PUserScreen        = ^TUserScreen;
  38.  
  39.  
  40.     TAppA        =  OBJECT (TApplication)
  41.     Clock        : PTimeView;
  42.     SoundInd    : pstring;
  43.     VideoInd    : pstring;
  44.       constructor Init;
  45.       destructor  Done;  VIRTUAL;
  46.       procedure EventError (var Event : TEvent);  VIRTUAL;
  47.       procedure HandleEvent (var Event : TEvent);  VIRTUAL;
  48.       procedure Idle;  VIRTUAL;
  49.       procedure InitClock;  VIRTUAL;
  50.       function  NewSoundItem (AHelpCtx : word; ANext : PMenuItem) : PMenuItem;
  51.       function  NewVideoItem (AHelpCtx : word; ANext : PMenuItem) : PMenuItem;
  52.       procedure OutOfMemory;  VIRTUAL;
  53.     end;
  54.  
  55.  
  56.     TLtdFrame        =  OBJECT (TFrame)
  57.       procedure Draw;  VIRTUAL;
  58.     end;
  59.  
  60.  
  61.     TLtdWindow        =  OBJECT (TWindow)
  62.     Limit    : TRect;
  63.       constructor Init (var Bounds,ALimit : TRect; ATitle : TTitleStr; ANumber : integer);
  64.       constructor Load (var S : TStream);
  65.       procedure ChangeBounds (var Bounds : TRect);  VIRTUAL;
  66.       procedure InitFrame;  VIRTUAL;
  67.       procedure Zoom;  VIRTUAL;
  68.     end;
  69.  
  70.  
  71.     TTimeView        =  OBJECT (TView)
  72.     Hour,Min,Sec    : word;
  73.       constructor Init (var Bounds : TRect);
  74.       procedure Draw;  VIRTUAL;
  75.       procedure Update;  VIRTUAL;
  76.     end;
  77.  
  78.  
  79.     TUserScreen        =  OBJECT (TScroller)
  80.       constructor Init (var Bounds : TRect; AHScrollBar,AVScrollBar : PScrollBar);
  81.       procedure Draw;  VIRTUAL;
  82.       procedure HandleEvent (var Event : TEvent);  VIRTUAL;
  83.       function  Valid (Command : word) : boolean;  VIRTUAL;
  84.     end;
  85.  
  86.  
  87.   function  SParam (S : pstring;  Next : pointer) : pointer;
  88.   function  DParam (N : longint;  Next : pointer) : pointer;
  89.     { accessories for FormatStr() and MessageBox() procedures }
  90.  
  91.  
  92.   procedure AssignWinRect (var Bounds : TRect;  MaxX,MaxY : integer);
  93.     { assigns a rectangle which cascades into the desktop }
  94.  
  95.   function  InsertLine (Dialog : PDialog;  Col,Row,Width,Max : integer;
  96.             Fmt : boolean; ALabel : string; HL : word) : PInputLine;
  97.     { inserts a TInputLine view with (optional) history list }
  98.  
  99.   function  InsertText (Dialog : PDialog; Col,Row : integer; AText : string) : PView;
  100.     { inserts a single-line standard text view }
  101.  
  102.   function  InsertView (Owner :PGroup; View :PView; Options :word) : pointer;
  103.     { sets a view's options and inserts it into an owner }
  104.  
  105.   function  NewVarItem (Name, Param : TMenuStr; var Ind : pstring;
  106.             KeyCode, Command, AHelpCtx : word;
  107.             Next : PMenuItem) : PMenuItem;
  108.     { creates a new menu item with a status indicator }
  109.  
  110.   function  wnNextAvail : integer;
  111.   function  NextWindowNumber  : integer;
  112.     { finds an unused window number
  113.       --function NextWindowNumber() is changing its name.
  114.         It will be removed in a future version.
  115.      }
  116.  
  117.   procedure TrimDialog (Window : PWindow);
  118.     { resizes a dialog window }
  119.  
  120.   procedure RegisterTVGizma;
  121.  
  122.  
  123. const
  124.     RLtdFrame     :  TStreamRec = (
  125.     ObjType:  rnLtdFrame;
  126.     VmtLink:  ofs (TypeOf (TLtdFrame)^);
  127.     Load:     @TLtdFrame.Load;
  128.     Store:    @TLtdFrame.Store
  129.       );
  130.  
  131.     RLtdWindow    :  TStreamRec = (
  132.     ObjType:  rnLtdWindow;
  133.     VmtLink:  ofs (TypeOf (TLtdWindow)^);
  134.     Load:     @TLtdWindow.Load;
  135.     Store:    @TLtdWindow.Store
  136.       );
  137.  
  138.  
  139. implementation
  140.  
  141. const KeptScreen    : PVideoBuf = nil;
  142. var   KeptCol, KeptRow    : byte;
  143.  
  144.  
  145.   { ══ Param Functions ═══════════════════════════════════════════════════ }
  146.  
  147. const    iparmax            = 15;  { max number of parameters - 1 }
  148.     ipar    : integer    = iparmax;
  149.  
  150. var    Apar    : array [0..iparmax] of pointer;
  151.  
  152.  
  153. function  SParam (S : pstring;  Next : pointer) : pointer;
  154. begin
  155.   {$IFOPT R+ }
  156.   If (ipar < 0) then RunError (201);
  157.   {$ENDIF }
  158.   If (Next = nil) then ipar := iparmax;
  159.   Apar [ipar] := S;
  160.   SParam := @Apar [ipar];
  161.   Dec (ipar);
  162. end;
  163.  
  164.  
  165. function  DParam (N : longint;  Next : pointer) : pointer;
  166. begin
  167.   {$IFOPT R+ }
  168.   If (ipar < 0) then RunError (201);
  169.   {$ENDIF }
  170.   If (Next = nil) then ipar := iparmax;
  171.   Apar [ipar] := pointer (N);
  172.   DParam := @Apar [ipar];
  173.   Dec (ipar);
  174. end;
  175.  
  176.  
  177.   { ══════════════════════════════════════════════════════════════════════ }
  178.  
  179.  
  180. procedure AssignWinRect (var Bounds : TRect;  MaxX,MaxY : integer);
  181. var  P : PView;
  182. begin
  183.  {$IFDEF VER60 }
  184.   DeskTop^.GetExtent (Bounds);
  185.  {$ELSE }
  186.   PApplication (Application)^.GetTileRect (Bounds);
  187.  {$ENDIF }
  188.   P := DeskTop^.Current;
  189.   If (P <> nil) and (P^.Options and ofTileable = 0) then P := nil;
  190.   If (P <> nil) then
  191.     begin
  192.     If (P^.Origin.X >= Bounds.A.X) and (P^.Origin.X < Bounds.B.X) then Bounds.A.X := succ (P^.Origin.X);
  193.     If (P^.Origin.Y >= Bounds.A.Y) and (P^.Origin.Y < Bounds.B.Y) then Bounds.A.Y := succ (P^.Origin.Y);
  194.     If (Bounds.B.X - Bounds.A.X < MinWinSize.X) or
  195.        (Bounds.B.Y - Bounds.A.Y < MinWinSize.Y) then
  196.       begin
  197.      {$IFDEF VER60 }
  198.       DeskTop^.GetExtent (Bounds);
  199.      {$ELSE }
  200.       PApplication (Application)^.GetTileRect (Bounds);
  201.      {$ENDIF }
  202.       end;
  203.     end;
  204.   If (MaxX > 0) and (Bounds.B.X - Bounds.A.X > MaxX) then Bounds.B.X := Bounds.A.X + MaxX;
  205.   If (MaxY > 0) and (Bounds.B.Y - Bounds.A.Y > MaxY) then Bounds.B.Y := Bounds.A.Y + MaxY;
  206. end;
  207.  
  208.  
  209.   { ══════════════════════════════════════════════════════════════════════ }
  210.  
  211.  
  212. function  InsertLine (Dialog : PDialog;  Col,Row,Width,Max : integer;
  213.               Fmt : boolean; ALabel : string;  HL : word) : PInputLine;
  214. var  i  : integer;
  215.      R  : TRect;
  216.      B  : PInputLine;
  217. begin
  218.   With Dialog^ do
  219.     begin
  220.     i  := succ (CStrLen (ALabel));
  221.     R.Assign (Col, Row, Col + Width + 2, succ (Row));
  222.     If (ALabel <> '') then
  223.       begin
  224.       If Fmt then R.Move (1, 1) else R.Move (i, 0);
  225.       end;
  226.     B  := New (PInputLine, Init (R, Max));
  227.     Insert (B);
  228.     If (HL > 0) then
  229.       begin
  230.       R.A.X := R.A.X + Width + 2;
  231.       R.B.X := R.A.X + 3;
  232.       Insert (New (PHistory, Init (R, B, HL)));
  233.       end;
  234.     If (ALabel <> '') then
  235.       begin
  236.       R.Assign (Col, Row, Col + i, succ (Row));
  237.       Insert (New (PLabel, Init (R, ALabel, B)));
  238.       end;
  239.     end;
  240.   InsertLine := B;
  241. end;
  242.  
  243.  
  244.   { ══════════════════════════════════════════════════════════════════════ }
  245.  
  246.  
  247. function  InsertText (Dialog : PDialog; Col,Row : integer; AText : string) : PView;
  248. var  R : TRect;
  249.      B : PView;
  250. begin
  251.   With Dialog^ do
  252.     begin
  253.     R.Assign (Col, Row, Col + length (AText), succ (Row));
  254.     B  := New (PStaticText, Init (R, AText));
  255.     Insert (B);
  256.     end;
  257.   InsertText := B;
  258. end;
  259.  
  260.  
  261.   { ══════════════════════════════════════════════════════════════════════ }
  262.  
  263.  
  264. function  InsertView (Owner :PGroup; View :PView; Options :word) : pointer;
  265. begin
  266.   If (View <> nil) then
  267.     begin
  268.     View^.Options := View^.Options or Options;
  269.     If (Owner <> nil) then Owner^.Insert (View);
  270.     end;
  271.   InsertView := View;
  272. end;
  273.  
  274.  
  275.   { ══════════════════════════════════════════════════════════════════════ }
  276.  
  277.  
  278. function  NewVarItem (Name, Param : TMenuStr; var Ind : pstring;
  279.                       KeyCode, Command, AHelpCtx : word;
  280.                       Next : PMenuItem) : PMenuItem;
  281. var  P : PMenuItem;
  282. begin
  283.   P := NewItem (Name,Param, KeyCode,Command,AHelpCtx, Next);
  284.   Ind := P^.Param;
  285.   NewVarItem := P;
  286. end;
  287.  
  288.  
  289.   { ══════════════════════════════════════════════════════════════════════ }
  290.  
  291.  
  292. function  NextWindowNumber  : integer;
  293. begin
  294.   NextWindowNumber := wnNextAvail;
  295. end;
  296.  
  297.  
  298. function  wnNextAvail : integer;
  299. var  wn : integer;
  300.  
  301.     function  UsedWN (P : PWindow) : boolean;  far;
  302.     begin
  303.       UsedWN := (P^.Number = wn) and (P <> PWindow (DeskTop^.Background))
  304.     end;
  305.  
  306. begin
  307.   wn := 0;
  308.   Repeat Inc (wn) until (DeskTop^.FirstThat (@UsedWN) = nil);
  309.   wnNextAvail := wn;
  310. end;
  311.  
  312.  
  313.   { ══════════════════════════════════════════════════════════════════════ }
  314.  
  315.  
  316. procedure TrimDialog (Window : PWindow);
  317. var  B    : TRect;
  318.      MinX : integer;
  319.  
  320.     procedure FindBounds (P : PView);  far;
  321.     begin
  322.       If (PFrame (P) <> Window^.Frame) and (P^.GetState (sfVisible)) then
  323.         begin
  324.         If (P^.Origin.X < MinX) then MinX := P^.Origin.X;
  325.         If (P^.Options and ofCenterX <> 0) then P^.MoveTo (0, P^.Origin.Y);
  326.         If (P^.Size.X + P^.Origin.X > B.B.X) then B.B.X := P^.Size.X + P^.Origin.X;
  327.         If (P^.Size.Y + P^.Origin.Y > B.B.Y) then B.B.Y := P^.Size.Y + P^.Origin.Y;
  328.         P^.GrowMode := 0;
  329.         end;
  330.     end;
  331.  
  332.     procedure ReCenter (P : PView);  far;
  333.     begin
  334.       If (P^.Options and ofCenterX <> 0) and (PFrame (P) <> Window^.Frame) and
  335.          (Window^.Size.X > P^.Size.X) then
  336.         P^.MoveTo (((Window^.Size.X - P^.Size.X) shr 1), P^.Origin.Y);
  337.     end;
  338.  
  339. begin
  340.   If (Window = nil) then Exit;
  341.   B.Assign (0,0,10,0);
  342.   If (Window^.Title <> nil) then B.B.X := 12 + length (Window^.Title^);
  343.   MinX := 999;
  344.   Window^.ForEach (@FindBounds);
  345.   If (MinX = 999) then MinX := 2;
  346.   B.B.X := B.B.X + MinX + 1;
  347.   B.B.Y := B.B.Y + 1;
  348.   If (B.B.X > Window^.Size.X) then B.B.X := Window^.Size.X;
  349.   If (B.B.Y > Window^.Size.Y) then B.B.Y := Window^.Size.Y;
  350.   Window^.GrowTo (B.B.X, B.B.Y);
  351.   Window^.ForEach (@ReCenter);
  352.   Window^.Options := Window^.Options or ofCentered;
  353.   Window^.DrawView;
  354. end;
  355.  
  356.  
  357.   { ══ TAppA ═════════════════════════════════════════════════════════════ }
  358.  
  359.  
  360. constructor TAppA.Init;
  361. begin
  362.   InitMemory;
  363.   InitVideo;
  364.   If PreserveScreen and (StartupMode = ScreenMode) then
  365.     begin
  366.     New (KeptScreen);
  367.     Move (ScreenBuffer^, KeptScreen^, sizeof (KeptScreen^));
  368.     KeptCol := WhereX;
  369.     KeptRow := WhereY;
  370.     end
  371.    else
  372.     KeptScreen := nil;
  373.   InitEvents;
  374.   InitSysError;
  375.   InitHistory;
  376.   TProgram.Init;
  377.   InitClock;
  378.   Insert (Clock);
  379. end;
  380.  
  381.  
  382. destructor TAppA.Done;
  383. begin
  384.   If (Clock <> nil) then Dispose (Clock, Done);
  385.   TProgram.Done;
  386.   DoneHistory;
  387.   DoneSysError;
  388.   DoneEvents;
  389.   DoneVideo;
  390.   If PreserveScreen and (KeptScreen <> nil) then
  391.     begin
  392.     Move (KeptScreen^, ScreenBuffer^, sizeof (KeptScreen^));
  393.     GotoXY (KeptCol, KeptRow);
  394.     end
  395.    else
  396.     PrintStr (#27'[J'^M'   '^M);
  397.   If (KeptScreen <> nil) then
  398.     begin
  399.     Dispose (KeptScreen);
  400.     KeptScreen := nil;
  401.     end;
  402.   DoneMemory;
  403. end;
  404.  
  405.  
  406. procedure TAppA.EventError (var Event : TEvent);
  407. var  k : boolean;
  408. begin
  409.   With Event do
  410.     If (What = evKeyDown) and (Current = PView (DeskTop)) then
  411.       begin
  412.       k := TRUE;
  413.       Case KeyCode of
  414.     kbUp,kbLeft,kbCtrlLeft:        KeyCode := kbShiftTab;
  415.     kbDown,kbRight,kbCtrlRight:    KeyCode := kbTab;
  416.        else                k := FALSE;
  417.     end;
  418.       If k then
  419.     begin
  420.     PutEvent (Event);
  421.     ClearEvent (Event);
  422.     end;
  423.       end;
  424.   If (Event.What <> evNothing) then TApplication.EventError (Event);
  425. end;
  426.  
  427.  
  428. procedure TAppA.HandleEvent (var Event : TEvent);
  429. var  R : TRect;
  430.      M : word;
  431.  
  432.     procedure DeskTopCommand;
  433.     begin
  434.       Desktop^.Lock;
  435.      {$IFDEF VER60 }
  436.       DeskTop^.GetExtent (R);
  437.      {$ELSE }
  438.       GetTileRect (R);
  439.      {$ENDIF }
  440.       Case Event.Command of
  441.     cmCascade:    Desktop^.Cascade (R);
  442.     cmTile:        Desktop^.Tile (R);
  443.     end;
  444.       Message (Desktop, evBroadcast, cmDMX_FixSize, @Self);
  445.       Desktop^.Unlock;
  446.     end;
  447.  
  448.     procedure ShowUserScreen;
  449.     var  Dialog : PDialog;
  450.     begin
  451.       GetExtent (R);
  452.       Dialog := New (PDialog, Init (R, 'User Screen'));
  453.       Dialog^.Insert (New (PUserScreen, Init (R, nil,nil)));
  454.       If (ValidView (Dialog) <> nil) then
  455.     begin
  456.     ExecView (Dialog);
  457.     Dispose (Dialog, Done);
  458.     end;
  459.     end;
  460.  
  461.     procedure DoBeep;
  462.     begin
  463.       If BeepOn then
  464.     begin
  465.     Sound (523);
  466.     Delay (50);
  467.     NoSound;
  468.     end;
  469.     end;
  470.  
  471. begin
  472.   TApplication.HandleEvent (Event);
  473.   If (Event.What = evCommand) then
  474.     begin
  475.     Case Event.Command of
  476.       cmCascade,cmTile:        DeskTopCommand;
  477.       cmBeep,cmDMX_WrongKey:    DoBeep;
  478.       cmToggleSound:
  479.     begin
  480.     BeepOn := not BeepOn;
  481.     If (SoundInd <> nil) then
  482.       begin
  483.       If BeepOn then SoundInd^ := SoundIndOn else SoundInd^ := SoundIndOff;
  484.       end;
  485.     end;
  486.       cmToggleVideo:
  487.     begin
  488.     M := ScreenMode xor smFont8x8;
  489.     If (M and smFont8x8 = 0) then
  490.       begin
  491.       ShadowSize.X := 2;
  492.       If (VideoInd <> nil) then VideoInd^ := VideoIndLow;
  493.       end
  494.      else
  495.       begin
  496.       ShadowSize.X := 1;
  497.       If (VideoInd <> nil) then VideoInd^ := VideoIndHi;
  498.       end;
  499.     SetScreenMode (M);
  500.     end;
  501.       cmUserScreen:    ShowUserScreen;
  502.      else        Exit;
  503.       end;
  504.     ClearEvent (Event);
  505.     end;
  506. end;
  507.  
  508.  
  509. procedure TAppA.Idle;
  510. var  M : word;
  511.      E : TEvent;
  512.  
  513.     function  IsTileable (P: PView) : boolean;  far;
  514.     begin
  515.       IsTileable := (P^.Options and ofTileable <> 0) and P^.GetState (sfVisible);
  516.     end;
  517.  
  518. begin
  519.   TApplication.Idle;
  520.   If (Desktop^.FirstThat (@IsTileable) <> nil) then
  521.     EnableCommands ([cmTile, cmCascade])
  522.    else
  523.     DisableCommands ([cmTile, cmCascade]);
  524.   If (VideoInd <> nil) then
  525.     begin
  526.     If (ScreenMode and smFont8x8 = 0) then
  527.       VideoInd^ := VideoIndLow
  528.      else
  529.       VideoInd^ := VideoIndHi;
  530.     end;
  531.   If (Current = PView (DeskTop)) and (DeskTop^.Current = nil) then
  532.     begin
  533.     E.What    := evCommand;
  534.     E.Command    := cmMenu;
  535.     E.InfoPtr    := @Self;
  536.     PutEvent (E);
  537.     end;
  538.   If (Clock <> nil) then Clock^.Update;
  539. end;
  540.  
  541.  
  542. procedure TAppA.InitClock;
  543. var  R : TRect;
  544. begin
  545.   GetExtent (R);
  546.   Dec (R.B.X);
  547.   R.A.X := R.B.X - 8;
  548.   R.B.Y := R.A.Y + 1;
  549.   Clock := New (PTimeView, Init (R));
  550. end;
  551.  
  552.  
  553. function  TAppA.NewSoundItem (AHelpCtx : word; ANext : PMenuItem) : PMenuItem;
  554. begin
  555.   NewSoundItem := NewVarItem ('~S~ound', SoundIndOn, SoundInd, kbNoKey,
  556.                 cmToggleSound, AHelpCtx, ANext);
  557. end;
  558.  
  559.  
  560. function  TAppA.NewVideoItem (AHelpCtx : word; ANext : PMenuItem) : PMenuItem;
  561. begin
  562.   If HiResScreen then
  563.     NewVideoItem := NewVarItem ('~V~ideo mode', VideoIndLow, VideoInd, kbNoKey,
  564.                 cmToggleVideo, AHelpCtx, ANext)
  565.    else
  566.     NewVideoItem := ANext;
  567. end;
  568.  
  569.  
  570. procedure TAppA.OutOfMemory;
  571. begin
  572.   MessageBox ('Not enough memory for this operation.', nil, mfError + mfOKButton);
  573. end;
  574.  
  575.  
  576.   { ══ TLtdFrame ═════════════════════════════════════════════════════════ }
  577.  
  578.  
  579. procedure TLtdFrame.Draw;
  580. { draws a zoom icon if the LtdWindow is at maximum size }
  581. var XY : TPoint;
  582. begin
  583.   TFrame.Draw;
  584.   If (State and sfActive <> 0) and (Owner <> nil) and (PWindow (Owner)^.Flags and wfZoom <> 0) then
  585.     begin
  586.     If (PLtdWindow (Owner)^.Limit.B.X > 0) then
  587.       XY.X := PLtdWindow (Owner)^.Limit.B.X else XY.X := Owner^.Owner^.Size.X;
  588.     If (PLtdWindow (Owner)^.Limit.B.Y > 0) then
  589.       XY.Y := PLtdWindow (Owner)^.Limit.B.Y else XY.Y := Owner^.Owner^.Size.Y;
  590.     If (Size.X >= XY.X) and (Size.Y >= XY.Y) then
  591.       WriteStr ((Size.X - 4), 0, #18, 5);
  592.     end;
  593. end;
  594.  
  595.  
  596.   { ══ TLtdWindow ════════════════════════════════════════════════════════ }
  597.  
  598.  
  599. constructor TLtdWindow.Init (var Bounds,ALimit    : TRect;
  600.                  ATitle        : TTitleStr;
  601.                  ANumber    : integer);
  602. begin
  603.   TWindow.Init (Bounds, ATitle, ANumber);
  604.   Move (ALimit, Limit, sizeof (Limit));
  605. end;
  606.  
  607.  
  608. constructor TLtdWindow.Load (var S : TStream);
  609. begin
  610.   TWindow.Load (S);
  611.   S.Read (Limit, sizeof (Limit));
  612. end;
  613.  
  614.  
  615. procedure TLtdWindow.ChangeBounds (var Bounds : TRect);
  616. begin
  617.   If (Limit.A.X > 0) and (Bounds.B.X - Bounds.A.X <= Size.X - Limit.A.X) then
  618.     Bounds.B.X := Bounds.A.X + succ (Limit.A.X);
  619.   If (Limit.A.Y > 0) and (Bounds.B.Y - Bounds.A.Y <= Size.Y - Limit.A.Y) then
  620.     Bounds.B.Y := Bounds.A.Y + succ (Limit.A.Y);
  621.   If (Limit.B.X > 0) and (Bounds.B.X - Bounds.A.X > Limit.B.X) then Bounds.B.X := Bounds.A.X + Limit.B.X;
  622.   If (Limit.B.Y > 0) and (Bounds.B.Y - Bounds.A.Y > Limit.B.Y) then Bounds.B.Y := Bounds.A.Y + Limit.B.Y;
  623.   TWindow.ChangeBounds (Bounds);
  624. end;
  625.  
  626.  
  627. procedure TLtdWindow.InitFrame;
  628. var R : TRect;
  629. begin
  630.   GetExtent (R);
  631.   Frame := New (PLtdFrame, Init (R));
  632. end;
  633.  
  634.  
  635. procedure TLtdWindow.Zoom;
  636. var R  : TRect;
  637.     XY : TPoint;
  638. begin
  639.   If (Limit.B.X = 0) or (Limit.B.X > Owner^.Size.X) then
  640.     XY.X := Owner^.Size.X else XY.X := Limit.B.X;
  641.   If (Limit.B.Y = 0) or (Limit.B.Y > Owner^.Size.Y) then
  642.     XY.Y := Owner^.Size.Y else XY.Y := Limit.B.Y;
  643.   If ((Size.X <> XY.X) or (Size.Y <> XY.Y)) then
  644.     begin
  645.     GetBounds (ZoomRect);
  646.     Owner^.GetExtent (R);
  647.     Locate (R);
  648.     end
  649.    else
  650.     Locate (ZoomRect);
  651. end;
  652.  
  653.  
  654.   { ══ TTimeView ═════════════════════════════════════════════════════════ }
  655.  
  656.  
  657. constructor TTimeView.Init (var Bounds : TRect);
  658. begin
  659.   TView.Init (Bounds);
  660.   Min := 99;
  661.   Update;
  662. end;
  663.  
  664.  
  665. procedure TTimeView.Draw;
  666. var  B : TDrawBuffer;
  667.      C : word;
  668.      H : word;
  669.      A,Suffix : string;
  670. begin
  671.   Suffix := ' pm';
  672.   H  := Hour mod 12;
  673.   If (Hour < 12) then Suffix [2] := 'a';
  674.   If (H = 0) then H := 12;
  675.   Str ((H * 1000) + Min:5, A);
  676.   A [3] := ':';
  677.   A := A + Suffix;
  678.   C := GetColor (2);
  679.   MoveChar (B, ' ', C, Size.X);
  680.   MoveStr (B, A, C);
  681.   WriteLine (0, 0, Size.X, 1, B);
  682. end;
  683.  
  684.  
  685. procedure TTimeView.Update;
  686. var  H,M,T : word;
  687. begin
  688.   GetTime (H,M,Sec,T);
  689.   If (Hour <> H) or (Min <> M) then
  690.     begin
  691.     Hour := H;
  692.     Min  := M;
  693.     DrawView;
  694.     If (Sec = 0) and (Min in [0,30]) then
  695.       Message (Application, evBroadcast, cmChime, @Self);
  696.     end;
  697. end;
  698.  
  699.  
  700.   { ══ TUserScreen ═══════════════════════════════════════════════════════ }
  701.  
  702.  
  703. constructor TUserScreen.Init (var Bounds : TRect; AHScrollBar,AVScrollBar : PScrollBar);
  704. var  Width,Height : integer;
  705. begin
  706.   TScroller.Init (Bounds, AHScrollBar,AVScrollBar);
  707.   Width  := 80;
  708.   Height := 25;
  709.   If (StartupMode in [0,1]) then Width := 40;
  710.   SetCursor (pred (KeptCol), pred (KeptRow));
  711.   If (KeptScreen = nil) then Height := 0;
  712.   GrowMode := gfGrowHiX or gfGrowHiY;
  713.   SetLimit (Width,Height);
  714. end;
  715.  
  716.  
  717. procedure TUserScreen.Draw;
  718. var  i, Y : integer;
  719.      B    : TDrawBuffer;
  720. begin
  721.   For Y := 0 to Size.Y - 1 do
  722.     begin
  723.     FillChar (B, sizeof (B), 0);
  724.     i := Delta.Y + Y;
  725.     If (i < Limit.Y) then
  726.       Move (KeptScreen^[(i * Limit.X) + Delta.X], B, Limit.X shl 1);
  727.     WriteLine (0, Y, Size.X, 1, B);
  728.     end;
  729.   If (Limit.Y > 0) then ShowCursor;
  730. end;
  731.  
  732.  
  733. procedure TUserScreen.HandleEvent (var Event : TEvent);
  734. begin
  735.   TScroller.HandleEvent (Event);
  736.   If Owner^.GetState (sfModal) and (Event.What in [evKeyDown,evMouseDown]) then
  737.     Owner^.EndModal (cmCancel);
  738. end;
  739.  
  740.  
  741. function  TUserScreen.Valid (Command : word) : boolean;
  742. begin
  743.   If (Command = cmValid) and (KeptScreen = nil) then
  744.     begin
  745.     MessageBox ('User screen was not preserved.', nil, mfError + mfOKButton);
  746.     Valid := FALSE;
  747.     end
  748.    else
  749.     Valid := TScroller.Valid (Command);
  750. end;
  751.  
  752.  
  753.   { ══════════════════════════════════════════════════════════════════════ }
  754.  
  755.  
  756. procedure RegisterTVGizma;
  757. begin
  758.   RegisterType (RLtdFrame);
  759.   RegisterType (RLtdWindow);
  760. end;
  761.  
  762.  
  763.   { ══════════════════════════════════════════════════════════════════════ }
  764.  
  765.  
  766. End.
  767.