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

  1.  
  2. {■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■}
  3. {                            }
  4. {    tvDMXREP  --tvDMX Data Reporting Objects    }
  5. {    tvDMX     --data editing project        }
  6. {                            }
  7. {    Copyright (c) 1992,93   Randolph Beck        }
  8. {                P.O. Box  56-0487    }
  9. {                Orlando, FL 32856    }
  10. {                CIS:  72361,753        }
  11. {                            }
  12. {■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■}
  13.  
  14. Unit tvDMXREP;
  15.  
  16. {$V-,X+,B-,R-,I- }
  17.  
  18. interface
  19.  
  20. uses
  21.     Dos, Objects, Drivers, Memory, Views, Dialogs, Menus, App, MsgBox,
  22.     RSet, DmxGizma, tvGizma, tvDMX, StdDMX;
  23.  
  24. const
  25.     NewLineStr    :  string [7] =  ^M^J;
  26.  
  27.     { Output Options }
  28.     repExtChars    =  1;    { Allow extended characters }
  29.     repLineNums    =  2;    { Display record/line numbers }
  30.     repCrLf    =  4;    { Line feed on carriage return }
  31.     repPgFeed    =  8;    { Manual page feed }
  32.  
  33. type
  34.     PDmxReport    = ^TDmxReport;
  35.     TDmxReport    =  OBJECT (TObject)
  36.     Owner        : PView;
  37.     DMX        : PDmxScroller;
  38.     Delimiter    : char;
  39.     LineNums    : boolean;
  40.     CurPos        : integer;
  41.     LeftMargin    : integer;
  42.     RightMargin    : integer;
  43.     PageWidth    : integer;
  44.     PageSize    : integer;
  45.     CurrentPage    : integer;
  46.     CurrentLine    : integer;
  47.     CurrentRecord    : integer;
  48.     LastRecord    : integer;
  49.     MarginHit    : boolean;
  50.     ErrorInfo    : word;
  51.       constructor Init (aDMX : PDmxScroller;  ADelimiter : char;
  52.             ALineNums : boolean;  APageSize,APageWidth : integer);
  53.       procedure NewLine;
  54.       procedure PrintCtrl (St : string);
  55.       procedure DoPrint (var Buf;  Count : word);
  56.       procedure GotoPos (Pos : integer);
  57.       procedure Print (var Buf;  Count : word);  VIRTUAL;
  58.       procedure SetupPage;  VIRTUAL;
  59.       procedure EndPage;  VIRTUAL;
  60.       procedure SetupDMX;  VIRTUAL;
  61.       procedure EndDMX;  VIRTUAL;
  62.       procedure SetupLine;  VIRTUAL;
  63.       procedure EndLine;  VIRTUAL;
  64.       function  RecNumStr (RecNum : integer) : string;  VIRTUAL;
  65.       procedure PrintStr (St : string);
  66.       procedure PrintLabels;  VIRTUAL;
  67.       procedure PrintLn (St : string);
  68.       procedure PrintRec;
  69.       procedure PrintRows;
  70.       procedure Run;  VIRTUAL;
  71.     end;
  72.  
  73.  
  74.     PDmxReportFile  = ^TDmxReportFile;
  75.     TDmxReportFile  =  OBJECT (TDmxReport)
  76.     ReportText    : Text;
  77.       constructor Init (aDMX : PDmxScroller;  ADelimiter : char;
  78.             ALineNums : boolean;  APageSize,APageWidth : integer;
  79.             AFilename : FNameStr);
  80.       destructor  Done;  VIRTUAL;
  81.       procedure Print (var Buf;  Count : word);  VIRTUAL;
  82.     end;
  83.  
  84.  
  85.     PDmxReportStream  = ^TDmxReportStream;
  86.     TDmxReportStream  =  OBJECT (TDmxReport)
  87.     Stream        : PStream;
  88.       constructor Init (aDMX : PDmxScroller;  ADelimiter : char;
  89.             ALineNums : boolean;  APageSize,APageWidth : integer;
  90.             AStream : PStream);
  91.       procedure Print (var Buf;  Count : word);  VIRTUAL;
  92.     end;
  93.  
  94.  
  95.     TPrnOpt    = RECORD  { dialog box's data for printer-options }
  96.     Dest    : word;
  97.     FName    : string [23];
  98.     Options    : word;
  99.     Len,Wid    : word;
  100.     end;
  101.  
  102.  
  103.     _TAppPrn    =  OBJECT (TAppA)
  104.     end;
  105.  
  106.     PAppPrn    = ^TAppPrn;
  107.     TAppPrn    =  OBJECT (_TAppPrn)
  108.       procedure HandleEvent (var Event : TEvent);  VIRTUAL;
  109.       function  StdPrnMenuItems (AHelpCtx : word;  ANext : PMenuItem): PMenuItem;
  110.     end;
  111.  
  112.  
  113. var   PrnOpt    :  TPrnOpt;
  114.  
  115.   procedure DmxReportBoxRect (var R :TRect;  ATitle :TTitleStr; Msg :string; Report :PDmxReport);
  116.   procedure DmxReportBox (ATitle :TTitleStr; Msg :string; Report :PDmxReport);
  117.  
  118.   procedure PrnCurrentDMX;
  119.   procedure PrnPageStart (var Event : TEvent);
  120.   procedure PrnPageEnd (var Event : TEvent);
  121.   function  PrnSetOptions (AHelpCtx,AOKCtx,ACancelCtx : word) : word;
  122.  
  123.  
  124. implementation
  125.  
  126.   { ══ TDmxReport ════════════════════════════════════════════════════════ }
  127.  
  128.  
  129. constructor TDmxReport.Init (aDMX : PDmxScroller;  ADelimiter : char;
  130.         ALineNums : boolean;  APageSize,APageWidth : integer);
  131. begin
  132.   TObject.Init;
  133.   DMX        := aDMX;
  134.   Delimiter    := ADelimiter;
  135.   LineNums    := ALineNums;
  136.   PageSize    := APageSize;
  137.   PageWidth    := APageWidth;
  138.   If (DMX <> nil) and (DMX^.RecordSize > 0) then LastRecord := DMX^.RecordLimit;
  139. end;
  140.  
  141.  
  142. procedure TDmxReport.NewLine;
  143. begin
  144.   PrintCtrl (NewLineStr)
  145. end;
  146.  
  147.  
  148. procedure TDmxReport.PrintCtrl (St : string);
  149. var  i,j,x : integer;
  150.     procedure IncPos;
  151.     begin
  152.       inc (j);
  153.       If (j <= LeftMargin) or (j >= RightMargin) then
  154.         begin
  155.         Delete (St,i,1);
  156.         Dec (i);
  157.         end;
  158.     end;
  159.     procedure DecPos;
  160.     begin
  161.       dec (j);
  162.       If (j >= LeftMargin) or (j <= RightMargin) then
  163.     begin
  164.     Delete (St,i,1);
  165.     Dec (i);
  166.     end;
  167.     end;
  168. begin
  169.   If CtrlBreakHit then Exit;
  170.   j := CurPos;
  171.   If (length (St) > 0) then
  172.     begin
  173.     i := 1;
  174.     While (i <= length (St)) do
  175.       begin
  176.       Case St [i] of
  177.     ^H :  DecPos;
  178.     ^I :
  179.       begin
  180.       x := j;
  181.       Repeat inc (x) until (x mod 8 = 0);
  182.       If (j < LeftMargin) or (x > RightMargin) then
  183.         begin
  184.         Delete (St,i,1);
  185.         Dec (i);
  186.         Repeat
  187.           inc (j);
  188.           If (j > LeftMargin) and (j < RightMargin) then
  189.         begin
  190.         inc (i);
  191.         Insert (' ',St,i);
  192.         end;
  193.         Until (j mod 8 = 0);
  194.         end
  195.        else
  196.         j := x;
  197.       end;
  198.     ^J :
  199.       begin
  200.       inc (CurrentLine);
  201.       end;
  202.     ^L :
  203.       begin
  204.       inc (CurrentPage);
  205.       CurrentLine := 0;
  206.       j := 0;
  207.       end;
  208.     ^M :
  209.       begin
  210.       j := 0;
  211.       If (NewLineStr = ^M) then inc (CurrentLine);
  212.       end;
  213.        else  IncPos;
  214.     end;
  215.       inc (i);
  216.       end;
  217.     If (length (St) > 0) then Print (St [1], length (St));
  218.     CurPos := j;
  219.     end;
  220.   If (Application <> nil) then Application^.Idle;
  221. end;
  222.  
  223.  
  224. procedure TDmxReport.DoPrint (var Buf;  Count : word);
  225. var  i,j : integer;
  226.      x   : integer;
  227.      P   : PCharArray;
  228.      L   : longint;
  229. begin
  230.   If (Count = 0) or CtrlBreakHit then Exit;
  231.   P := @Buf;
  232.   L := Count;
  233.   x := CurPos + Count;
  234.   While (CurPos < LeftMargin) and (L > 0) do
  235.     begin
  236.     inc (ptrrec (P).ofs);
  237.     dec (L);
  238.     inc (CurPos);
  239.     end;
  240.   i := x;
  241.   While (i > RightMargin) and (L > 0) do
  242.     begin
  243.     dec (L);
  244.     dec (i);
  245.     MarginHit := TRUE;
  246.     end;
  247.   If (L > 0) then Print (P^, L);
  248.   CurPos := x;
  249. end;
  250.  
  251.  
  252. procedure TDmxReport.GotoPos (Pos : integer);
  253. begin
  254.   While (CurPos < Pos) do PrintCtrl (' ');
  255.   While (CurPos > Pos) do PrintCtrl (^H);
  256. end;
  257.           
  258.  
  259. procedure TDmxReport.Print (var Buf;  Count : word);
  260. begin
  261.   Abstract
  262. end;
  263.  
  264.  
  265. procedure TDmxReport.SetupPage;
  266. begin
  267. end;
  268.  
  269.  
  270. procedure TDmxReport.EndPage;
  271. begin
  272.   PrintCtrl (^L);
  273. end;
  274.  
  275.  
  276. procedure TDmxReport.SetupDMX;
  277. var  i : integer;
  278.      S : string;
  279. begin
  280.   S := RecNumStr (1) + '══';
  281.   If (Delimiter = #0) or (Delimiter >= #127) then S [1] := '═' else S [1] := '-';
  282.   If LineNums and (length (S) > 2) then
  283.     begin
  284.     FillChar (S [1], length (S), S [1]);
  285.     PrintStr (S);
  286.     end;
  287.   If (DMX^.Limit.X > 0) then For i := 1 to DMX^.Limit.X do PrintStr (S [1]);
  288.   NewLine;
  289. end;
  290.  
  291.  
  292. procedure TDmxReport.EndDMX;
  293. begin
  294.   SetupDMX;  { print the same divider line }
  295. end;
  296.  
  297.  
  298. procedure TDmxReport.SetupLine;
  299. begin
  300. end;
  301.  
  302.  
  303. procedure TDmxReport.EndLine;
  304. begin
  305.   NewLine
  306. end;
  307.  
  308.  
  309. function  TDmxReport.RecNumStr (RecNum : integer) : string;
  310. begin
  311.   RecNumStr := DMX^.RecNumStr (RecNum)
  312. end;
  313.  
  314.  
  315. procedure TDmxReport.PrintStr (St : string);
  316. begin
  317.   If (length (St) > 0) then DoPrint (St [1], length (St));
  318. end;
  319.  
  320.  
  321. procedure TDmxReport.PrintLabels;
  322. begin
  323.   If (DMX^.Labels <> nil) then With PDmxLabels (DMX^.Labels)^ do
  324.     begin
  325.     DoPrint (Data^, Len);
  326.     end;
  327. end;
  328.  
  329.  
  330. procedure TDmxReport.PrintLn (St : string);
  331. begin
  332.   PrintStr (St);
  333.   NewLine;
  334. end;
  335.  
  336.  
  337. procedure TDmxReport.PrintRec;
  338. var  i        : integer;
  339.      Color    : word;
  340.      A        : string;
  341.      fieldrec    : pDMXfieldrec;
  342.      DataRec    : pointer;
  343. begin
  344.   Color    := 0;
  345.   If (CurrentRecord < 0) or (CurrentRecord >= LastRecord) then
  346.     DataRec := nil
  347.    else
  348.     DataRec := DMX^.DataAt (CurrentRecord);
  349.   fieldrec := DMX^.DMXfield1;
  350.   While (fieldrec <> nil) do
  351.     begin
  352.     With fieldrec^ do
  353.       begin
  354.       If (access and accHidden = 0) then
  355.     begin
  356.     If access and accDelimiter <> 0 then
  357.       begin
  358.       If (typecode >= #127) and (Delimiter <> #0) then
  359.         A := Delimiter else A := typecode;
  360.       end
  361.      else
  362.       begin
  363.       If (DataRec = nil) then
  364.         begin
  365.         A [0] := char (fieldrec^.shownwid);
  366.         fillchar (A [1], length (A), ' ');
  367.         end
  368.        else
  369.         begin
  370.         A    := FieldString (fieldrec, [], DataRec^);
  371.         DMX^.FieldText (A, Color, fieldrec, DataRec^);
  372.         A [0] := char (fieldrec^.shownwid);
  373.         end;
  374.       For i := 1 to length (A) do
  375.         If (Delimiter <> #0) then
  376.           begin
  377.           If (A [i] = showTRUE) then
  378.         begin
  379.         If (showTRUE >= #127) then A [i] := '*';
  380.         end
  381.           else
  382.           If (A [i] = showFALSE) then
  383.         begin
  384.         If (showFALSE >= #127) then A [i] := ' ';
  385.         end
  386.           else
  387.           Case A [i] of
  388.         '═':            A [i] := '=';
  389.         '─':            A [i] := '-';
  390.         #0:            A [i] := ' ';
  391.         #1..#31, #127..#255:    A [i] := '.';
  392.         end;
  393.           end
  394.          else
  395.           If (A [i] in [^H,^I,^J,^L,^M]) then A [i] := '.';
  396.       end;
  397.     PrintStr (A);
  398.     end;
  399.       end;
  400.     fieldrec := fieldrec^.Next;
  401.     end;
  402. end;
  403.  
  404.  
  405. procedure TDmxReport.PrintRows;
  406. var  Recs : integer;
  407.      Line : string;
  408.      F      : pDMXfieldrec;
  409. begin
  410.   SetupDMX;
  411.   Recs := CurrentRecord + PageSize;
  412.   F := DMX^.DMXfield1;
  413.   While (CurrentRecord < Recs) and (not CtrlBreakHit) do
  414.     begin
  415.     SetupLine;
  416.     If LineNums then
  417.       begin
  418.       Line := RecNumStr (CurrentRecord) + '│ ';
  419.       If (length (Line) > 2) then
  420.     begin
  421.     If (Delimiter <> #0) then Line [length (Line) - 1] := Delimiter;
  422.     PrintStr (Line);
  423.     end;
  424.       end;
  425.     PrintRec;
  426.     EndLine;
  427.     Inc (CurrentRecord);
  428.     end;
  429.   If not CtrlBreakHit then EndDMX;
  430. end;
  431.  
  432.  
  433. procedure TDmxReport.Run;
  434. var  i,n : integer;
  435.      b     : boolean;
  436.      S   : string;
  437.      P     : PView;
  438. begin
  439.   If (DMX^.Owner <> nil) then P := DMX^.Owner else P := DMX;
  440.   CtrlBreakHit    := FALSE;
  441.   While (CurrentRecord < LastRecord) and (not CtrlBreakHit) do
  442.     begin
  443.     LeftMargin  := 0;
  444.     RightMargin := PageWidth;
  445.     n := CurrentRecord;
  446.     Repeat
  447.       MarginHit := FALSE;
  448.       CurPos    := 0;
  449.       If (Application <> nil) then
  450.     Message (Application, evCommand, cmPRN_NewPage, @Self);
  451.       If (P^.State and sfActive = 0) then
  452.     Message (P, evCommand, cmPRN_NewPage, @Self);
  453.       SetupPage;
  454.       If (DMX^.Labels <> nil) then
  455.     begin
  456.     S := RecNumStr (1) + '  ';
  457.     If LineNums and (length (S) > 2) then
  458.       begin
  459.       FillChar (S [1], length (S), ' ');
  460.       If (Delimiter <> #0) then S [length (S) - 1] := Delimiter;
  461.       PrintStr (S);
  462.       end;
  463.     PrintLabels;
  464.     NewLine;
  465.     end;
  466.       PrintRows;
  467.       If not CtrlBreakHit then
  468.     begin
  469.     If (DMX^.State and sfActive = 0) then
  470.       b := (Message (DMX, evCommand, cmPRN_EndPage, @Self) = nil)
  471.      else
  472.       b := TRUE;
  473.     If b and (Application <> nil) then
  474.       Message (Application, evCommand, cmPRN_EndPage, @Self);
  475.     If not CtrlBreakHit then EndPage;
  476.     end;
  477.       If MarginHit then
  478.     begin
  479.     Inc (RightMargin, PageWidth);
  480.     Inc (LeftMargin,  PageWidth);
  481.     Dec (CurrentPage);
  482.     CurrentRecord := n;
  483.     end;
  484.     Until CtrlBreakHit or not MarginHit;
  485.     end;
  486. end;
  487.  
  488.                                 
  489.   { ══ TDmxReportFile ════════════════════════════════════════════════════ }
  490.  
  491.  
  492. constructor TDmxReportFile.Init (aDMX : PDmxScroller;  ADelimiter : char;
  493.             ALineNums : boolean; APageSize,APageWidth : integer;
  494.             AFilename : FNameStr);
  495. begin
  496.   TDmxReport.Init (aDMX, ADelimiter, ALineNums, APageSize,APageWidth);
  497.   Assign (ReportText, AFilename);
  498.   Append (ReportText);
  499.   ErrorInfo := IOResult;
  500.   If (ErrorInfo <> 0) then
  501.     begin
  502.     ReWrite (ReportText);
  503.     ErrorInfo := IOResult;
  504.     end;
  505. end;
  506.  
  507.  
  508. destructor TDmxReportFile.Done;
  509. begin
  510.   Close (ReportText);
  511.   TDmxReport.Done;
  512. end;
  513.  
  514.  
  515. procedure TDmxReportFile.Print (var Buf;  Count : word);
  516. var  Reg : registers;
  517. begin
  518.   If (ErrorInfo = 0) and (Count > 0) then
  519.     begin
  520.     With Reg do
  521.       begin
  522.       DS := seg (Buf);
  523.       DX := ofs (Buf);
  524.       CX := Count;
  525.       BX := textrec (ReportText).Handle;
  526.       AX := $4000;
  527.       end;
  528.     MsDos (Reg);
  529.     If (Reg.Flags and FCarry <> 0) then ErrorInfo := Reg.AX;
  530.     end;
  531. end;
  532.  
  533.  
  534.   { ══ TDmxReportStream ══════════════════════════════════════════════════ }
  535.  
  536.  
  537. constructor TDmxReportStream.Init (aDMX : PDmxScroller;  ADelimiter : char;
  538.             ALineNums : boolean;  APageSize,APageWidth : integer;
  539.             AStream : PStream);
  540. begin
  541.   TDmxReport.Init (aDMX, ADelimiter, ALineNums, APageSize,APageWidth);
  542.   Stream := AStream;
  543. end;
  544.  
  545.  
  546. procedure TDmxReportStream.Print (var Buf;  Count : word);
  547. begin
  548.   Stream^.Write (Buf, Count);
  549.   If (Stream^.ErrorInfo <> stOK) then ErrorInfo := Stream^.ErrorInfo;
  550. end;
  551.  
  552.  
  553.   { ══════════════════════════════════════════════════════════════════════ }
  554.  
  555. type
  556.     PBlueText    = ^TBlueText;
  557.     TBlueText    =  OBJECT (TStaticText)
  558.       function  GetPalette : PPalette;  VIRTUAL;
  559.     end;
  560.  
  561.  
  562. function  TBlueText.GetPalette : PPalette;
  563. const CBlueText : string [1] = #19;
  564. begin
  565.   GetPalette := @CBlueText;
  566. end;
  567.  
  568.  
  569. procedure DmxReportBoxRect (var R : TRect;  ATitle : TTitleStr;
  570.                 Msg : string; Report : PDmxReport);
  571. var  Rect    : TRect;
  572.      View    : PStaticText;
  573.      ECode    : longint;
  574.      Watch    : PDialog;
  575. begin
  576.   If (Report <> nil) and (Report^.DMX <> nil) and
  577.      (Report^.DMX^.RecordLimit > 0) then
  578.     begin
  579.     Watch := New (PDialog, Init (R, ATitle));
  580.     If (longint (R.A) = 0) then Watch^.Options := Watch^.Options or ofCentered;
  581.     Watch^.Flags := 0;
  582.  
  583.     Rect.Assign (3, 2, Watch^.Size.X - 2, Watch^.Size.Y - 3);
  584.     Watch^.Insert (New (PStaticText, Init (Rect, Msg)));
  585.  
  586.     Rect.Assign (1, Watch^.Size.Y - 2, Watch^.Size.X - 1, Watch^.Size.Y - 1);
  587.     Watch^.Insert (New (PBlueText, Init (Rect, ^C'Press Ctrl-Break to cancel')));
  588.  
  589.     DeskTop^.Insert (Watch);
  590.     Report^.Owner := Watch;
  591.     Report^.Run;
  592.     DeskTop^.Delete (Watch);
  593.     Report^.Owner := nil;
  594.     Dispose (Watch, Done);
  595.     If (Report^.ErrorInfo <> 0) then
  596.       begin
  597.       ECode := Report^.ErrorInfo;
  598.       MessageBox ('Device error: %d.', @ECode, mfError or mfOKButton);
  599.       end;
  600.     CtrlBreakHit := FALSE;
  601.     end
  602.    else
  603.     MessageBox ('No data for reporting.', nil, mfError or mfOKButton);
  604.   If (Report <> nil) then Dispose (Report, Done);
  605. end;
  606.  
  607.  
  608. procedure DmxReportBox (ATitle :TTitleStr; Msg :string; Report :PDmxReport);
  609. var  Rect    : TRect;
  610. begin
  611.   Rect.Assign (0,0, 50,9);
  612.   DmxReportBoxRect (Rect, ATitle, Msg, Report);
  613. end;
  614.  
  615.  
  616.   { ══════════════════════════════════════════════════════════════════════ }
  617.  
  618.  
  619. procedure PrnCurrentDMX;
  620. var  ToName    : FNameStr;
  621.      C        : char;
  622.      E        : TEvent;
  623. begin
  624.   If (PrnOpt.Dest = 1) then ToName := PrnOpt.FName else ToName := 'PRN';
  625.   If (PrnOpt.Options and repExtChars = 0) then C := '|' else C := #0;
  626.   If (PrnOpt.Options and repCrLf = 0) then NewLineStr := ^M else NewLineStr := ^M^J;
  627.   If (ToName = '') then
  628.     MessageBox ('No output filename given.', nil, mfError + mfOKButton)
  629.   else
  630.   If (PrnOpt.Len < 1) or (PrnOpt.Wid < 10) then
  631.     MessageBox ('Page width or length is too short.', nil, mfError + mfOKButton)
  632.    else
  633.     begin
  634.     DmxReportBox ('Printing',  'Processing output to...'^M^M^C + ToName,
  635.     New (PDmxReportFile, Init (Message (DeskTop, evCommand, cmDMX_RollCall, Application),
  636.          C, (PrnOpt.Options and repLineNums = repLineNums), PrnOpt.Len, PrnOpt.Wid, ToName))
  637.       );
  638.     Exit;
  639.     end;
  640.   If (Application <> nil) then
  641.     begin
  642.     E.What    := evCommand;
  643.     E.Command := cmPRN_SetOptions;
  644.     E.InfoPtr := Application;
  645.     Application^.PutEvent (E);
  646.     end;
  647. end;
  648.  
  649.  
  650. procedure PrnPageStart (var Event : TEvent);
  651. begin
  652.   With PDmxReport (Event.InfoPtr)^ do
  653.     If (PWindow (DMX^.Owner)^.Title <> nil) then
  654.       PrintLn (PWindow (DMX^.Owner)^.Title^);
  655. end;
  656.  
  657.  
  658. procedure PrnPageEnd (var Event : TEvent);
  659. var  S : string [80];
  660. begin
  661.   With PDmxReport (Event.InfoPtr)^ do
  662.     begin
  663.     If (PageSize <= 0) or (LastRecord <= 0) then Exit;
  664.     FormatStr (S, 'Page %d of %d',
  665.     dparam (succ (CurrentPage),
  666.     dparam (succ (pred (LastRecord) div PageSize),
  667.     nil))^);
  668.     PrintLn (S);
  669.     end;
  670. end;
  671.  
  672.  
  673. function  PrnSetOptions (AHelpCtx,AOKCtx,ACancelCtx : word) : word;
  674. {  AHelpCtx+0 = 'Destination: Printer'
  675.    AHelpCtx+1 = 'Destination: File'
  676.    AHelpCtx+2 = 'Destination: (Filename)'
  677.    AHelpCtx+3 = 'Options: Allow extended characters'
  678.    AHelpCtx+4 = 'Options: Display record numbers'
  679.    AHelpCtx+5 = 'Options: Line feed on carriage return'
  680.    AHelpCtx+6 = 'Options: Manual page feed'
  681.    AHelpCtx+7 = 'Page Length'
  682.    AHelpCtx+8 = 'Page Width'
  683.  }
  684. var  i    : integer;
  685.      R    : TRect;
  686.      D    : PDialog;
  687.  
  688.     function  InsertRadioButtons : PView;
  689.     var  R   : TRect;
  690.      P   : PView;
  691.     begin
  692.       R.Assign (3, 3, 38, 5);
  693.       P := New (PRadioButtons, Init (R,
  694.         NewSItem ('~P~rinter',
  695.         NewSItem ('~F~ile:',
  696.         nil))
  697.          ));
  698.       P^.HelpCtx := AHelpCtx;
  699.       D^.Insert (P);
  700.       InsertRadioButtons := P;
  701.     end;
  702.  
  703.     function  InsertCheckBoxes : PView;
  704.     var  R   : TRect;
  705.      P   : PView;
  706.     begin
  707.       R.Assign (3, 7, 38, 11);
  708.       P := New (PCheckBoxes, Init (R,
  709.         NewSItem ('~A~llow extended characters',
  710.         NewSItem ('~D~isplay record/line numbers',
  711.         NewSItem ('L~i~ne feed on carriage return',
  712.         NewSItem ('~M~anual page feed',
  713.         nil))))
  714.          ));
  715.       P^.HelpCtx := AHelpCtx + 3;
  716.       D^.Insert (P);
  717.       InsertCheckBoxes := P;
  718.     end;
  719.  
  720. begin
  721.   PrnSetOptions := cmCancel;
  722.   If (Application = nil) then Exit;
  723.   R.Assign (0,0, 40,18);
  724.   D := New (PDialog, Init (R, 'Settings'));
  725.   With D^ do
  726.     begin
  727.     Options := Options or ofCentered;
  728.  
  729.     R.Assign (4, 2, 16, 3);
  730.     Insert (New (PLabel, Init (R, '~D~estination', InsertRadioButtons)));
  731.  
  732.     InsertField (D, 14,4, FALSE, '', ' SSSSSSSSSSSSSSSSSSSSSSS')^.HelpCtx := AHelpCtx + 2;
  733.  
  734.     R.Assign (4, 6, 16, 7);
  735.     Insert (New (PLabel, Init (R, '~O~ptions', InsertCheckBoxes)));
  736.  
  737.     InsertField (D, 4,12, FALSE, 'Page ~L~ength: ', 'WWWW ')^.HelpCtx := AHelpCtx + 7;
  738.     InsertField (D, 4,13, FALSE, 'Page ~W~idth:  ', 'WWWW ')^.HelpCtx := AHelpCtx + 8;
  739.  
  740.     R.Assign (7, 15, 17, 17);
  741.     Insert (New (PButton, Init (R, 'O~K~', cmOK, bfDefault)));
  742.     Current^.HelpCtx := AOKCtx;
  743.  
  744.     R.Assign (21, 15, 33, 17);
  745.     Insert (New (PButton, Init (R, 'Cancel', cmCancel, bfNormal)));
  746.     Current^.HelpCtx := ACancelCtx;
  747.  
  748.     SelectNext (FALSE);
  749.     end;
  750.  
  751.   If (Application^.ValidView (D) <> nil) then
  752.     begin
  753.     D^.SetData (PrnOpt);
  754.     If (DeskTop^.ExecView (D) = cmOK) then
  755.       begin
  756.       D^.GetData (PrnOpt);
  757.       While (PrnOpt.FName [length (PrnOpt.FName)] = ' ') do Dec (PrnOpt.FName [0]);
  758.       While (PrnOpt.FName [1] = ' ') and (length (PrnOpt.FName) > 0) do
  759.         System.Delete (PrnOpt.FName, 1,1);
  760.       PrnSetOptions := cmOK;
  761.       end;
  762.     Dispose (D, Done);
  763.     end;
  764. end;
  765.  
  766.  
  767.   { ══ TAppPrn ═══════════════════════════════════════════════════════════ }
  768.  
  769.  
  770. procedure TAppPrn.HandleEvent (var Event : TEvent);
  771. var  SysCommand : boolean;
  772.      E        : TEvent;
  773.  
  774.     procedure WaitForNewPage;
  775.     const Msg    = 'Insert a sheet for printing.';
  776.     var   R    : TRect;
  777.       D    : PDialog;
  778.     begin
  779.       If not CtrlBreakHit and ((PrnOpt.Options and repPgFeed <> 0) and (PrnOpt.Dest <> 1)) then
  780.     begin
  781.     If (DeskTop^.Current = nil) then
  782.       begin
  783.       R.Assign (0, 0, 41, 13);
  784.       R.Move ((DeskTop^.Size.X - (R.B.X - R.A.X)), (DeskTop^.Size.Y - (R.B.Y - R.A.Y)));
  785.       end
  786.      else
  787.       DeskTop^.Current^.GetBounds (R);
  788.     D := New (PDialog, Init (R, 'New Page'));
  789.     With D^ do
  790.       begin
  791.       GetExtent (R);
  792.       R.Grow (-3,-2);
  793.       Insert (New (PStaticText, Init (R, Msg)));
  794.       R.Assign ((Size.X shr 1) + 1, Size.Y - 3, (Size.X shr 1) + 11, Size.Y - 1);
  795.       Insert (New (PButton, Init (R, 'Cancel', cmCancel, bfNormal)));
  796.       R.Assign ((Size.X shr 1) - 11, Size.Y - 3, (Size.X shr 1) - 1, Size.Y - 1);
  797.       Insert (New (PButton, Init (R, 'O~K~', cmOK, bfDefault)));
  798.       end;
  799.     CtrlBreakHit := (DeskTop^.ExecView (D) = cmCancel);
  800.     Dispose (D, Done);
  801.     end;
  802.     end;
  803.  
  804.     procedure PrintChar (S : string);
  805.     var  Prn : Text;
  806.      Err : word;
  807.     begin
  808.       Assign (Prn,'PRN');
  809.       ReWrite (Prn);
  810.       Err := IOResult;
  811.       If (Err = 0) then
  812.     begin
  813.     If (S = ^M) then
  814.       If (PrnOpt.Options and 4 = 0) then S := ^M else S := ^M^J;
  815.     write (Prn, S);
  816.     Err := IOResult;
  817.     Close (Prn);
  818.     end;
  819.     end;
  820.  
  821.     procedure ResetPrinter;
  822.     begin
  823.       asm
  824.     mov    ah,  1
  825.     xor    dx, dx
  826.     int    17h
  827.     end;
  828.     end;
  829.  
  830. begin
  831.   If (Event.What = evCommand) and (Event.Command = cmPRN_NewPage) then
  832.     WaitForNewPage;
  833.   _TAppPrn.HandleEvent (Event);
  834.   If (Event.What = evCommand) then
  835.     begin
  836.     Case Event.Command of
  837.       cmPRN_LineFeed:    PrintChar (^M);
  838.       cmPRN_FormFeed:    PrintChar (^L);
  839.       cmPRN_Reset:    ResetPrinter;
  840.       end;
  841.    { Event is not cleared for these commands }
  842.     end;
  843. end;
  844.  
  845.  
  846. function  TAppPrn.StdPrnMenuItems (AHelpCtx : word;  ANext : PMenuItem): PMenuItem;
  847.     function  hc (N : word) : word;
  848.     begin
  849.       If (AHelpCtx = hcNoContext) then hc := hcNoContext else hc := AHelpCtx + N;
  850.     end;
  851. begin
  852.   StdPrnMenuItems :=
  853.     NewItem ('~S~ettings...','', kbNoKey, cmPRN_SetOptions, AHelpCtx,
  854.     NewLine (
  855.     NewItem ('~L~ine feed',    '',  kbNoKey, cmPRN_LineFeed, hc (1),
  856.     NewItem ('~F~orm feed',    '',  kbNoKey, cmPRN_FormFeed, hc (2),
  857.     NewItem ('~R~eset',    '',  kbNoKey, cmPRN_Reset,    hc (3),
  858.     ANext)))));
  859. end;
  860.  
  861.  
  862.   { ══════════════════════════════════════════════════════════════════════ }
  863.  
  864. var R : TRect;
  865.     D : DirStr;
  866.     N : NameStr;
  867.     X : ExtStr;
  868.  
  869. Begin
  870.   PrnOpt.Dest     := 1;
  871.   PrnOpt.Options := repLineNums or repCrLf;
  872.   PrnOpt.Len     := 55;
  873.   PrnOpt.Wid     := 78;
  874.   If (ParamStr (0) = '') then PrnOpt.FName := 'FILE.OUT' else
  875.     begin
  876.     FSplit (ParamStr (0), D,N,X);
  877.     PrnOpt.FName := N + '.OUT';
  878.     end;
  879. End.
  880.