home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Pascal / TP.7_1 / TP / EXAMPLES / TVDEMO / TVDEMO.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-10-05  |  18.6 KB  |  702 lines

  1. {************************************************}
  2. {                                                }
  3. {   Turbo Vision Demo                            }
  4. {   Copyright (c) 1992 by Borland International  }
  5. {                                                }
  6. {************************************************}
  7.  
  8. {
  9.   Changes to this program since Turbo Pascal Version 6.0:
  10.  
  11.   1. File|Open and File|New now create editor windows using the
  12.      Editors unit.  The Edit and Search menus have been added to
  13.      provide complete editor functionality.  Help has been expanded
  14.      accordingly.
  15.  
  16.   2. Save Desktop now writes a "signature" string as the first part
  17.      of the desktop file.  Load Desktop looks for this signature, and
  18.      if it is not found, an error is reported.  This is the "safe" way
  19.      to read/write configuration files.  (Try TYPE TVDEMO.DSK from the
  20.      DOS prompt).  The application's palette is now saved in the desktop
  21.      file.
  22.  
  23.   3. A bug which caused the desktop's color not to be set correctly
  24.      has been fixed.
  25. }
  26.  
  27. program TVDemo;
  28.  
  29. {$X+,S-}
  30. {$M 16384,8192,655360}
  31.  
  32. { Turbo Vision demo program. This program uses many of the Turbo
  33.   Vision standard and demo units, including:
  34.  
  35.     StdDlg    - Open file browser, change directory tree.
  36.     MsgBox    - Simple dialog to display messages.
  37.     ColorSel  - Color customization.
  38.     Gadgets   - Shows system time and available heap space.
  39.     AsciiTab  - ASCII table.
  40.     Calendar  - View a month at a time
  41.     Calc      - Desktop calculator.
  42.     HelpFile  - Context sensitive help.
  43.     MouseDlg  - Mouse options dialog.
  44.     Puzzle    - Simple brain puzzle.
  45.     Editors   - Text Editor object.
  46.  
  47.   And of course this program includes many standard Turbo Vision
  48.   objects and behaviors (menubar, desktop, status line, dialog boxes,
  49.   mouse support, window resize/move/tile/cascade).
  50. }
  51.  
  52. uses
  53.   Dos, Objects, Drivers, Memory, Views, Menus, Dialogs, StdDlg, HistList,
  54.   MsgBox, App, DemoCmds, Gadgets, Puzzle, Calendar, AsciiTab, Calc,
  55.   HelpFile, DemoHelp, ColorSel, MouseDlg, Editors;
  56.  
  57. const
  58.   HeapSize = 48 * (1024 div 16);  { Save 48k heap for main program }
  59.  
  60.   { Desktop file signature information }
  61.   SignatureLen = 21;
  62.   DSKSignature : string[SignatureLen] = 'TV Demo Desktop File'#26;
  63.  
  64. var
  65.   ClipWindow: PEditWindow;
  66.  
  67. type
  68.  
  69.   { TTVDemo }
  70.  
  71.   PTVDemo = ^TTVDemo;
  72.   TTVDemo = object(TApplication)
  73.     Clock: PClockView;
  74.     Heap: PHeapView;
  75.     constructor Init;
  76.     procedure FileOpen(WildCard: PathStr);
  77.     function OpenEditor(FileName: FNameStr; Visible: Boolean): PEditWindow;
  78.     procedure GetEvent(var Event: TEvent); virtual;
  79.     function GetPalette: PPalette; virtual;
  80.     procedure HandleEvent(var Event: TEvent); virtual;
  81.     procedure Idle; virtual;
  82.     procedure InitMenuBar; virtual;
  83.     procedure InitStatusLine; virtual;
  84.     procedure LoadDesktop(var S: TStream);
  85.     procedure OutOfMemory; virtual;
  86.     procedure StoreDesktop(var S: TStream);
  87.   end;
  88.  
  89. { CalcHelpName }
  90.  
  91. function CalcHelpName: PathStr;
  92. var
  93.   EXEName: PathStr;
  94.   Dir: DirStr;
  95.   Name: NameStr;
  96.   Ext: ExtStr;
  97. begin
  98.   if Lo(DosVersion) >= 3 then EXEName := ParamStr(0)
  99.   else EXEName := FSearch('TVDEMO.EXE', GetEnv('PATH'));
  100.   FSplit(EXEName, Dir, Name, Ext);
  101.   if Dir[Length(Dir)] = '\' then Dec(Dir[0]);
  102.   CalcHelpName := FSearch('DEMOHELP.HLP', Dir);
  103. end;
  104.  
  105. function CreateFindDialog: PDialog;
  106. var
  107.   D: PDialog;
  108.   Control: PView;
  109.   R: TRect;
  110. begin
  111.   R.Assign(0, 0, 38, 12);
  112.   D := New(PDialog, Init(R, 'Find'));
  113.   with D^ do
  114.   begin
  115.     Options := Options or ofCentered;
  116.  
  117.     R.Assign(3, 3, 32, 4);
  118.     Control := New(PInputLine, Init(R, 80));
  119.     Insert(Control);
  120.     R.Assign(2, 2, 15, 3);
  121.     Insert(New(PLabel, Init(R, '~T~ext to find', Control)));
  122.     R.Assign(32, 3, 35, 4);
  123.     Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
  124.  
  125.     R.Assign(3, 5, 35, 7);
  126.     Insert(New(PCheckBoxes, Init(R,
  127.       NewSItem('~C~ase sensitive',
  128.       NewSItem('~W~hole words only', nil)))));
  129.  
  130.     R.Assign(14, 9, 24, 11);
  131.     Insert(New(PButton, Init(R, 'O~K~', cmOk, bfDefault)));
  132.     Inc(R.A.X, 12); Inc(R.B.X, 12);
  133.     Insert(New(PButton, Init(R, 'Cancel', cmCancel, bfNormal)));
  134.  
  135.     SelectNext(False);
  136.   end;
  137.   CreateFindDialog := D;
  138. end;
  139.  
  140. function CreateReplaceDialog: PDialog;
  141. var
  142.   D: PDialog;
  143.   Control: PView;
  144.   R: TRect;
  145. begin
  146.   R.Assign(0, 0, 40, 16);
  147.   D := New(PDialog, Init(R, 'Replace'));
  148.   with D^ do
  149.   begin
  150.     Options := Options or ofCentered;
  151.  
  152.     R.Assign(3, 3, 34, 4);
  153.     Control := New(PInputLine, Init(R, 80));
  154.     Insert(Control);
  155.     R.Assign(2, 2, 15, 3);
  156.     Insert(New(PLabel, Init(R, '~T~ext to find', Control)));
  157.     R.Assign(34, 3, 37, 4);
  158.     Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
  159.  
  160.     R.Assign(3, 6, 34, 7);
  161.     Control := New(PInputLine, Init(R, 80));
  162.     Insert(Control);
  163.     R.Assign(2, 5, 12, 6);
  164.     Insert(New(PLabel, Init(R, '~N~ew text', Control)));
  165.     R.Assign(34, 6, 37, 7);
  166.     Insert(New(PHistory, Init(R, PInputLine(Control), 11)));
  167.  
  168.     R.Assign(3, 8, 37, 12);
  169.     Insert(New(PCheckBoxes, Init(R,
  170.       NewSItem('~C~ase sensitive',
  171.       NewSItem('~W~hole words only',
  172.       NewSItem('~P~rompt on replace',
  173.       NewSItem('~R~eplace all', nil)))))));
  174.  
  175.     R.Assign(17, 13, 27, 15);
  176.     Insert(New(PButton, Init(R, 'O~K~', cmOk, bfDefault)));
  177.     R.Assign(28, 13, 38, 15);
  178.     Insert(New(PButton, Init(R, 'Cancel', cmCancel, bfNormal)));
  179.  
  180.     SelectNext(False);
  181.   end;
  182.   CreateReplaceDialog := D;
  183. end;
  184.  
  185. function DoEditDialog(Dialog: Integer; Info: Pointer): Word; far;
  186. var
  187.   R: TRect;
  188.   T: TPoint;
  189. begin
  190.   case Dialog of
  191.     edOutOfMemory:
  192.       DoEditDialog := MessageBox('Not enough memory for this operation.',
  193.         nil, mfError + mfOkButton);
  194.     edReadError:
  195.       DoEditDialog := MessageBox('Error reading file %s.',
  196.         @Info, mfError + mfOkButton);
  197.     edWriteError:
  198.       DoEditDialog := MessageBox('Error writing file %s.',
  199.         @Info, mfError + mfOkButton);
  200.     edCreateError:
  201.       DoEditDialog := MessageBox('Error creating file %s.',
  202.         @Info, mfError + mfOkButton);
  203.     edSaveModify:
  204.       DoEditDialog := MessageBox('%s has been modified. Save?',
  205.         @Info, mfInformation + mfYesNoCancel);
  206.     edSaveUntitled:
  207.       DoEditDialog := MessageBox('Save untitled file?',
  208.         nil, mfInformation + mfYesNoCancel);
  209.     edSaveAs:
  210.       DoEditDialog := Application^.ExecuteDialog(New(PFileDialog, Init('*.*',
  211.         'Save file as', '~N~ame', fdOkButton, 101)), Info);
  212.     edFind:
  213.       DoEditDialog := Application^.ExecuteDialog(CreateFindDialog, Info);
  214.     edSearchFailed:
  215.       DoEditDialog := MessageBox('Search string not found.',
  216.         nil, mfError + mfOkButton);
  217.     edReplace:
  218.       DoEditDialog := Application^.ExecuteDialog(CreateReplaceDialog, Info);
  219.     edReplacePrompt:
  220.       begin
  221.         { Avoid placing the dialog on the same line as the cursor }
  222.         R.Assign(0, 1, 40, 8);
  223.         R.Move((Desktop^.Size.X - R.B.X) div 2, 0);
  224.         Desktop^.MakeGlobal(R.B, T);
  225.         Inc(T.Y);
  226.         if TPoint(Info).Y <= T.Y then
  227.           R.Move(0, Desktop^.Size.Y - R.B.Y - 2);
  228.         DoEditDialog := MessageBoxRect(R, 'Replace this occurence?',
  229.           nil, mfYesNoCancel + mfInformation);
  230.       end;
  231.   end;
  232. end;
  233.  
  234. { TTVDemo }
  235. constructor TTVDemo.Init;
  236. var
  237.   R: TRect;
  238.   I: Integer;
  239.   FileName: PathStr;
  240. begin
  241.   MaxHeapSize := HeapSize;
  242.   inherited Init;
  243.   RegisterObjects;
  244.   RegisterViews;
  245.   RegisterMenus;
  246.   RegisterDialogs;
  247.   RegisterApp;
  248.   RegisterHelpFile;
  249.   RegisterPuzzle;
  250.   RegisterCalendar;
  251.   RegisterAsciiTab;
  252.   RegisterCalc;
  253.   RegisterEditors;
  254.  
  255.   { Initialize demo gadgets }
  256.  
  257.   GetExtent(R);
  258.   R.A.X := R.B.X - 9; R.B.Y := R.A.Y + 1;
  259.   Clock := New(PClockView, Init(R));
  260.   Insert(Clock);
  261.  
  262.   GetExtent(R);
  263.   Dec(R.B.X);
  264.   R.A.X := R.B.X - 9; R.A.Y := R.B.Y - 1;
  265.   Heap := New(PHeapView, Init(R));
  266.   Insert(Heap);
  267.  
  268.   DisableCommands([cmSave, cmSaveAs, cmCut, cmCopy, cmPaste, cmClear,
  269.     cmUndo, cmFind, cmReplace, cmSearchAgain]);
  270.   EditorDialog := DoEditDialog;
  271.   ClipWindow := OpenEditor('', False);
  272.   if ClipWindow <> nil then
  273.   begin
  274.     Clipboard := ClipWindow^.Editor;
  275.     Clipboard^.CanUndo := False;
  276.   end;
  277.  
  278.   for I := 1 to ParamCount do
  279.   begin
  280.     FileName := ParamStr(I);
  281.     if FileName[Length(FileName)] = '\' then
  282.       FileName := FileName + '*.*';
  283.     if (Pos('?', FileName) = 0) and (Pos('*', FileName) = 0) then
  284.       OpenEditor(FExpand(FileName), True)
  285.     else FileOpen(FileName);
  286.   end;
  287. end;
  288.  
  289. function TTVDemo.OpenEditor(FileName: FNameStr; Visible: Boolean): PEditWindow;
  290. var
  291.   P: PView;
  292.   R: TRect;
  293. begin
  294.   DeskTop^.GetExtent(R);
  295.   P := Application^.ValidView(New(PEditWindow,
  296.     Init(R, FileName, wnNoNumber)));
  297.   if not Visible then P^.Hide;
  298.   DeskTop^.Insert(P);
  299.   OpenEditor := PEditWindow(P);
  300. end;
  301.  
  302. procedure TTVDemo.FileOpen(WildCard: PathStr);
  303. var
  304.   FileName: FNameStr;
  305. begin
  306.   FileName := '*.*';
  307.   if ExecuteDialog(New(PFileDialog, Init(WildCard, 'Open a file',
  308.     '~N~ame', fdOpenButton + fdHelpButton, 100)), @FileName) <> cmCancel then
  309.     OpenEditor(FileName, True);
  310. end;
  311.  
  312. procedure TTVDemo.GetEvent(var Event: TEvent);
  313. var
  314.   W: PWindow;
  315.   HFile: PHelpFile;
  316.   HelpStrm: PDosStream;
  317. const
  318.   HelpInUse: Boolean = False;
  319. begin
  320.   TApplication.GetEvent(Event);
  321.   case Event.What of
  322.     evCommand:
  323.       if (Event.Command = cmHelp) and not HelpInUse then
  324.       begin
  325.         HelpInUse := True;
  326.         HelpStrm := New(PDosStream, Init(CalcHelpName, stOpenRead));
  327.         HFile := New(PHelpFile, Init(HelpStrm));
  328.         if HelpStrm^.Status <> stOk then
  329.         begin
  330.           MessageBox('Could not open help file.', nil, mfError + mfOkButton);
  331.           Dispose(HFile, Done);
  332.         end
  333.         else
  334.         begin
  335.           W := New(PHelpWindow,Init(HFile, GetHelpCtx));
  336.           if ValidView(W) <> nil then
  337.           begin
  338.             ExecView(W);
  339.             Dispose(W, Done);
  340.           end;
  341.           ClearEvent(Event);
  342.         end;
  343.         HelpInUse := False;
  344.       end;
  345.     evMouseDown:
  346.       if Event.Buttons <> 1 then Event.What := evNothing;
  347.   end;
  348. end;
  349.  
  350. function TTVDemo.GetPalette: PPalette;
  351. const
  352.   CNewColor = CAppColor + CHelpColor;
  353.   CNewBlackWhite = CAppBlackWhite + CHelpBlackWhite;
  354.   CNewMonochrome = CAppMonochrome + CHelpMonochrome;
  355.   P: array[apColor..apMonochrome] of string[Length(CNewColor)] =
  356.     (CNewColor, CNewBlackWhite, CNewMonochrome);
  357. begin
  358.   GetPalette := @P[AppPalette];
  359. end;
  360.  
  361. procedure TTVDemo.HandleEvent(var Event: TEvent);
  362.  
  363. procedure ChangeDir;
  364. var
  365.   D: PChDirDialog;
  366. begin
  367.   D := New(PChDirDialog, Init(cdNormal + cdHelpButton, 101));
  368.   D^.HelpCtx := hcFCChDirDBox;
  369.   ExecuteDialog(D, nil);
  370. end;
  371.  
  372. procedure Puzzle;
  373. var
  374.   P: PPuzzleWindow;
  375. begin
  376.   P := New(PPuzzleWindow, Init);
  377.   P^.HelpCtx := hcPuzzle;
  378.   InsertWindow(P);
  379. end;
  380.  
  381. procedure Calendar;
  382. var
  383.   P: PCalendarWindow;
  384. begin
  385.   P := New(PCalendarWindow, Init);
  386.   P^.HelpCtx := hcCalendar;
  387.   InsertWindow(P);
  388. end;
  389.  
  390. procedure About;
  391. var
  392.   D: PDialog;
  393.   Control: PView;
  394.   R: TRect;
  395. begin
  396.   R.Assign(0, 0, 40, 11);
  397.   D := New(PDialog, Init(R, 'About'));
  398.   with D^ do
  399.   begin
  400.     Options := Options or ofCentered;
  401.  
  402.     R.Grow(-1, -1);
  403.     Dec(R.B.Y, 3);
  404.     Insert(New(PStaticText, Init(R,
  405.       #13 +
  406.       ^C'Turbo Vision Demo'#13 +
  407.       #13 +
  408.       ^C'Copyright (c) 1992'#13 +
  409.       #13 +
  410.       ^C'Borland International')));
  411.  
  412.     R.Assign(15, 8, 25, 10);
  413.     Insert(New(PButton, Init(R, 'O~K', cmOk, bfDefault)));
  414.   end;
  415.   if ValidView(D) <> nil then
  416.   begin
  417.     Desktop^.ExecView(D);
  418.     Dispose(D, Done);
  419.   end;
  420. end;
  421.  
  422. procedure AsciiTab;
  423. var
  424.   P: PAsciiChart;
  425. begin
  426.   P := New(PAsciiChart, Init);
  427.   P^.HelpCtx := hcAsciiTable;
  428.   InsertWindow(P);
  429. end;
  430.  
  431. procedure Calculator;
  432. var
  433.   P: PCalculator;
  434. begin
  435.   P := New(PCalculator, Init);
  436.   P^.HelpCtx := hcCalculator;
  437.   InsertWindow(P);
  438. end;
  439.  
  440. procedure Colors;
  441. var
  442.   D: PColorDialog;
  443. begin
  444.   D := New(PColorDialog, Init('',
  445.     ColorGroup('Desktop',       DesktopColorItems(nil),
  446.     ColorGroup('Menus',         MenuColorItems(nil),
  447.     ColorGroup('Dialogs/Calc',  DialogColorItems(dpGrayDialog, nil),
  448.     ColorGroup('Editor/Puzzle', WindowColorItems(wpBlueWindow, nil),
  449.     ColorGroup('Ascii table',   WindowColorItems(wpGrayWindow, nil),
  450.     ColorGroup('Calendar',
  451.       WindowColorItems(wpCyanWindow,
  452.       ColorItem('Current day',       22, nil)),
  453.       nil))))))));
  454.  
  455.   D^.HelpCtx := hcOCColorsDBox;
  456.  
  457.   if ExecuteDialog(D, Application^.GetPalette) <> cmCancel then
  458.   begin
  459.     DoneMemory;    { Dispose all group buffers }
  460.     ReDraw;        { Redraw application with new palette }
  461.   end;
  462. end;
  463.  
  464. procedure Mouse;
  465. var
  466.   D: PDialog;
  467. begin
  468.   D := New(PMouseDialog, Init);
  469.   D^.HelpCtx := hcOMMouseDBox;
  470.   ExecuteDialog(D, @MouseReverse);
  471. end;
  472.  
  473. procedure RetrieveDesktop;
  474. var
  475.   S: PStream;
  476.   Signature: string[SignatureLen];
  477. begin
  478.   S := New(PBufStream, Init('TVDEMO.DSK', stOpenRead, 1024));
  479.   if LowMemory then OutOfMemory
  480.   else if S^.Status <> stOk then
  481.     MessageBox('Could not open desktop file', nil, mfOkButton + mfError)
  482.   else
  483.   begin
  484.     Signature[0] := Char(SignatureLen);
  485.     S^.Read(Signature[1], SignatureLen);
  486.     if Signature = DSKSignature then
  487.     begin
  488.       LoadDesktop(S^);
  489.       LoadIndexes(S^);
  490.       LoadHistory(S^);
  491.       if S^.Status <> stOk then
  492.         MessageBox('Error reading desktop file', nil, mfOkButton + mfError);
  493.     end
  494.     else
  495.       MessageBox('Error: Invalid Desktop file.', nil, mfOkButton + mfError);
  496.   end;
  497.   Dispose(S, Done);
  498. end;
  499.  
  500. procedure SaveDesktop;
  501. var
  502.   S: PStream;
  503.   F: File;
  504. begin
  505.   S := New(PBufStream, Init('TVDEMO.DSK', stCreate, 1024));
  506.   if not LowMemory and (S^.Status = stOk) then
  507.   begin
  508.     S^.Write(DSKSignature[1], SignatureLen);
  509.     StoreDesktop(S^);
  510.     StoreIndexes(S^);
  511.     StoreHistory(S^);
  512.     if S^.Status <> stOk then
  513.     begin
  514.       MessageBox('Could not create TVDEMO.DSK.', nil, mfOkButton + mfError);
  515.       {$I-}
  516.       Dispose(S, Done);
  517.       Assign(F, 'TVDEMO.DSK');
  518.       Erase(F);
  519.       Exit;
  520.     end;
  521.   end;
  522.   Dispose(S, Done);
  523. end;
  524.  
  525. procedure FileNew;
  526. begin
  527.   OpenEditor('', True);
  528. end;
  529.  
  530. procedure ShowClip;
  531. begin
  532.   ClipWindow^.Select;
  533.   ClipWindow^.Show;
  534. end;
  535.  
  536. begin
  537.   inherited HandleEvent(Event);
  538.   case Event.What of
  539.     evCommand:
  540.       begin
  541.         case Event.Command of
  542.           cmOpen: FileOpen('*.*');
  543.           cmNew: FileNew;
  544.           cmShowClip: ShowClip;
  545.           cmChangeDir: ChangeDir;
  546.           cmAbout: About;
  547.           cmPuzzle: Puzzle;
  548.           cmCalendar: Calendar;
  549.           cmAsciiTab: AsciiTab;
  550.           cmCalculator: Calculator;
  551.           cmColors: Colors;
  552.           cmMouse: Mouse;
  553.           cmSaveDesktop: SaveDesktop;
  554.           cmRetrieveDesktop: RetrieveDesktop;
  555.         else
  556.           Exit;
  557.         end;
  558.         ClearEvent(Event);
  559.       end;
  560.   end;
  561. end;
  562.  
  563. procedure TTVDemo.Idle;
  564.  
  565. function IsTileable(P: PView): Boolean; far;
  566. begin
  567.   IsTileable := P^.Options and ofTileable <> 0;
  568. end;
  569.  
  570. begin
  571.   TApplication.Idle;
  572.   Clock^.Update;
  573.   Heap^.Update;
  574.   if Desktop^.FirstThat(@IsTileable) <> nil then
  575.     EnableCommands([cmTile, cmCascade])
  576.   else
  577.     DisableCommands([cmTile, cmCascade]);
  578. end;
  579.  
  580. procedure TTVDemo.InitMenuBar;
  581. var
  582.   R: TRect;
  583. begin
  584.   GetExtent(R);
  585.   R.B.Y := R.A.Y+1;
  586.   MenuBar := New(PMenuBar, Init(R, NewMenu(
  587.     NewSubMenu('~'#240'~', hcSystem, NewMenu(
  588.       NewItem('~A~bout', '', kbNoKey, cmAbout, hcSAbout,
  589.       NewLine(
  590.       NewItem('~P~uzzle', '', kbNoKey, cmPuzzle, hcSPuzzle,
  591.       NewItem('Ca~l~endar', '', kbNoKey, cmCalendar, hcSCalendar,
  592.       NewItem('Ascii ~t~able', '', kbNoKey, cmAsciiTab, hcSAsciiTable,
  593.       NewItem('~C~alculator', '', kbNoKey, cmCalculator, hcCalculator, nil))))))),
  594.     NewSubMenu('~F~ile', hcFile, NewMenu(
  595.       StdFileMenuItems(nil)),
  596.     NewSubMenu('~E~dit', hcNoContext, NewMenu(
  597.       StdEditMenuItems(
  598.       NewLine(
  599.       NewItem('~S~how clipboard', '', kbNoKey, cmShowClip, hcShowClip,
  600.       nil)))),
  601.     NewSubMenu('~S~earch', hcNoContext, NewMenu(
  602.       NewItem('~F~ind...', '', kbNoKey, cmFind, hcNoContext,
  603.       NewItem('~R~eplace...', '', kbNoKey, cmReplace, hcNoContext,
  604.       NewItem('~S~earch again', '', kbNoKey, cmSearchAgain, hcNoContext,
  605.       nil)))),
  606.     NewSubMenu('~W~indows', hcWindows, NewMenu(
  607.       StdWindowMenuItems(nil)),
  608.     NewSubMenu('~O~ptions', hcOptions, NewMenu(
  609.       NewItem('~M~ouse...', '', kbNoKey, cmMouse, hcOMouse,
  610.       NewItem('~C~olors...', '', kbNoKey, cmColors, hcOColors,
  611.       NewLine(
  612.       NewItem('~S~ave desktop', '', kbNoKey, cmSaveDesktop, hcOSaveDesktop,
  613.       NewItem('~R~etrieve desktop', '', kbNoKey, cmRetrieveDesktop, hcORestoreDesktop, nil)))))),
  614.       nil)))))))));
  615. end;
  616.  
  617. procedure TTVDemo.InitStatusLine;
  618. var
  619.   R: TRect;
  620. begin
  621.   GetExtent(R);
  622.   R.A.Y := R.B.Y - 1;
  623.   StatusLine := New(PStatusLine, Init(R,
  624.     NewStatusDef(0, $FFFF,
  625.       NewStatusKey('~Alt-X~ Exit', kbAltX, cmQuit,
  626.       NewStatusKey('~F1~ Help', kbF1, cmHelp,
  627.       NewStatusKey('~F3~ Open', kbF3, cmOpen,
  628.       NewStatusKey('~Alt-F3~ Close', kbAltF3, cmClose,
  629.       NewStatusKey('~F5~ Zoom', kbF5, cmZoom,
  630.       NewStatusKey('', kbF10, cmMenu,
  631.       NewStatusKey('', kbCtrlF5, cmResize,
  632.       nil))))))),
  633.     nil)));
  634. end;
  635.  
  636. procedure TTVDemo.OutOfMemory;
  637. begin
  638.   MessageBox('Not enough memory available to complete operation.',
  639.     nil, mfError + mfOkButton);
  640. end;
  641.  
  642. { Since the safety pool is only large enough to guarantee that allocating
  643.   a window will not run out of memory, loading the entire desktop without
  644.   checking LowMemory could cause a heap error.  This means that each
  645.   window should be read individually, instead of using Desktop's Load.
  646. }
  647.  
  648. procedure TTVDemo.LoadDesktop(var S: TStream);
  649. var
  650.   P: PView;
  651.   Pal: PString;
  652.  
  653. procedure CloseView(P: PView); far;
  654. begin
  655.   Message(P, evCommand, cmClose, nil);
  656. end;
  657.  
  658. begin
  659.   if Desktop^.Valid(cmClose) then
  660.   begin
  661.     Desktop^.ForEach(@CloseView); { Clear the desktop }
  662.     repeat
  663.       P := PView(S.Get);
  664.       Desktop^.InsertBefore(ValidView(P), Desktop^.Last);
  665.     until P = nil;
  666.     Pal := S.ReadStr;
  667.     if Pal <> nil then
  668.     begin
  669.       Application^.GetPalette^ := Pal^;
  670.       DoneMemory;
  671.       Application^.ReDraw;
  672.       DisposeStr(Pal);
  673.     end;
  674.   end;
  675. end;
  676.  
  677. procedure TTVDemo.StoreDesktop(var S: TStream);
  678. var
  679.   Pal: PString;
  680.  
  681. procedure WriteView(P: PView); far;
  682. begin
  683.   if P <> Desktop^.Last then S.Put(P);
  684. end;
  685.  
  686. begin
  687.   Desktop^.ForEach(@WriteView);
  688.   S.Put(nil);
  689.   Pal := @Application^.GetPalette^;
  690.   S.WriteStr(Pal);
  691. end;
  692.  
  693.  
  694. var
  695.   Demo: TTVDemo;
  696.  
  697. begin
  698.   Demo.Init;
  699.   Demo.Run;
  700.   Demo.Done;
  701. end.
  702.