home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / t / tvcom.zip / TVCOM.PAS < prev   
Pascal/Delphi Source File  |  1992-12-06  |  22KB  |  730 lines

  1. {
  2.   TVCOM - a program that demonstrates one way of using Async Professional
  3.   within a Turbo Vision program.
  4.  
  5.   This program provides a TTerminalWindow object derived from TWindow. The
  6.   interior of this object is derived TTerminal. Such an object offers a handy
  7.   way of adding text to the end of a scroller and navigating (using cursor
  8.   keys or mouse) around the scroller.
  9.  
  10.   We also derive a new application object from TApplication called TComApp.
  11.   The actual application, TMyApp is then derived from TComApp. In your
  12.   programs, you might want to consolidate TComApp and TMyApp into one object.
  13.   We broke it into two objects in case you wanted to move TComApp and
  14.   TTerminalWindow objects into their own units.
  15.  
  16.   Serial port output is handled by TTerminalWindow's interior. Whenever it
  17.   receives a evKeyDown message it sends that character to the serial port with
  18.   PutChar.
  19.  
  20.   Serial port input is handled by TComApp's Idle method. Each time that method
  21.   is called (which is once for every generated message) it checks the com port
  22.   for characters waiting in the input buffer. If it finds that a character is
  23.   ready, it will retreive that character, format an event record with a custom
  24.   event code of evComChar and passes that event directly to the
  25.   TTerminalWindow's HandleEvent method. It will process up to 10 characters
  26.   each time Idle is called (speeding things up a bit whenever a large block of
  27.   characters arrives at the serial port).
  28.  
  29.   TTerminalWindow's TInterior is the object that actually processes the
  30.   evComChar event. To do so, it calls TTerminal's CharWrite method to add that
  31.   character to the end of the scroller buffer and display it.
  32.  
  33.   Note this is a rather "bare bones" implementation. The TTerminal ancestor of
  34.   TTerminalWindow's interior doesn't have the necessary methods to easily add
  35.   terminal emulation (which would need to modify colors, position the cursor
  36.   anywhere within the scroller buffer, etc.). To add emulation, you'll either
  37.   need to add methods to TTerminalWindow's interior, or perhaps, choose a
  38.   different ancestor than Turbo Vision's TTerminal.
  39.  
  40.   Additionally, this example gives little consideration to performance. You
  41.   may want to consider processing characters in blocks rather than generating
  42.   an event for each character. That is, the TComApp Idle method would collect
  43.   a block of input characters, place a pointer to that block in the event
  44.   record's InfoPtr field, and have the TTerminalWindow's HandleEvent method
  45.   process that entire block at once.
  46.  
  47.   Released to the public domain
  48.  
  49.   Written by Terry Hughes, TurboPower Software
  50.   Version 1.0 - 6-10-91
  51.     initial release
  52.  
  53.   1.01 - 8-24-92 : wasn't releasing comport memory when terminal window closed
  54.   1.02 - 12-5-92 : updated for BP7
  55.  
  56. }
  57.  
  58. {$X+}
  59. program TVCom;
  60. uses
  61.   {.................rtl}
  62.   Dos,
  63.   {.................turbo vision}
  64.   Objects,
  65.   Drivers,
  66.   Memory,
  67.   Views,
  68.   TextView,
  69.   Menus,
  70.   Dialogs,
  71.   StdDlg,
  72.   MsgBox,
  73.   App,
  74.   {$IFNDEF VER70}                                                      {!!.02}
  75.   Buffers,
  76.   {$ENDIF}                                                             {!!.02}
  77.   Editors,
  78.   {.................async professional}
  79.   ApMisc,
  80.   ApPort,
  81.   ApUart,
  82.   OoCom;
  83.  
  84. const
  85.   {Change these parameters for the comport you're using}
  86.   ComPort = Com2;
  87.   ComBaud = 9600;
  88.  
  89.   evComChar   = $1000;      {Character received at serial port}
  90.  
  91.   HeapSize = 32 * (1024 div 16);
  92.  
  93.   cmOpen       = 100;
  94.   cmNew        = 101;
  95.   cmChangeDir  = 102;
  96.   cmDosShell   = 103;
  97.   cmCalculator = 104;
  98.   cmShowClip   = 105;
  99.   cmTermOpen   = 106;
  100.   cmTermStart  = 107;
  101.   cmTermStop   = 108;
  102.   cmComChar    = 109;
  103.  
  104. type
  105.   PInterior = ^TInterior;
  106.   TInterior = object(TTerminal)
  107.     AP     : AbstractPortPtr;           {Pointer to port object}
  108.     SWidth : Byte;                      {Logical screen width}
  109.  
  110.     constructor Init(var Bounds : TRect;
  111.                      AHScrollBar, AVScrollBar : PScrollBar;
  112.                      ABufSize : Word; APort : AbstractPortPtr);
  113.       {-Instantiate the interior view of the TerminalWindow}
  114.     procedure HandleEvent(var Event: TEvent); virtual;
  115.       {-Custom event handler -- also transmits keystrokes out com port}
  116.     procedure CharWrite(C : Char);
  117.       {-Add and display one character (handle line wrapping)}
  118.   end;
  119.  
  120.   PTerminalWindow = ^TTerminalWindow;
  121.   TTerminalWindow = object(TWindow)
  122.     constructor Init(Bounds: TRect; WinTitle: String;
  123.                      WindowNo: Word; ABufSize: Word;
  124.                      APort : AbstractPortPtr);
  125.       {-Instantiate a TerminalWindow}
  126.     destructor Done; virtual;
  127.       {-Destroy the TTerminalWindow}
  128.     function MakeInterior(Bounds: TRect; ABufSize: Word;
  129.                           APort : AbstractPortPtr): PInterior;
  130.       {-Make an interior subview}
  131.   end;
  132.  
  133.   PComApp = ^TComApp;
  134.   TComApp = object(TApplication)
  135.     TW          : PTerminalWindow;     {Pointer to a TerminalWindow}
  136.     UP          : UartPortPtr;         {Pointer to the port object}
  137.     DoComEvents : Boolean;             {True if a TermWin is open}
  138.  
  139.     constructor Init;
  140.       {-Instantiate the com application}
  141.     procedure Idle; virtual;
  142.       {-Override Idle to handle incoming characters}
  143.   end;
  144.  
  145.   PMyApp = ^TMyApp;
  146.   TMyApp = object(TComApp)
  147.     constructor Init;
  148.       {-Instantiate the main application}
  149.     procedure HandleEvent(var Event : TEvent); virtual;
  150.       {-Override HandleEvent to process custom desktop commands}
  151.     procedure InitMenuBar; virtual;
  152.       {-Insert a custom menu bar}
  153.     procedure InitStatusLine; virtual;
  154.       {-Insert a custom status line}
  155.     procedure OutOfMemory; virtual;
  156.       {-Insert an outofmemory handler}
  157.   end;
  158.  
  159. var
  160.   MyMain: TMyApp;
  161.   ClipWindow: PEditWindow;
  162.  
  163. {TInterior}
  164. constructor TInterior.Init(var Bounds: TRect;
  165.                            AHScrollBar, AVScrollBar : PScrollBar;
  166.                            ABufSize : Word; APort : AbstractPortPtr);
  167. begin
  168.   TTerminal.Init(Bounds, AHScrollBar, AvScrollBar, ABufSize);
  169.   EventMask := EventMask or evComChar;
  170.   AP := APort;
  171.   SWidth := 80;
  172. end;
  173.  
  174. procedure TInterior.CharWrite(C : Char);
  175. var
  176.   CurPos : Word;
  177.   ScreenLines: Word;
  178.   Count : Byte;
  179.  
  180.   procedure InsertChar(C : Char);
  181.   var
  182.     I : Word;
  183.   begin
  184.     if QueFront+1 > BufSize then begin
  185.       Buffer^[0] := C;
  186.       QueFront := 1;
  187.     end else begin
  188.       Buffer^[QueFront] := C;
  189.       Inc(QueFront);
  190.     end;
  191.   end;
  192.  
  193. begin
  194.   {Don't store received line feeds}
  195.   if C = cLF then
  196.     Exit;
  197.  
  198.   {Handle end-of-line (TTextDevice requires cLFs)}
  199.   ScreenLines := Limit.Y;
  200.   if C = cCR then begin
  201.     C := cLF;
  202.     Inc(ScreenLines);
  203.   end;
  204.  
  205.   {Make sure there's room for at least two more characters}
  206.   while not CanInsert(2) do begin
  207.     QueBack := NextLine(QueBack);
  208.     Dec(ScreenLines);
  209.   end;
  210.  
  211.   {Get current horizontal cursor position}
  212.   CurPos := PrevLines(QueFront, 1);
  213.   if CurPos <= QueFront then
  214.     CurPos := QueFront - CurPos
  215.   else
  216.     CurPos := BufSize - (CurPos - QueFront);
  217.  
  218.   {Force a new line if we are at the end of the current line}
  219.   if CurPos > SWidth then begin
  220.     InsertChar(cLF);
  221.     Inc(ScreenLines);
  222.     CurPos := 1;
  223.   end;
  224.  
  225.   {Add this character to the buffer}
  226.   InsertChar(C);
  227.   if C = cLF then
  228.     CurPos := 0
  229.   else
  230.     Inc(CurPos);
  231.  
  232.   {Get length of longest line and recalibrate the scroll bar limits}
  233.   SetLimit(CalcWidth, ScreenLines);
  234.  
  235.   {Scroll to the last line and move to the current horiz cursor position}
  236.   ScrollTo(0, ScreenLines+1);
  237.   SetCursor(CurPos, ScreenLines-Delta.Y-1);
  238.  
  239.   {Update the view}
  240.   DrawView;
  241. end;
  242.  
  243. procedure TInterior.HandleEvent(var Event: TEvent);
  244. var
  245.   S : TextBuf;
  246. begin
  247.   TTerminal.HandleEvent(Event);
  248.   if (Event.What = evKeyDown) or (Event.What = evComChar) then begin
  249.     if Event.CharCode <> #0 then begin
  250.       {Send the character out the serial port}
  251.       if Event.What = evKeyDown then
  252.         AP^.PutChar(Event.CharCode);
  253.  
  254.       {Add it to the terminalwindow's buffer}
  255.       CharWrite(Event.CharCode);
  256.       ClearEvent(Event);
  257.     end;
  258.   end;
  259. end;
  260.  
  261. {TTerminalWindow}
  262. constructor TTerminalWindow.Init(Bounds: TRect; WinTitle: String;
  263.                                  WindowNo: Word; ABufSize: Word;
  264.                                  APort : AbstractPortPtr);
  265. var
  266.   Interior : PInterior;
  267. begin
  268.   TWindow.Init(Bounds, WinTitle, WindowNo);
  269.  
  270.   {Instantiate the internal scroller and insert it into the TerminalWindow}
  271.   Interior := MakeInterior(Bounds, ABufSize, APort);
  272.   Insert(Interior);
  273.  
  274.   {Tell the application to start getting com events}
  275.   Message(Application, evBroadCast, cmTermStart, nil);
  276.  
  277.   {Consider com events as focused events}
  278.   FocusedEvents := FocusedEvents or evComChar;
  279.  
  280.   EventMask := EventMask or evComChar;
  281. end;
  282.  
  283. destructor TTerminalWindow.Done;
  284.   {-Tell the application to stop getting com events}
  285. begin
  286.   TWindow.Done;
  287.   Message(Application, evBroadCast, cmTermStop, nil);
  288. end;
  289.  
  290. function TTerminalWindow.MakeInterior(Bounds: TRect; ABufSize: Word;
  291.                                       APort : AbstractPortPtr): PInterior;
  292. begin
  293.   GetExtent(Bounds);
  294.   Bounds.Grow(-1, -1);
  295.   MakeInterior := New(PInterior, Init(Bounds,
  296.                       StandardScrollBar(sbHorizontal + sbHandleKeyboard),
  297.                       StandardScrollBar(sbVertical + sbHandleKeyboard),
  298.                       ABufSize, APort));
  299. end;
  300.  
  301. {TComApp}
  302. constructor TComApp.Init;
  303. begin
  304.   {Do parent init}
  305.   TApplication.Init;
  306.  
  307.   {Don't get com events yet}
  308.   TW := nil;
  309.   DoComEvents := False;
  310. end;
  311.  
  312.  
  313. procedure TComApp.Idle;
  314.   {-Override Idle to handle incoming characters}
  315. const
  316.   ReleaseCnt = 10;
  317. var
  318.   C : Char;
  319.   Event : TEvent;
  320.   Cnt : Byte;
  321. begin
  322.   TApplication.Idle;
  323.  
  324.   if DoComEvents then begin
  325.     Cnt := 1;
  326.  
  327.     while UP^.CharReady and (Cnt < ReleaseCnt) do begin
  328.       Inc(Cnt);
  329.       UP^.GetChar(C);
  330.       if AsyncStatus = ecOk then begin
  331.         Event.What := evComChar;
  332.         Event.CharCode := C;
  333.         Event.ScanCode := $FF;
  334.         TW^.HandleEvent(Event);
  335.       end;
  336.     end;
  337.   end;
  338. end;
  339.  
  340. function ExecDialog(P: PDialog; Data: Pointer): Word;
  341. var
  342.   Result: Word;
  343. begin
  344.   Result := cmCancel;
  345.   P := PDialog(Application^.ValidView(P));
  346.   if P <> nil then
  347.   begin
  348.     if Data <> nil then P^.SetData(Data^);
  349.     Result := DeskTop^.ExecView(P);
  350.     if (Result <> cmCancel) and (Data <> nil) then P^.GetData(Data^);
  351.     Dispose(P, Done);
  352.   end;
  353.   ExecDialog := Result;
  354. end;
  355.  
  356. function CreateFindDialog: PDialog;
  357. var
  358.   D: PDialog;
  359.   Control: PView;
  360.   R: TRect;
  361. begin
  362.   R.Assign(0, 0, 38, 12);
  363.   D := New(PDialog, Init(R, 'Find'));
  364.   with D^ do
  365.   begin
  366.     Options := Options or ofCentered;
  367.  
  368.     R.Assign(3, 3, 32, 4);
  369.     Control := New(PInputLine, Init(R, 80));
  370.     Insert(Control);
  371.     R.Assign(2, 2, 15, 3);
  372.     Insert(New(PLabel, Init(R, '~T~ext to find', Control)));
  373.     R.Assign(32, 3, 35, 4);
  374.     Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
  375.  
  376.     R.Assign(3, 5, 35, 7);
  377.     Insert(New(PCheckBoxes, Init(R,
  378.       NewSItem('~C~ase sensitive',
  379.       NewSItem('~W~hole words only', nil)))));
  380.  
  381.     R.Assign(14, 9, 24, 11);
  382.     Insert(New(PButton, Init(R, 'O~K~', cmOk, bfDefault)));
  383.     Inc(R.A.X, 12); Inc(R.B.X, 12);
  384.     Insert(New(PButton, Init(R, 'Cancel', cmCancel, bfNormal)));
  385.  
  386.     SelectNext(False);
  387.   end;
  388.   CreateFindDialog := D;
  389. end;
  390.  
  391. function CreateReplaceDialog: PDialog;
  392. var
  393.   D: PDialog;
  394.   Control: PView;
  395.   R: TRect;
  396. begin
  397.   R.Assign(0, 0, 40, 16);
  398.   D := New(PDialog, Init(R, 'Replace'));
  399.   with D^ do
  400.   begin
  401.     Options := Options or ofCentered;
  402.  
  403.     R.Assign(3, 3, 34, 4);
  404.     Control := New(PInputLine, Init(R, 80));
  405.     Insert(Control);
  406.     R.Assign(2, 2, 15, 3);
  407.     Insert(New(PLabel, Init(R, '~T~ext to find', Control)));
  408.     R.Assign(34, 3, 37, 4);
  409.     Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
  410.  
  411.     R.Assign(3, 6, 34, 7);
  412.     Control := New(PInputLine, Init(R, 80));
  413.     Insert(Control);
  414.     R.Assign(2, 5, 12, 6);
  415.     Insert(New(PLabel, Init(R, '~N~ew text', Control)));
  416.     R.Assign(34, 6, 37, 7);
  417.     Insert(New(PHistory, Init(R, PInputLine(Control), 11)));
  418.  
  419.     R.Assign(3, 8, 37, 12);
  420.     Insert(New(PCheckBoxes, Init(R,
  421.       NewSItem('~C~ase sensitive',
  422.       NewSItem('~W~hole words only',
  423.       NewSItem('~P~rompt on replace',
  424.       NewSItem('~R~eplace all', nil)))))));
  425.  
  426.     R.Assign(17, 13, 27, 15);
  427.     Insert(New(PButton, Init(R, 'O~K~', cmOk, bfDefault)));
  428.     R.Assign(28, 13, 38, 15);
  429.     Insert(New(PButton, Init(R, 'Cancel', cmCancel, bfNormal)));
  430.  
  431.     SelectNext(False);
  432.   end;
  433.   CreateReplaceDialog := D;
  434. end;
  435.  
  436. function DoEditDialog(Dialog: Integer; Info: Pointer): Word; far;
  437. var
  438.   R: TRect;
  439.   T: TPoint;
  440. begin
  441.   case Dialog of
  442.     edOutOfMemory:
  443.       DoEditDialog := MessageBox('Not enough memory for this operation.',
  444.         nil, mfError + mfOkButton);
  445.     edReadError:
  446.       DoEditDialog := MessageBox('Error reading file %s.',
  447.         @Info, mfError + mfOkButton);
  448.     edWriteError:
  449.       DoEditDialog := MessageBox('Error writing file %s.',
  450.         @Info, mfError + mfOkButton);
  451.     edCreateError:
  452.       DoEditDialog := MessageBox('Error creating file %s.',
  453.         @Info, mfError + mfOkButton);
  454.     edSaveModify:
  455.       DoEditDialog := MessageBox('%s has been modified. Save?',
  456.         @Info, mfInformation + mfYesNoCancel);
  457.     edSaveUntitled:
  458.       DoEditDialog := MessageBox('Save untitled file?',
  459.         nil, mfInformation + mfYesNoCancel);
  460.     edSaveAs:
  461.       DoEditDialog := ExecDialog(New(PFileDialog, Init('*.*',
  462.         'Save file as', '~N~ame', fdOkButton, 101)), Info);
  463.     edFind:
  464.       DoEditDialog := ExecDialog(CreateFindDialog, Info);
  465.     edSearchFailed:
  466.       DoEditDialog := MessageBox('Search string not found.',
  467.         nil, mfError + mfOkButton);
  468.     edReplace:
  469.       DoEditDialog := ExecDialog(CreateReplaceDialog, Info);
  470.     edReplacePrompt:
  471.       begin
  472.         { Avoid placing the dialog on the same line as the cursor }
  473.         R.Assign(0, 1, 40, 8);
  474.         R.Move((Desktop^.Size.X - R.B.X) div 2, 0);
  475.         Desktop^.MakeGlobal(R.B, T);
  476.         Inc(T.Y);
  477.         if TPoint(Info).Y <= T.Y then
  478.           R.Move(0, Desktop^.Size.Y - R.B.Y - 2);
  479.         DoEditDialog := MessageBoxRect(R, 'Replace this occurence?',
  480.           nil, mfYesNoCancel + mfInformation);
  481.       end;
  482.   end;
  483. end;
  484.  
  485. function OpenEditor(FileName: FNameStr; Visible: Boolean): PEditWindow;
  486. var
  487.   P: PView;
  488.   R: TRect;
  489. begin
  490.   DeskTop^.GetExtent(R);
  491.   P := Application^.ValidView(New(PEditWindow, Init(R, FileName, wnNoNumber)));
  492.   if not Visible then
  493.     P^.Hide;
  494.   DeskTop^.Insert(P);
  495.   OpenEditor := PEditWindow(P);
  496. end;
  497.  
  498. constructor TMyApp.Init;
  499. var
  500.   H: Word;
  501. begin
  502.   {$IFNDEF VER70}                                                      {!!.02}
  503.   {Init edit buffers}
  504.   H := PtrRec(HeapEnd).Seg - PtrRec(HeapPtr).Seg;
  505.   if H > HeapSize then
  506.     BufHeapSize := H - HeapSize
  507.   else
  508.     BufHeapSize := 0;
  509.   InitBuffers;
  510.   {$ENDIF}                                                             {!!.02}
  511.  
  512.   {Do parent init}
  513.   TComApp.Init;
  514.  
  515.   {Make a clipboard from an editor}
  516.   DisableCommands([cmSave, cmSaveAs, cmCut, cmCopy, cmPaste, cmClear,
  517.                    cmUndo, cmFind, cmReplace, cmSearchAgain]);
  518.   EditorDialog := DoEditDialog;
  519.   ClipWindow := OpenEditor('', False);
  520.   if ClipWindow <> nil then begin
  521.     Clipboard := ClipWindow^.Editor;
  522.     Clipboard^.CanUndo := False;
  523.   end;
  524. end;
  525.  
  526. procedure TMyApp.HandleEvent(var Event: TEvent);
  527.  
  528. procedure FileOpen;
  529. var
  530.   FileName: FNameStr;
  531. begin
  532.   FileName := '*.*';
  533.   if ExecDialog(New(PFileDialog, Init('*.*', 'Open file',
  534.     '~N~ame', fdOpenButton, 100)), @FileName) <> cmCancel then
  535.     OpenEditor(FileName, True);
  536. end;
  537.  
  538. procedure FileNew;
  539. begin
  540.   OpenEditor('', True);
  541. end;
  542.  
  543. procedure ChangeDir;
  544. begin
  545.   ExecDialog(New(PChDirDialog, Init(cdNormal, 0)), nil);
  546. end;
  547.  
  548. {$IFNDEF VER70}                                                        {!!.02}
  549. procedure DosShell;
  550. begin
  551.   DoneSysError;
  552.   DoneEvents;
  553.   DoneVideo;
  554.   DoneMemory;
  555.   SetMemTop(Ptr(BufHeapPtr, 0));
  556.   PrintStr('Type EXIT to return to TVEDIT...');
  557.   SwapVectors;
  558.   Exec(GetEnv('COMSPEC'), '');
  559.   SwapVectors;
  560.   SetMemTop(Ptr(BufHeapEnd, 0));
  561.   InitMemory;
  562.   InitVideo;
  563.   InitEvents;
  564.   InitSysError;
  565.   Redraw;
  566. end;
  567. {$ENDIF}                                                               {!!.02}
  568.  
  569. procedure ShowClip;
  570. begin
  571.   ClipWindow^.Select;
  572.   ClipWindow^.Show;
  573. end;
  574.  
  575. {$IFNDEF VER70}                                                        {!!.02}
  576. procedure Tile;
  577. var
  578.   R: TRect;
  579. begin
  580.   Desktop^.GetExtent(R);
  581.   Desktop^.Tile(R);
  582. end;
  583.  
  584. procedure Cascade;
  585. var
  586.   R: TRect;
  587. begin
  588.   Desktop^.GetExtent(R);
  589.   Desktop^.Cascade(R);
  590. end;
  591. {$ENDIF}                                                               {!!.02}
  592.  
  593. procedure TermOpen;
  594. var
  595.   R : TRect;
  596. begin
  597.   {Open up the serial port}
  598.   New(UP, InitCustom(ComPort, ComBaud, NoParity, 8, 1, 1000, 1000, DefPortOptions));
  599.   if UP = nil then begin
  600.     WriteLn('Failed to open port: ', AsyncStatus);
  601.     Halt;
  602.   end;
  603.  
  604.   {Instantiate the TerminalWindow object}
  605.   R.Assign(10, 1, 70, 18);
  606.   TW := New(PTerminalWindow, Init(R, 'Terminal', wnNoNumber, 8192, UP));
  607.   TW := PTerminalWindow(Application^.ValidView(TW));
  608.   Desktop^.Insert(TW);
  609.  
  610.   {Start com events}
  611.   DoComEvents := True;
  612. end;
  613.  
  614. begin
  615.   TApplication.HandleEvent(Event);
  616.   case Event.What of
  617.     evCommand :
  618.       case Event.Command of
  619.         cmOpen : FileOpen;
  620.         cmNew : FileNew;
  621.         cmChangeDir : ChangeDir;
  622.         cmDosShell : DosShell;
  623.         cmShowClip : ShowClip;
  624.         cmTile : Tile;
  625.         cmCascade : Cascade;
  626.         cmTermOpen : TermOpen;
  627.         else Exit;
  628.       end;
  629.     evBroadCast :
  630.       case Event.Command of
  631.         cmTermStart : DoComEvents := True;
  632.         cmTermStop :
  633.           begin
  634.             DoComEvents := False;
  635.             TW := nil;
  636.             Dispose(UP, Done);                                         {!!.01}
  637.           end;
  638.         else Exit;
  639.       end;
  640.   else
  641.     Exit;
  642.   end;
  643.   ClearEvent(Event);
  644. end;
  645.  
  646. procedure TMyApp.InitMenuBar;
  647. var
  648.   R: TRect;
  649. begin
  650.   GetExtent(R);
  651.   R.B.Y := R.A.Y + 1;
  652.   MenuBar := New(PMenuBar, Init(R, NewMenu(
  653.     NewSubMenu('~F~ile', hcNoContext, NewMenu(
  654.       NewItem('~O~pen...', 'F3', kbF3, cmOpen, hcNoContext,
  655.       NewItem('~N~ew', '', kbNoKey, cmNew, hcNoContext,
  656.       NewItem('~S~ave', 'F2', kbF2, cmSave, hcNoContext,
  657.       NewItem('S~a~ve as...', '', kbNoKey, cmSaveAs, hcNoContext,
  658.       NewLine(
  659.       NewItem('~C~hange dir...', '', kbNoKey, cmChangeDir, hcNoContext,
  660.       NewItem('~D~OS shell', '', kbNoKey, cmDosShell, hcNoContext,
  661.       NewItem('E~x~it', 'Alt-X', kbAltX, cmQuit, hcNoContext,
  662.       nil))))))))),
  663.     NewSubMenu('~E~dit', hcNoContext, NewMenu(
  664.       NewItem('~U~ndo', '', kbNoKey, cmUndo, hcNoContext,
  665.       NewLine(
  666.       NewItem('Cu~t~', 'Shift-Del', kbShiftDel, cmCut, hcNoContext,
  667.       NewItem('~C~opy', 'Ctrl-Ins', kbCtrlIns, cmCopy, hcNoContext,
  668.       NewItem('~P~aste', 'Shift-Ins', kbShiftIns, cmPaste, hcNoContext,
  669.       NewItem('~S~how clipboard', '', kbNoKey, cmShowClip, hcNoContext,
  670.       NewLine(
  671.       NewItem('~C~lear', 'Ctrl-Del', kbCtrlDel, cmClear, hcNoContext,
  672.       nil))))))))),
  673.     NewSubMenu('~S~earch', hcNoContext, NewMenu(
  674.       NewItem('~F~ind...', '', kbNoKey, cmFind, hcNoContext,
  675.       NewItem('~R~eplace...', '', kbNoKey, cmReplace, hcNoContext,
  676.       NewItem('~S~earch again', '', kbNoKey, cmSearchAgain, hcNoContext,
  677.       nil)))),
  678.     NewSubMenu('~W~indows', hcNoContext, NewMenu(
  679.       NewItem('~S~ize/move','Ctrl-F5', kbCtrlF5, cmResize, hcNoContext,
  680.       NewItem('~Z~oom', 'F5', kbF5, cmZoom, hcNoContext,
  681.       NewItem('~T~ile', '', kbNoKey, cmTile, hcNoContext,
  682.       NewItem('C~a~scade', '', kbNoKey, cmCascade, hcNoContext,
  683.       NewItem('~N~ext', 'F6', kbF6, cmNext, hcNoContext,
  684.       NewItem('~P~revious', 'Shift-F6', kbShiftF6, cmPrev, hcNoContext,
  685.       NewItem('~C~lose', 'Alt-F3', kbAltF3, cmClose, hcNoContext,
  686.       NewLine(
  687.       NewItem('Ca~l~culator', '', kbNoKey, cmCalculator, hcNoContext,
  688.       nil)))))))))),
  689.     NewSubMenu('~T~erminal', hcNoContext, NewMenu(
  690.       NewItem('~O~pen', '', kbNoKey, cmTermOpen, hcNoContext,
  691.       NewItem('~C~lose', '', kbNoKey, cmClose, hcNoContext,
  692.       nil))),
  693.     nil))))))));
  694. end;
  695.  
  696. procedure TMyApp.InitStatusLine;
  697. var
  698.   R: TRect;
  699. begin
  700.   GetExtent(R);
  701.   R.A.Y := R.B.Y - 1;
  702.   New(StatusLine, Init(R,
  703.     NewStatusDef(0, $FFFF,
  704.       NewStatusKey('~F2~ Save', kbF2, cmSave,
  705.       NewStatusKey('~F3~ Open', kbF3, cmOpen,
  706.       NewStatusKey('~Alt-F3~ Close', kbAltF3, cmClose,
  707.       NewStatusKey('~F5~ Zoom', kbF5, cmZoom,
  708.       NewStatusKey('~F6~ Next', kbF6, cmNext,
  709.       NewStatusKey('~F10~ Menu', kbF10, cmMenu,
  710.       NewStatusKey('', kbCtrlF5, cmResize,
  711.       nil))))))),
  712.     nil)));
  713. end;
  714.  
  715. procedure TMyApp.OutOfMemory;
  716. begin
  717.   MessageBox('Not enough memory for this operation.', nil, mfError+mfOkButton);
  718. end;
  719.  
  720. begin
  721.   {$IFDEF VER70}                                                        {!!.02}
  722.   {$IFNDEF Dpmi}                                                        {!!.02}
  723.   MaxHeapSize := (MaxAvail div 16) - 8192;
  724.   {$ENDIF}                                                              {!!.02}
  725.   {$ENDIF}                                                              {!!.02}
  726.   MyMain.Init;
  727.   MyMain.Run;
  728.   MyMain.Done;
  729. end.
  730.