unit prnutl;{Prn access utilities}
{$I DEFINE.PAS}
interface
uses
  Forms, WinTypes, WinProcs, Graphics,
  SysUtils, MyLib, BinHex, WinSpool,  Printers
  {$IFDEF ALPRINTER}
  ,AlRep
  {$ENDIF}
  ;

const
  mmPerInch = 25.4;

type
  {$IFNDEF ALPRINTER}
  TAlPrinter = Printers.TPrinter;
  {$ENDIF}
  TPrinterPage = record
    Width,
    Height,
    FixLeftMargin,
    FixTopMargin,
    FixRightMargin,
    FixBottomMargin:integer;
  end;

  TDataPrinter = class(TObject)
    {DataSrc:PDataSrc;}
  private
    FPPIX, FPPIY: integer; {pixels per inch in given directions}

  public
    PrinterPage: TPrinterPage;
    Prn: TAlPrinter;

    Index:integer;
    Columns:integer;{1 or 2 (or more?), also for printing tellist}
    CurCol:integer;
    ColumnWidth:Integer;{= AreaWidth or AreaWidth / 2, pixels}
    CharsPerLine,
    LinesPerPage,
    CharHeight,
    CharWidth,
    LineHeight:integer;{pixels}
    LeftMargin,
    TopMargin,
    BottomMargin,
    RightMargin,
    HeadHeight, {area above TopMargin for printing page headings}
    FootHeight:integer;{area below BottomMargin for printing page footers}
    {printing area (does not includes head and foot:}
    AreaWidth,
    AreaHeight:integer;{pixels}
    RecordLeftMargin,
    RecordTopMargin:integer;{for subareas on page}
    RecordWidth,
    RecordHeight : integer;{pixels}
    CurRecordOffset:integer;{current distance of
      left end of string to be printed from RecordLeftMargin pos
      in the record area}
    RecordColumns, RecordRows,
    CurRecordCol, CurRecordRow : integer;{for printing labels, using
      globals LabelRows and LabelColumns}

    CurX, CurY : integer;{cur line start (left top edge)
      in points}
    CheckBottomLines :integer;{how many char lines before reaching
      bottom of printable erea to skip to new column or page; default = 1}
    RecordsRemainedToPrint:integer;{how many records still remain to be
      printed, used to decide if formfeed at the end is necessary}
    ExactPageSize:boolean;
    constructor Create;{(const ADataSrcInfo:TDataSrcInfo; AData:PData);}
    function InspectPrinter:boolean;
    function GetPaperSize(dmPaperSize: integer; var w: single; var h: single): boolean;

    procedure SetPaperMargins;virtual;{called from init
      before adjusting; set paper margins and columns
      to what ever you want(, footheight, headheigh..)}
    procedure SetDefaults;virtual;{e.g. for records}

    procedure Print;virtual;
    procedure PrintRecord;virtual;
      procedure PrintSimpleRecord;{generic just dump it}

    procedure Write(s:string);
    procedure WriteLine(s:string);
    procedure NewColumn;{moves to new column or page}
    procedure MoveTo(X,Y:integer);
    procedure NextRecord;
    procedure FixRecordWidth(var s:string);
    procedure StartPage;virtual;{write heading, page num or anything,
      call at the beggining of print and before Prn.NewPage}
    procedure FinishPage;virtual;{write footing or anyting, call before
      Prn.NewPage}
    procedure SetCurRecordOffset(AOffset:integer);
    function ScanOrPrintRecord(APrint:boolean):integer;
  public
    property PPIX: integer read FPPIX write FPPIX;
    property PPIY: integer read FPPIY write FPPIY;
  end;

implementation

{**************************************************}
{**************************************************}
{***********************************************}


{function MMToPixels(MM:integer):integer;
begin
end;}


function TDataPrinter.GetPaperSize(dmPaperSize: integer; var w: single; var h: single): boolean;
{ returns size of paper in tenths of mm if the code known }
begin
  GetPaperSize := false;
  case dmPaperSize of
    DMPAPER_LETTER:{Letter, 8 1/2 x 11 in.}begin
      w := 8.5 * mmPerInch;
      h := 11 * mmPerInch;
    end;
    DMPAPER_LEGAL:{Legal, 8 1/2 x 14 in.}begin
      w := 8.5 * mmPerInch;
      h := 14 * mmPerInch;
    end;
    DMPAPER_LETTERSMALL:{Letter Small, 8 1/2 x 11 in.}begin
      w := 8.5 * mmPerInch;
      h := 11 * mmPerInch;
    end;
    DMPAPER_TABLOID:{Tabloid, 11 x 17 in.} begin
      w := 11 * mmPerInch;
      h := 17 * mmPerInch;
    end;
    DMPAPER_LEDGER:{Ledger, 17 x 11 in.}begin
      w := 17 * mmPerInch;
      h := 11 * mmPerInch;
    end;
    DMPAPER_STATEMENT:{Statement, 5 1/2 x 8 1/2 in.}begin
      w := 5.5 * mmPerInch;
      h := 8.5 * mmPerInch;
    end;
    DMPAPER_EXECUTIVE:{Executive, 7 1/2 x 10 1/2 in.}begin
      w := 7.5 * mmPerInch;
      h := 10.5 * mmPerInch;
    end;
    DMPAPER_A3:{A3, 297 x 420 mm}begin
      w := 297;
      h := 420;
    end;
    DMPAPER_A4:{A4, 210 x 297 mm}begin
      w := 210;
      h := 297;
    end;
    DMPAPER_A4SMALL:{A4 Small, 210 x 297 mm}begin
      w := 210;
      h := 297;
    end;
    DMPAPER_A5:{A5, 148 x 210 mm}begin
      w := 148;
      h := 210;
    end;
    DMPAPER_B4:{B4, 250 x 354 mm}begin
      w := 250;
      h := 354;
    end;
    DMPAPER_B5:{B5, 182 x 257 mm}begin
      w := 182;
      h := 257;
    end;
    DMPAPER_FOLIO:{Folio, 8 1/2 x 13 in.}begin
      w := 8.5 * mmperinch;
      h := 13 * mmperinch;
    end;
    DMPAPER_QUARTO:{Quarto, 215 x 275 mm}begin
      w := 215;
      h := 275;
    end;
    DMPAPER_10X14:{10 x 14 in.}begin
      w := 10 * mmperinch;
      h := 14 * mmperinch;
    end;
    DMPAPER_11X17:{11 x 17 in.}begin
      w := 11 * mmperinch;
      h := 17 * mmperinch;
    end;
    DMPAPER_NOTE:{Note, 8 1/2 x 11 in.}begin
      w := 8.5 * mmperinch;
      h := 11 * mmperinch;
    end;
    DMPAPER_ENV_9:{Envelope #9, 3 7/8 x 8 7/8 in.}begin
      w := 3.875 * mmperinch;
      h := 8.875 * mmperinch;
    end;
    DMPAPER_ENV_10:{Envelope #10, 4 1/8 x 9 1/2 in.}begin
      w := 4.125 * mmperinch;
      h := 9.5 * mmperinch;
    end;
    DMPAPER_ENV_11:{Envelope #11, 4 1/2 x 10 3/8 in.}begin
      w := 4.5 * mmperinch;
      h := 10.375 * mmperinch;
    end;
    DMPAPER_ENV_12:{Envelope #12, 4 1/2 x 11 in.}begin
      w := 4.5 * mmperinch;
      h := 11 * mmperinch;
    end;
    {DMPAPER_ENV_12	#12 Envelope, 4 3/4- by 11-inches}

    DMPAPER_ENV_14:{Envelope #14, 5 x 11 1/2 in.}begin
      w := 5 * mmperinch;
      h := 11.5 * mmperinch;
    end;
    DMPAPER_CSHEET: begin {C Sheet, 17- by 22-inches}
      w := 17 * mmperinch;
      h := 22 * mmperinch;
    end;
    DMPAPER_DSHEET: begin {D Sheet, 22- by 34-inches}
      w := 22 * mmperinch;
      h := 34 * mmperinch;
    end;
    DMPAPER_ESHEET:{E size sheet 34- by 44-inches}begin
      w := 34 * mmperinch;
      h := 44 * mmperinch;
    end;
    DMPAPER_ENV_DL:{Envelope DL, 110 x 220 mm}begin
      w := 110;
      h := 220;
    end;
    DMPAPER_ENV_C3:{Envelope C3, 324 x 458 mm}begin
      w := 324;
      h := 458;
    end;
    DMPAPER_ENV_C4:{Envelope C4, 229 x 324 mm}begin
      w := 229;
      h := 324;
    end;
    DMPAPER_ENV_C5:{Envelope C5, 162 x 229 mm}begin
      w := 162;
      h := 229;
    end;
    DMPAPER_ENV_C6:{Envelope C6, 114 x 162 mm}begin
      w := 114;
      h := 162;
    end;
    DMPAPER_ENV_C65:{Envelope C65, 114 x 229 mm}begin
      w := 114;
      h := 229;
    end;
    DMPAPER_ENV_B4:{Envelope B4, 250 x 353 mm}begin
      w := 250;
      h := 353;
    end;
    DMPAPER_ENV_B5:{Envelope B5, 176 x 250 mm}begin
      w := 176;
      h := 250;
    end;
    DMPAPER_ENV_B6:{Envelope B6, 176 x 125 mm}begin
      w := 176;
      h := 125;
    end;
    DMPAPER_ENV_ITALY:{Envelope, 110 x 230 mm}begin
      w := 110;
      h := 230;
    end;
    DMPAPER_ENV_MONARCH:{Envelope Monarch, 3 7/8 x 7 1/2 in.}begin
      w := 3.875 * mmperinch;
      h := 7.2 * mmperinch;
    end;
    DMPAPER_ENV_PERSONAL:{Envelope, 3 5/8 x 6 1/2 in.}begin
      w := 3.625 * mmperinch;
      h := 6.5 * mmperinch;
    end;
    DMPAPER_FANFOLD_US:{U.S. Standard Fanfold, 14 7/8 x 11 in.}begin
      w := 14.875 * mmperinch;
      h := 11 * mmperinch;
    end;
    {258}DMPAPER_FANFOLD_STD_GERMAN:{German Standard Fanfold, 8 1/2 x 12 in.}begin
      w := 8.5 * mmperinch;
      h := 12 * mmperinch;
    end;

    DMPAPER_FANFOLD_LGL_GERMAN
    {DMPAPER_LAST}:{German Legal Fanfold, 8 1/2 x 13 in.}begin
      w := 8.5 * mmperinch;
      h := 13 * mmperinch;
    end;
  else
    exit;
  end;
  w := w * 10;
  h := h * 10;
  GetPaperSize := true;
end;

{$IFDEF WIN32}
{PRINTER_INFO_2 DEVMODE}
{   BCHAR  dmDeviceName[CCHDEVICENAME];
    WORD   dmSpecVersion;
    WORD   dmDriverVersion;
    WORD   dmSize;
    WORD   dmDriverExtra;
    DWORD  dmFields;
    short  dmOrientation;
    short  dmPaperSize;
    short  dmPaperLength;
    short  dmPaperWidth;
    short  dmScale;
    short  dmCopies;
    short  dmDefaultSource;
    short  dmPrintQuality;
    short  dmColor;
    short  dmDuplex;
    short  dmYResolution;
    short  dmTTOption;
    short  dmCollate;
    BCHAR  dmFormName[CCHFORMNAME]; 
    WORD  dmLogPixels; 
    DWORD  dmBitsPerPel; 
    DWORD  dmPelsWidth; 
    DWORD  dmPelsHeight;
    DWORD  dmDisplayFlags;
    DWORD  dmDisplayFrequency;
#if(WINVER >= 0x0400)
    DWORD  dmICMMethod;         // Windows 95 only
    DWORD  dmICMIntent;         // Windows 95 only
    DWORD  dmMediaType;         // Windows 95 only
    DWORD  dmDitherType;        // Windows 95 only
    DWORD  dmReserved1;         // Windows 95 only
    DWORD  dmReserved2;         // Windows 95 only }

{v0.38}
function TDataPrinter.InspectPrinter:boolean;
var
  ADeviceName, ADriver, APort: array[0..255] of char;
  FPrinterHandle: THandle;
  Info2: pointer;{PRINTER_INFO_2;}{winspool}
  InfoNeededSize: DWORD;
  res:integer;

  function SetSizes:boolean;
  var
    w, h: single;  {in 0.1 mm units}
  begin
    w := 0; h := 0;
    if not GetPaperSize(PPrinterInfo2(Info2)^.pDevMode^.dmPaperSize, w, h) then begin
      w := PPrinterInfo2(Info2)^.pDevMode^.dmPaperWidth;
      h := PPrinterInfo2(Info2)^.pDevMode^.dmPaperLength;
    end;
    with PrinterPage do begin
      Height := round(h * PPIY / 254);
      Width := round(w *  PPIX / 254);
    end;
    SetSizes := true;
  end;

begin
  InspectPrinter:= false;
  ExactPageSize:= false;
  FPrinterHandle := 0;
  GetMem(Info2, sizeof(PRINTER_INFO_2));
  try
    Prn.GetPrinter(ADeviceName, ADriver, APort, FPrinterHandle);
    if OpenPrinter(ADeviceName, FPrinterHandle, nil) then
    try
      InfoNeededSize := sizeof(PRINTER_INFO_2);
      if not GetPrinter(FPrinterHandle, 2, Info2, InfoNeededSize, @InfoNeededSize) then begin
        res := GetLastError;
        if res = 122 then begin { small info2 buffer, retry: }
          FreeMem(Info2);
          Info2 := nil;
          GetMem(Info2, InfoNeededSize);
          if not GetPrinter(FPrinterHandle, 2, Info2, InfoNeededSize, @InfoNeededSize) then begin
            res := GetLastError;
            exit;
          end;
        end else begin
          exit;
        end;
      end;
    finally
      ClosePrinter(FPrinterHandle);
    end;
    if not SetSizes then
      exit;
  finally
    if Info2 <> nil then begin
      FreeMem(Info2);
      Info2 := nil;
    end;
  end;
  ExactPageSize:= true;
  InspectPrinter := true;
end;

{/v0.38
function TDataPrinter.InspectPrinter:boolean;
var
  ADeviceName, ADriver, APort: array[0..255] of char;
  FPrinterHandle: THandle;
  Info2: PRINTER_INFO_2;
  InfoNeededSize: DWORD;

  function SetSizes:boolean;
  var
    w, h: single;  //in 0.1 mm units
  begin
    w := 0; h := 0;
    if not GetPaperSize(Info2.pDevMode^.dmPaperSize, w, h) then begin
      w := Info2.pDevMode^.dmPaperWidth;
      h := Info2.pDevMode^.dmPaperLength;
    end;
    with PrinterPage do begin
      Height := round(h * PPIY / 254);
      Width := round(w *  PPIX / 254);
    end;
    SetSizes := true;
  end;

label ex;
begin
  InspectPrinter:= false;
  ExactPageSize:= false;
  Prn.GetPrinter(ADeviceName, ADriver, APort, FPrinterHandle);
  InfoNeededSize := sizeof(Info2);
  if not GetPrinter(FPrinterHandle, 2, @Info2, InfoNeededSize, @InfoNeededSize) then begin
    exit;
  end;
  if not SetSizes then
    goto ex;
  ExactPageSize:= true;
  InspectPrinter := true;
ex:
end; }

{$ELSE}
function TDataPrinter.InspectPrinter:boolean;
var
  n, ADeviceName, ADriver, ADriverName, APort: array[0..255] of char;

  I, J: Integer;
  StubDevMode: TDevMode;
  Pin, Pout: PDevMode;

  FDeviceHandle:THandle;
  DeviceMode: THandle;
  loutDeviceMode:word;
  linDeviceMode:word;
  dmSize:word;

  FExtDeviceMode:function(Wnd: HWnd; Driver: THandle;
    var DevModeOutput: TDevMode; DeviceName, Port: PChar;
    var DevModeInput: TDevMode; Profile: PChar; Mode: Word): Integer;


  function SetSizes:boolean;
  var
    w, h: real;  {in 0.1 mm units}
  begin
    SetSizes := false;
    w := 0;
    h := 0;
    if not GetPaperSize(Pout^.dmPaperSize, w, h) begin
      w := Pout^.dmPaperWidth;
      h := Pout^.dmPaperLength;
    end;
    with PrinterPage do begin
      Height := round(h * ppiy / 254);
      Width := round(w *  ppix / 254);
    end;
    SetSizes := true;
  end;

label
  ex;
var
  what: integer;
begin
  InspectPrinter:= false;
  ExactPageSize:= false;

  {CheckPrinting(False);}
  DeviceMode := 0;
  loutDeviceMode:= 0;
  linDeviceMode := 0;

  Prn. GetPrinter(ADeviceName, ADriver, APort, DeviceMode);
  StrCat(StrCopy(ADriverName, ADriver), '.DRV');
  FDeviceHandle := LoadLibrary(ADriverName);
  if FDeviceHandle < HINSTANCE_ERROR{16} then
    exit;

  @FExtDeviceMode := GetProcAddress(FDeviceHandle, 'ExtDeviceMode');
  if not Assigned(FExtDeviceMode) then
    goto ex;

  dmSize := FExtDeviceMode(0, FDeviceHandle, StubDevMode,
    ADeviceName, APort, StubDevMode, nil, 0);
  if DeviceMode = 0 then begin
    linDeviceMode := GlobalAlloc(HeapAllocFlags or GMEM_ZEROINIT,
      dmSize);
  end else begin
    linDeviceMode := DeviceMode;
  end;

  loutDeviceMode := GlobalAlloc(HeapAllocFlags or GMEM_ZEROINIT,
      dmSize);

  if (linDeviceMode = 0) or (loutDeviceMode = 0) then
    goto ex;

  Pin := Ptr(linDeviceMode, 0);
  Pout := Ptr(loutDeviceMode, 0);
  move(Pin^, Pout^, dmSize);

  if pp^.printtype = prLabels then
    what := DM_OUT_BUFFER{DM_IN_PROMPT}
  else
    what := DM_OUT_BUFFER;
  if FExtDeviceMode(0, FDeviceHandle, Pin^, ADeviceName, APort, Pout^, nil,
    what) < 0 then
    goto ex;

  if not SetSizes then
    goto ex;
  ExactPageSize:= true;
  InspectPrinter := true;
ex:
  if (linDeviceMode <> 0) and (DeviceMode = 0) then
    GlobalFree(linDeviceMode);
  if (loutDeviceMode <> 0) then
    GlobalFree(loutDeviceMode);
  linDeviceMode := 0;
  loutDeviceMode := 0;
  FreeLibrary(FDeviceHandle);
end;
{$ENDIF}

constructor TDataPrinter.Create;{(const ADataSrcInfo:TDataSrcInfo; AData:PData);}

  procedure InitPrinterPageSizes;
  label ex;
  begin
    if InspectPrinter then begin{i.e. got exact paper sizes to
      height, width vars}
      with PrinterPage do begin
        FixLeftMargin := (Width - Prn.PageWidth) div 2;
        if FixLeftMargin < 0 then
          FixLeftMargin := 0;
        FixRightMargin := Width - FixLeftMargin - Prn.PageWidth;
        if FixRightMargin < 0 then
          FixRightMargin := 0;

        FixTopMargin := (Height - Prn.PageHeight) div 2;
        if FixTopMargin < 0 then
          FixTopMargin := 0;
        FixBottomMargin := Height - FixTopMargin - Prn.PageHeight;
        if FixBottomMargin < 0 then
          FixBottomMargin := 0;
      end;
    end else begin
      with PrinterPage do begin
        Height := Prn.PageHeight;
        Width := Prn.PageWidth;
        FixLeftMargin := 0;
        FixTopMargin := 0;
        FixRightMargin := Width - Prn.PageWidth - FixLeftMargin;
        FixBottomMargin := Height - Prn.PageHeight - FixTopMargin;
      end;
    end;

    {A4:}
    if (Prn.PageWidth > 2300) and (Prn.PageWidth < 2500) then begin
      {HP 300dpi A4}
      with PrinterPage do begin
        Height := 3507;
        Width := 2480;
        FixLeftMargin := 50;
        FixTopMargin := 60;
        FixRightMargin := 92;
        FixBottomMargin := 58;
      end;
    end else begin

    end;

  ex:
  end;


  procedure ConvertPaperMargins;
  begin
    TopMargin := TopMargin - PrinterPage.FixTopMargin;
    BottomMargin := BottomMargin - PrinterPage.FixBottomMargin;
    LeftMargin := LeftMargin - PrinterPage.FixLeftMargin;
    RightMargin := RightMargin - PrinterPage.FixRightMargin;
    if (HeadHeight > 0) and (TopMargin - HeadHeight < 0) then begin
      TopMargin := HeadHeight;
    end;
  end;

begin
  inherited Create;
  { if not DataSrcInit(ADataSrcInfo, AData, @Self, DataSrc) then
    Fail;}
  Prn := {$IFDEF ALPRINTER}AlPrinter{$ELSE}Printer{$ENDIF};
  Fppix := GetDeviceCaps(Prn.Handle, LOGPIXELSX);
  Fppiy := GetDeviceCaps(Prn.Handle, LOGPIXELSY);
  ExactPageSize := false;
  RecordsRemainedToPrint := 0;
  CurRecordCol := 0;
  CurRecordRow := 0;
  Index := 0;
  CurCol := 0;
  Columns := 1;
  HeadHeight := 0;
    { eventually changed in SetPaperMargins }
  FootHeight := 0;
  CharWidth := Prn.Canvas.TextWidth('M');
  CharHeight := Prn.Canvas.TextHeight('M');
  LineHeight := CharHeight;
  InitPrinterPageSizes;
    SetPaperMargins;
      { override to set page margins and columns }
  ConvertPaperMargins;
    { so that they reflect accessible area, not paper area }
  AreaHeight := Prn.PageHeight - TopMargin - BottomMargin;
  AreaWidth := Prn.PageWidth - LeftMargin - RightMargin;
  ColumnWidth := AreaWidth div Columns;
  CharsPerLine := AreaWidth div CharWidth;
  LinesPerPage := AreaHeight div CharHeight;
  RecordWidth := AreaWidth div Columns;
  RecordHeight := 1;
  RecordLeftMargin := 0;
  RecordTopMargin := 0;
  CurRecordOffset := 0;
  SetDefaults;
    { override to set record margins and sizes }
  MoveTo(LeftMargin + RecordLeftMargin, TopMargin + RecordTopMargin);
end;

procedure TDataPrinter.SetDefaults;
begin
  CheckBottomLines := 1;
end;

procedure TDataPrinter.StartPage;
  { write heading, page num or anything, call at the beggining of print
    and before Prn.NewPage }
begin
{  DataSrcDo(DataSrc, ddStartPage);}
end;

procedure TDataPrinter.FinishPage;{write footing or anyting, call before
      Prn.NewPage}
begin
{  DataSrcDo(DataSrc, ddFinishPage);}
end;

procedure TDataPrinter.SetPaperMargins;
begin
  LeftMargin := ppix;
  RightMargin := LeftMargin;
  TopMargin := ppiy;
  BottomMargin := TopMargin;
{  DataSrcDo(DataSrc, ddSetPaperMargins);}
{  if (PP^.opts and op2columns) <> 0 then
    Columns := 2;}
end;

procedure TDataPrinter.MoveTo(X,Y:integer);
begin
  CurX := X;
  CurY := Y;
  Prn.Canvas.MoveTo(X,Y);
end;

procedure TDataPrinter.SetCurRecordOffset(AOffset:integer);
begin
  CurRecordOffset := AOffset;
  MoveTo(LeftMargin + RecordLeftMargin + CurRecordOffset +
    CurCol * RecordWidth, CurY);
end;

procedure TDataPrinter.Write(S:String);
begin
  FixRecordWidth(s);
  Prn.Canvas.TextOut(CurX, CurY, S);
end;

procedure TDataPrinter.WriteLine(S:string);
begin
  Write(S);
  MoveTo(CurX, CurY + LineHeight);
  if CurY > TopMargin + AreaHeight - (LineHeight * CheckBottomLines) then
    NewColumn;
end;

procedure TDataPrinter.NewColumn;
begin
  inc(CurCol);
  if Columns = CurCol then begin
    FinishPage;
    Prn.NewPage;
    StartPage;
    CurCol := 0;
    MoveTo(LeftMargin + RecordLeftMargin, TopMargin + RecordTopMargin);
  end else begin
   {if CurX < (ColumnWidth * CurCol + LeftMargin) then begin}
    MoveTo(LeftMargin + ColumnWidth * CurCol + RecordLeftMargin,
     TopMargin + RecordTopMargin);
  end;
end;

procedure TDataPrinter.Print;
begin
  Prn.BeginDoc;
  StartPage;
  MoveTo(LeftMargin + RecordLeftMargin, TopMargin + RecordTopMargin);
  {$IFDEF DEBUG}
  Prn.Canvas.Rectangle(0, 0, Prn.PageWidth, Prn.PageHeight);
  {$ENDIF}
  {RecordsRemainedToPrint := DataSrcGetInt(DataSrc, dpRecordCount);}
  Index := 0;
  {if not DataSrcDoAction(DataSrc, daResetSource) then
    exit;

  repeat
    if Prn.Aborted then
      break;
    PrintRecord;
    dec(RecordsRemainedToPrint);
    inc(Index);
  until not DataSrcDoAction(DataSrc, daSkip);
         }
  FinishPage;
  Prn.EndDoc;
end;

procedure TDataPrinter.PrintRecord;
begin
  PrintSimpleRecord;
end;

procedure TDataPrinter.NextRecord;
begin
  inc(CurRecordCol);
  if CurRecordCol = RecordColumns then begin
    inc(CurRecordRow);
    if (CurRecordRow = RecordRows) then
    begin
      if RecordsRemainedToPrint > 1 {i.e. more than just the one just printed}
      then
        Prn.NewPage;
      CurRecordRow := 0;
    end;
    CurRecordCol := 0;
  end;
  CurCol := CurRecordCol;

  MoveTo(LeftMargin + CurRecordCol * RecordWidth + RecordLeftMargin,
    TopMargin + CurRecordRow * RecordHeight + RecordTopMargin);

  if (CurY > (TopMargin + AreaHeight - RecordHeight)) then
  begin
    if RecordsRemainedToPrint > 1 {i.e. more than just the one just printed}
    then begin
      Prn.NewPage;
      CurRecordRow := 0;
      CurRecordCol := 0;
      MoveTo(LeftMargin + CurRecordCol * RecordWidth + RecordLeftMargin,
        TopMargin + CurRecordRow * RecordHeight + RecordTopMargin);
    end;
  end;
end;

function TDataPrinter.ScanOrPrintRecord(APrint:boolean):integer;
begin
  ScanOrPrintRecord := 0;
{  ScanOrPrintRecord := DataSrcGetInt(DataSrc, dpRecordLineCount);
  if APrint then
    DataSrcDoAction(DataSrc, daPrintRecord);}
end;

procedure TDataPrinter.PrintSimpleRecord;{generic just dump it}
var
  recordDist:integer;
begin
  recordDist := LineHeight div 2;
  if (ScanOrPrintRecord(false) * LineHeight + recordDist) >= (TopMargin + AreaHeight - CurY) then
    NewColumn;
  ScanOrPrintRecord(true);
  MoveTo(CurX, CurY + recordDist);
end;

procedure TDataPrinter.FixRecordWidth(var s:string);
var i:integer;
begin
  i := (RecordWidth - RecordLeftMargin - CurRecordOffset);
  if i <= 0 then begin
    s := '';
  end else begin
    while Prn.Canvas.TextWidth(s) > i do begin
      SetLength(s, length(s) - 1);
    end;
  end;
end;


{
procedure PrintData(const ADataSrcInfo:TDataSrcInfo; AData:PData);
var dp:PDataPrinter;
begin
  dp := New(PDataPrinter, Init(ADataSrcInfo, AData));
  if dp <> nil then begin
    dp^.Print;
    Dispose(dp, Done);
  end;
end;
}
end.
