unit PrintDrv;
{
	Version 2.3
  Last Modified: 1/20/2000

	Created by: James "Woody" Woodard
  						2/24/99

  The origins of this component came from the Inprise site and contained most
  of the functionality. I don't remember who the author was but thank him for
  the insight and the main procedures for printing and calculating printer
  metrics. The rest of the implementation is my own and some of the original
  procedures were changed to reflect the addition of the preview mode.

	This component is used as a reporting tool when standard report generators
  don't allow you the flexibility needed for more complex printing. You can
  use this component to provide a more robust method of generating reports.
  Though the amount of work involved in creating a report requires more coding
  than using a report generator, the amount of control you have far outweighs
  the hassles, in my opinion.

  I built this component because I have written several programs that needed to
  be flexible in not only what was printed but where depending on certain criteria
  selectable by the user. Also, most report generators don't allow you to expand
  or contract sections unless you use grids, etc.

  The way this component works is this:
  	Initially, when you issue all of the print commands from start to finish, they
    are stored in an object called Pages. This stores all print commands in lists,
    one list per page. This list of pages and commands is then replayed either to
    the printer or to the preview screen. By capturing the commands this way, it is
    possible for the user to select a printing range of pages instead of the complete
    job if desired.

  Now there is built in support for printing to any TCanvas object. Assign the
  PrinterCanvas property a valid TCanvas object and you can print to it using
  almost all of the print commands. Some of them are not used for obvious reasons
  such as a NewPage.

  Also added is the ability to use either pixels, inches or millimeters for all commands.
  This allows you to structure your printing more to your standards without worrying
  about the conversions of units from one to the other.
}

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls, ExtCtrls, Printers, PrintDr1, PrintDr2;

const
  HeaderLines = 10;                        { Number of allowable header lines }
  FooterLines = 10;                        { Number of allowable footer lines }
  Columns = 20;                            { Number of allowable columns }

type
  THeaderRecord = record
  	Text: string[240];                   { Header text }
    YPosition: single;                   { Inches from the top }
    Alignment: integer;                  { 0:Left 1:Center 2:Right }
    Font: TFont;												 { Current font information }
  end;

  TFooterRecord = record
    Text: string[240];                   { Footer text }
    YPosition: single;                   { Inches from the top }
    Alignment: integer;                  { 0:Left 1:Center 2:Right }
    Font: TFont;												 { Current font information }
  end;

  THeaderCoordinates = record
  	XTop: single;
    YTop: single;
    XBottom: single;
    YBottom: single;
    Boxed: boolean;
    Shading: TColor;
    LineWidth: word;
  end;

  TFooterCoordinates = record
    XTop: single;
    YTop: single;
    XBottom: single;
    YBottom: single;
    Boxed: boolean;
    Shading: TColor;
    LineWidth: word;
  end;

  TPageNumberRecord = record
    YPosition: single;
    Text: string[240];
    Alignment: word;
    Font: TFont;												 { Current font information }
    ShowTotalPages: boolean;
  end;

  TColumnInformationRecord = record
    XPosition: single;
    Length: single;
  end;

  TFontInformationRecord = record
  	Font: TFont;
  end;

  inTPoint = record
  	X,Y: single;
  end;

  Percentages = ({P1_Fifty,}P2_Sixty,P3_Seventy,P4_Eighty,P5_Ninety,P6_Full);

  PrnPaperRec = Record
    pType: integer;
    Width,
    Height: single;
  end;

  PaperSizes = //TMWPaperSizes;
    ( PAPER_LETTER, PAPER_LETTERSMALL, PAPER_TABLOID, PAPER_LEDGER,
     PAPER_LEGAL, PAPER_STATEMENT, PAPER_EXECUTIVE, PAPER_A3,
     PAPER_A4, TBA1, PAPER_A5, PAPER_B4, PAPER_B5, PAPER_FOLIO, PAPER_QUARTO,
     PAPER_10X14, PAPER_11X17, PAPER_NOTE, PAPER_ENV_9, PAPER_ENV_10,
     PAPER_ENV_11, PAPER_ENV_12, PAPER_ENV_14, TBA2, TBA3, TBA4, PAPER_ENV_DL,
     PAPER_ENV_C3, PAPER_ENV_C4, PAPER_ENV_C5, PAPER_ENV_C6, PAPER_ENV_C65,
     PAPER_ENV_B4, PAPER_ENV_B5, PAPER_ENV_B6, PAPER_ENV_ITALY, PAPER_ENV_MONARCH,
     PAPER_ENV_PERSONAL);

  MeasureType = (mtInches, mtMM, mtPixels);

  PPalEntriesArray = ^TPalEntriesArray; {for palette re-construction}
  TPalEntriesArray = array[0..0] of TPaletteEntry;

  TMWPrintObject = class(TComponent)
  private
    PixelsPerInchVertical: integer;   { Number of pixels per inch
    																		along Y axis }
    PixelsPerInchHorizontal: integer; { Number of pixels per inch
                                        along X axis }
    TotalPageWidthPixels: integer;    { Full width of page in pixels
                                        includes gutters }
    TotalPageHeightPixels: integer;   { Full height of page in pixels
                                        includes gutters }
    TotalPageHeightInches: single;    { Height of page in inches }
    TotalPageWidthInches: single;     { Width of page in inches }
    GutterLeft: integer;              { Unprintable area on left }
    GutterRight: integer;             { Unprintable area on right }
    GutterTop: integer;               { Unprintable area on top }
    GutterBottom: integer;            { Unprintable area on bottom }
    LastYPosition: single;            { The Y position where the last
                                        write occurred }
    LastXPosition: single;
    AutoPaging: boolean;              { Are new pages automatically generated? }
    CurrentTab: single;               { The value of the current tab }
    CurrentFonts: array [1..10] of TFontInformationRecord;
    CurrentYPosition: array [1..10] of single;
    CurrentFontRecord: integer;
    CurrentYRecord: integer;
    TextMetrics: TTextMetric;
    Header: Array[1..HeaderLines] of THeaderRecord;
    Footer: Array[1..FooterLines] of TFooterRecord;
    ColumnInformation: Array[1..Columns] of TColumnInformationRecord;
    PageNumber: TPageNumberRecord;
    HeaderCoordinates: THeaderCoordinates;
    FooterCoordinates: TFooterCoordinates;
		ThePrinter: TImage; {Used for current canvas during print preview mode}
    TheCanvas: TCanvas; {This is set to current drawing canvas}
    DryRun,	{used for counting total pages before actually printing report}
    PreviewMode: boolean; {Used to set internal preview mode to build pages}
    ActualPreview: boolean; {Used to control users choice of preview mode}
    ScaleByValue: single; {Used to scale the pixels per inch for scaling}
    UseProgress: boolean; {Shows progress bar if set to true}
    ProgressBar: TPrintBarForm; {Progress bar form}
    DocumentTitle: string; {Title to show in print manager for current job}
    PageOrientation: TPrinterOrientation; {Keep track of orientation}
    ShowDialog: boolean; {True to allow print dialog box to show}
    ShowCancel: boolean; {True will show a cancel button while printing}
    PageNumbering: boolean; {True if page numbering is desired}
    BarShowing: boolean; {In case we abort, need a way to know if progress
    											bar is showing or not to destroy it.}
    ProgressMax: word; {Sets the progress bar maximum}
    ProgressInc: word; {Sets the progress bar increment}
    PrintTransparent: boolean; {True to print transparent text for backgrounds}
    PrintingInternal: boolean; {Flag to control cancelling printing}
    FPageChange: TNotifyEvent; {Event for user to put any specific printing to
    														be done for every page.}
    FAPageChange: TNotifyEvent; {Event for user to put any specific printing to
    														be done for every page.}
    FLastPage,            		{Event called when last page completes printing.}
    FFirstPage,            		{Event called before first page starts printing.}
    FStartPrint,            	{Event called before printing starts.}
    FEndPrint: TNotifyEvent;	{Event called after printing stops.}
    FOnCancelPrint: TNotifyEvent; {Event to cancel printing during processing.}
    PreviewPercent: Percentages;
    PaperDimension: PaperSizes;
    PrintingOK: boolean; {Flag to determine if print object has been initialized
    											and the print job is not aborted.}
    ImagePrinting: boolean; {Flag to tell whether we are going to print to a printer
    														 or a regular canvas for output.}
    ImageCanvas: TCanvas; {Use this to print to something other than a printer. This
    													allows you to print to an image canvas on a form, etc.}
    IsColor: boolean; {used to determine if color printer is being used}
    IsPrinting: boolean; {used to test with IsColor so we don't change color if the
    	the printer we are using does not support it}
    OrigPaperSize,            {used to store the values of the printer before printing}
    OrigPaperOrient: integer; {so we can restore the printer back to original when done}
    Measure: MeasureType; {used to set either inches or millimeters to work with}
    BarFormColor: TColor; {used to set the background color of the progress bar form}
    BarTextColor: TColor; {used to set the color of the text of the progress bar form}

	protected
  	TopMargin: integer;               { Top margin in pixels }
    BottomMargin: integer;            { Bottom margin in pixels }
    LeftMargin: integer;              { Left margin in pixels }
    RightMargin: integer;             { Right margin in pixels }
    DetailTop: single;                { Inches from the top where the
                                        detail section starts }
    DetailBottom: single;             { Inches from the top where the
                                        detail section ends }
    procedure OnPageChange; virtual;
    procedure AfterPageChange; virtual;
    procedure SetPreviewMode(Mode: boolean); {set preview or print mode}
    procedure ShowPreview; {call ShowPreview to see the actual report on screen}
    procedure SetShowTotalPages(Mode: boolean); {set whether to display page number
    																						 with total pages (ex. 1 of 26)}
    procedure Cleanup;
    function CurrentFont: TFont;
    function CurrentFontName: string;
    function CurrentFontSize: word;
    function CurrentFontStyle: TFontStyles;
    function GetShowTotalPages: boolean; {returns current setting of show total pages}
		function CalculateLineHeight: integer;
		procedure WrapText(Text: string; var theText: TStringList; X,Y: single);
		procedure BltTBitmapAsDib(DestDc : hdc;   {Handle of where to blt}
                          		x,       				{Bit at x}
                          		y,       				{Blt at y}
                          		Width,   				{Width to stretch}
                          		Height: integer;{Height to stretch}
                          		bm : TBitmap);  {the TBitmap to Blt}

	public
		constructor Create(AOwner: TComponent); override;{need to initialize some default values}
    destructor Destroy; override;
    procedure CalculateMeasurements;
    procedure UpdateBar(x: integer); {used to set progress bar value}
    procedure IncBar(x: integer); {used to increment the progress bar by X}
    procedure Increment; {used to increment the progress bar by ProgressBarInc value}
    procedure PrintGraphic(X,Y,W,H: single;thePicture: TImage); {Use this procedure to place an image on the printed page.}
		procedure Start; {starts the print job and initializes things}
    procedure Quit; {must be called to complete the print job}
    procedure Abort; {called to abort the print job}
    function InchesToPixelsHorizontal( Inches: single ): integer;
    function InchesToPixelsVertical( Inches: single ): integer;
    function PixelsToInchesHorizontal( Pixels: integer ): single;
    function PixelsToInchesVertical( Pixels: integer ): single;
    function MMToPixelsHorizontal( MM: single ): integer;
    function MMToPixelsVertical( MM: single ): integer;
    function PixelsToMMHorizontal( Pixels: integer ): single;
    function PixelsToMMVertical( Pixels: integer ): single;
    function LinesToPixels( Line:integer ): integer;
    procedure SetMargins( Top,Bottom,Left,Right:single );
    procedure SetFontInformation( Name:string; Size:word; Style: TFontStyles );
		procedure SetFontInfo( Font: TFont );
    procedure WriteLine( X:single; Y:single; Text:string );
    procedure WriteLineRight( Y:single; Text:string );
    procedure WriteLineCenter( Y:single; Text:string );
    procedure WriteLineWrap(XL,XR,Y: single; Text: string; KeepY,SamePage:boolean);
    procedure WriteLineColumnRight( ColumnNumber:word; Y:single; Text:string );
    procedure WriteLineColumnCenter( ColumnNumber:word; Y:single; Text:string );
    procedure WriteLineColumnWrap(ColumnNumber:word; Y:single; Text:string; KeepY,SamePage:boolean);
    procedure WriteLineColumnArray(Y: single; Cols: array of variant;
    														Justif: array of variant;	Strings: array of variant;
                                KeepY, SamePage: boolean);
    function GetColumnLeft(Number:Word): single; {returns start in inches of column}
    function GetColumnRight(Number:Word): single; {returns end in inches of column}
    procedure DrawLine( TopX,TopY,BottomX,BottomY:single; LineWidth:word );
    procedure SetLineWidth( Width:word );
    function  GetLineWidth: word;
    procedure SetTab( Inches:single );
    procedure NewPage;
    function  GetLinesPerPage: integer;
    procedure GetPixelsPerInch( var X:word; var Y:word );
    procedure GetPixelsPerMM( var X:word; var Y:word );
    procedure GetPixelsPerPage( var X:word; var Y:word );
    procedure GetGutter( var Top:word; var Bottom:word; var Left:word;
                         var Right:word );
    function  GetTextWidth( Text:string ): integer;
    function  GetTextWidthMM( Text:string ): single;
    function 	GetTextWidthInches( Text:string): single;
    function  GetLineHeightPixels: word;
    function  GetLineHeightInches: single;
    function  GetLineHeightMM: single;
    function  GetPageNumber:integer;
    function  GetColumnsPerLine: integer;
    procedure SetHeaderInformation( Line:integer; YPosition: single;
                                    Text:string; Alignment:word;
                                    FontName:string; FontSize: word;
                     								FontStyle: TFontStyles );
    procedure SetHeaderInfo( Line:integer; YPosition: single;Text:string;
    												 Alignment:word; Font: TFont );
    procedure SetFooterInformation( Line:integer; YPosition: single; Text:string;
                                    Alignment:word; FontName:string; FontSize: word;
                     								FontStyle: TFontStyles );
    procedure SetFooterInfo( Line:integer; YPosition: single; Text:string;
                             Alignment:word; Font: TFont );
    procedure WriteHeader;
    procedure WriteFooter;
    procedure SaveCurrentFont;
    procedure RestoreCurrentFont;
    procedure SaveCurrentY;
    procedure RestoreCurrentY;
    procedure SetDetailTopBottom( Top: single; Bottom: single );
    procedure SetPageNumberInformation( YPosition:single; Text:string;
                   											Alignment:word; IncludeTotal: boolean;
                                        FontName:string; FontSize:word;
                                        FontStyle:TFontStyles );
    procedure SetPageNumberInfo( YPosition:single; Text:string;
                   						 	 Alignment:word; IncludeTotal: boolean;
                                 Font:TFont );
    procedure WritePageNumber;
    procedure WriteLineColumn( ColumnNumber:word; Y:single; Text:string );
    procedure DrawBox( XTop,YTop,XBottom,YBottom:single; LineWidth:word );
    procedure DrawBoxShaded( XTop,YTop,XBottom,YBottom:single; LineWidth:word;
    												 Shading:word );
    procedure DrawBoxShade( XTop,YTop,XBottom,YBottom:single; LineWidth:word;
    												 Shading:TColor );


    procedure DrawTextBox( XTop,YTop,XBottom,YBottom:single; LineWidth:word;
    											 Shading:word; Text: string; Column: integer;
                           Alignment: word ); {draws a box around written text}
    procedure TextColumnBox( XTop,YTop,XBottom,YBottom:single; LineWidth:word;
    											 	 Shading:TColor; Text: string; Column: integer;
                             Alignment: word ); {draws a box around written text}


    procedure SetHeaderDimensions( XTop,YTop,XBottom,YBottom:single; Boxed: boolean;
    															 LineWidth:word; Shading:word );
    procedure SetHeaderDim( XTop,YTop,XBottom,YBottom:single; Boxed: boolean;
    															 LineWidth:word; Shading:TColor );


    procedure SetFooterDimensions( XTop,YTop,XBottom,YBottom:single; Boxed: boolean;
    															 LineWidth:word; Shading:word );
    procedure SetFooterDim( XTop,YTop,XBottom,YBottom:single; Boxed: boolean;
    															 LineWidth:word; Shading:TColor );


    procedure CreateColumn( Number:word; XPosition:single; Length:single );
    procedure SetYPosition( YPosition:single );
    function  GetYPosition: single;
    procedure NextLine;
    function  GetLinesLeft: word;
    function  GetLinesInDetailArea: word;
    procedure SetTopOfPage;
    procedure NewLines( Number:word );
    procedure OnCancelPrint;
    procedure SetProgressMax(Max: integer);
    procedure SetAutoPaging( Value: boolean );
	{Added Gets for the font information making it easier to use SetFontInformation.}
    property GetFontName: string read CurrentFontName;
    property GetFontSize: word read CurrentFontSize;
    property GetFontStyle: TFontStyles read CurrentFontStyle;
    property PrintingStatus: boolean read PrintingOK;
    {Used to coordinate the TMWPrintObject and the Printer so that you can code your
     own printer setup routine. After setting up the printer like you want it, Call
     GetPrinterSpecs to update the TMWPrintObject with the new settings.}
    procedure SetPrinterSpecs;
    procedure GetPrinterSpecs;
    procedure WritePrinterSpecs(RestoreState: boolean); {sets the orientation and
    																										 paper size of current printer}
    procedure ReadPrinterSpecs(SaveState: boolean); {gets the orientation and
    																								 paper size of current printer}
    procedure SetOrientation(Orient: TPrinterOrientation);
    procedure SetPaperSize(Size: PaperSizes);
  {These procedures and functions are used internally and by the preview
   form unit. They should not be called from outside of this component.}
    procedure SetPrnPrinter(Current: TImage); {used when printing to TImage}
    procedure PrintPage(Page: TMWPageList;iPage: integer); {procedure to
        	loop through the current page commands and output to screen or printer}
    procedure PrintFromPreview; {used to print from the preview screen}
    function GetScale: single; {returns the current scale factor}
    procedure SetScale(ScaleFactor: single); {sets the current scale factor}
    procedure ClearCanvas(iColor: TColor); {clears the canvas when printing to an image canvas}
    procedure ClearCanvasArea(XTop,YTop,XBottom,YBottom: integer; iColor: TColor); {clears a
    	section of the canvas we are printing on. This is in integer form because
      we assume the printing is on a graphic canvas.}
    procedure SetFontColor(iColor: TColor);
    function GetFontColor: TColor;
    procedure SetBrushColor(iColor: TColor);
    function GetBrushColor: TColor;
    procedure SetPenColor(iColor: TColor);
    function GetPenColor: TColor;
    procedure SetPenWidth(iWidth: integer);
    function GetPenWidth: integer;
    property PrinterCanvas: TCanvas read ImageCanvas write ImageCanvas;
    procedure SetBrushStyle(Style: TBrushStyle);
    procedure SetPenStyle(Style: TPenStyle);
    procedure SetPenMode(Mode: TPenMode);
    function GetBrushStyle: TBrushStyle;
    function GetPenStyle: TPenStyle;
    function GetPenMode: TPenMode;
    function MMToInches(mm: single): single;
    function InchesToMM(inches: single): single;
    procedure SetMeasure(Meas: MeasureType);
    function CurrentPageNumber: integer;

{ The following are graphic commands for drawing on the current canvas. Each
	one is duplicated for using either pixels or inches to specify the drawing.
  To use pixels, call the method like you would normally for a canvas. To use
  inches, call the method with Inches appended to the name. }
		procedure Arc(X1,Y1,X2,Y2,X3,Y3,X4,Y4: single);
    procedure LineTo(X1,Y1: single);
    procedure MoveTo(X1,Y1: single);
    procedure Ellipse(X1,Y1,X2,Y2: single);
    procedure FillRect(X1, Y1, X2, Y2: single);
    procedure FloodFill(X,Y: single;Color: TColor;FillStyle: TFillStyle);
    procedure FrameRect(X1,Y1,X2,Y2: single);
		procedure Pie(X1,Y1,X2,Y2,X3,Y3,X4,Y4: single);
    procedure PolyLine(Points: array of single);
    procedure Polygon(Points: array of single);

{Added Published properties for ease of setting certain properties at design time.}

	published
  	{Properties:
    	AutomaticPaging: can be used to automatically do NewPage when printing.
      Title: this text becomes the title of the print job in printer manager
      Preview: whether to print directly to printer of show preview of job
      ShowProgress: display a progress bar or not
      ShowPrintDialog: whether to show print dialog to allow user to select
      								 printer, pages to print, etc.
      Orientation: set page orientation (can only be set for all pages)
      ShowTotalPages: sets whether to display page number as 1 of x or not
      ProgressBarMax: sets the maximum progress bar value
      ProgressBarInc: sets the increment for the progress bar
      Transparent: if you want a background image, this sets the text to print
      						 transparently so it shows through
      StartPercent: sets the beginning scale factor for viewing previews
      PaperSize: sets either legal or letter size paper
      ShowCancelBtn: determines whether to display a cancel button for longer
      							print jobs
      Measurement: used to determine whether you are giving value in pixels,
      							inches or millimeters
      ProgressFormColor: sets the progress bar form background color
      ProgressTextColor: sets the color of the text for the messages on the
      									progress bar form
    }
  	property AutomaticPaging: boolean read AutoPaging write AutoPaging;
  	property Title: string read DocumentTitle write DocumentTitle;
  	property Preview: boolean read ActualPreview write ActualPreview;
    property ShowProgress: boolean read UseProgress write UseProgress;
    property ShowPrintDialog: boolean read ShowDialog write ShowDialog;
    property Orientation: TPrinterOrientation read PageOrientation write PageOrientation;
    property ShowTotalPages: boolean read GetShowTotalPages write SetShowTotalPages;
    property PrintPageNumbers: boolean read PageNumbering write PageNumbering;
    property ProgressBarMax: word read ProgressMax write ProgressMax;
    property ProgressBarInc: word read ProgressInc write ProgressInc;
    property Transparent: boolean read PrintTransparent write PrintTransparent;
    property StartPercent: Percentages read PreviewPercent write PreviewPercent;
    property PaperSize: PaperSizes read PaperDimension write PaperDimension;
    property ShowCancelBtn: boolean read ShowCancel write ShowCancel;
    property Measurement: MeasureType read Measure write Measure;
    property ProgressFormColor: TColor read BarFormColor write BarFormColor;
    property ProgressTextColor: TColor read BarTextColor write BarTextColor;
		{Events:
      OnNewPage: event for any printing to occur for every page
      	(I use this to put a bitmap on every page like a company logo)
      AfterNewPage: event to print after the page has been advanced
      	(I use this for things to occur on all but the first page like
        	a continuation header or something)
      OnCancel: event to execute in the case that the cancel button is
      					displayed and the user clicks it
    }
    property OnNewPage: TNotifyEvent read FPageChange write FPageChange;
    property AfterNewPage: TNotifyEvent read FAPageChange write FAPageChange;
    property OnCancel: TNotifyEvent read FOnCancelPrint write FOnCancelPrint;
    property BeforePrint: TNotifyEvent read FStartPrint write FStartPrint;
    property AfterPrint: TNotifyEvent read FEndPrint write FEndPrint;
    property OnLastPage: TNotifyEvent read FLastPage write FLastPage;
    property OnFirstPage: TNotifyEvent read FFirstPage write FFirstPage;
	end;

  { used to store the actual paper sizes in inches for quick retrieval }
  PrnSizeArray = array [1..38] of PrnPaperRec;

procedure Register;

implementation

{$R PRINTDRV.RES}

const
	PrinterSizes: PrnSizeArray =
  	((pType:1;Width:8.5;Height:11.0),(pType:2;Width:8.5;Height:11.0),
     (pType:3;Width:11.0;Height:17.0),(pType:4;Width:17.0;Height:11.0),
     (pType:5;Width:8.5;Height:14.0),(pType:6;Width:5.5;Height:8.5),
     (pType:7;Width:7.5;Height:10.5),(pType:8;Width:11.7;Height:16.5),
     (pType:9;Width:8.3;Height:11.7),(pType:10;Width:0.0;Height:0.0),
     (pType:11;Width:5.9;Height:8.3),
     (pType:12;Width:9.9;Height:14.0),(pType:13;Width:7.2;Height:10.1),
     (pType:14;Width:8.5;Height:13.0),(pType:15;Width:8.5;Height:10.8),
     (pType:16;Width:10.0;Height:14.0),(pType:17;Width:11.0;Height:17.0),
     (pType:18;Width:8.5;Height:11.0),(pType:19;Width:3.875;Height:8.9),
     (pType:20;Width:4.1;Height:9.5),(pType:21;Width:4.5;Height:10.4),
     (pType:22;Width:4.1;Height:9.5),(pType:23;Width:5.0;Height:11.5),
     (pType:24;Width:0.0;Height:0.0),(pType:25;Width:0.0;Height:0.0),
     (pType:26;Width:0.0;Height:0.0),
     (pType:27;Width:4.3;Height:8.7),(pType:29;Width:12.8;Height:18.0),
     (pType:30;Width:9.0;Height:12.0),(pType:28;Width:6.4;Height:9.0),
     (pType:31;Width:4.5;Height:6.4),(pType:32;Width:4.5;Height:9.0),
     (pType:33;Width:9.8;Height:14.0),(pType:34;Width:7.0;Height:9.8),
     (pType:35;Width:7.0;Height:5.0),(pType:36;Width:4.3;Height:9.1),
     (pType:37;Width:3.9;Height:7.5),(pType:38;Width:3.6;Height:6.5));

var
	PointArray: array [0..99] of TPoint;

constructor TMWPrintObject.Create(AOwner: TComponent);
{Create TMWPrintObject and set default values}
var
	x: integer;

begin
	inherited Create(AOwner);
  for x := 1 to HeaderLines do
  begin
  	CurrentFonts[x].Font := nil;
    Header[x].Font := nil;
    Footer[x].Font := nil;
  end;
  PageNumber.Font := nil;
  PreviewMode := true;
  ActualPreview := false;
  ScaleByValue := 1.0;
  DocumentTitle := '';
  AutomaticPaging := false;
  ShowProgress := true;
  ShowDialog := true;
  ShowCancel := false;
  ProgressMax := 100;
  ProgressInc := 1;
  ProgressFormColor := clInfoBk;
  PageNumbering := false;
  PrintTransparent := false;
  PageNumber.ShowTotalPages := true;
  PreviewPercent := P6_Full;
  CurrentFontRecord := 0;
  CurrentYRecord := 0;
  PrintingInternal := false;
  Measure := mtInches;
  FPageChange := nil;
  FAPageChange := nil;
  FOnCancelPrint := nil;
  FStartPrint := nil;
  FEndPrint := nil;
  FFirstPage := nil;
  FLastPage := nil;
  ImageCanvas := nil;
  ImagePrinting := false;
  PrintingOK := false;
  IsColor := false;
  IsPrinting := false;
  if Not (csDesigning in ComponentState) then
  	Printer.PrinterIndex := -1;
end;

destructor TMWPrintObject.Destroy;
{ Destroy TMWPrintObject and call TComponent destructor}
{ If printing was performed, the other objects created for it
	should have already been destroyed after the print job.}
begin
	FPageChange := nil;
  FAPageChange := nil;
  FOnCancelPrint := nil;
  FStartPrint := nil;
  FEndPrint := nil;
  FFirstPage := nil;
  FLastPage := nil;
  inherited Destroy;
end;

procedure TMWPrintObject.Abort;
{Used to abort the print job in progress}
begin
	if ImagePrinting then
  begin
  	PrinterCanvas := nil;
  	PrintingOK := false;
    exit;
  end;
  Cleanup;
	if PreviewMode then
   	PreviewForm.Abort
  else
  	if not ImagePrinting then
   		Printer.EndDoc;
  if not ImagePrinting and BarShowing then
  begin
    ProgressBar.Close;
    ProgressBar.Destroy;
  end;
  Pages.Destroy;
  PrintingOK := false;
  ImagePrinting := false;
  WritePrinterSpecs(true);
end;

procedure TMWPrintObject.AfterPageChange;
begin
	if assigned(FAPageChange) then FAPageChange(self);
end;

procedure TMWPrintObject.Arc(X1,Y1,X2,Y2,X3,Y3,X4,Y4: single);
var
	ScreenToPrinter: single;

begin
  if DryRun or ImagePrinting then
  case Measure of
  	mtInches:
    	begin
      	X1 := InchesToPixelsHorizontal(X1); Y1 := InchesToPixelsVertical(Y1);
      	X2 := InchesToPixelsHorizontal(X2); Y2 := InchesToPixelsVertical(Y2);
      	X3 := InchesToPixelsHorizontal(X3); Y3 := InchesToPixelsVertical(Y3);
      	X4 := InchesToPixelsHorizontal(X4); Y4 := InchesToPixelsVertical(Y4);
      end;
    mtMM:
    	begin
      	X1 := InchesToPixelsHorizontal(MMToInches(X1)); Y1 := InchesToPixelsVertical(MMToInches(Y1));
      	X2 := InchesToPixelsHorizontal(MMToInches(X2)); Y2 := InchesToPixelsVertical(MMToInches(Y2));
      	X3 := InchesToPixelsHorizontal(MMToInches(X3)); Y3 := InchesToPixelsVertical(MMToInches(Y3));
      	X4 := InchesToPixelsHorizontal(MMToInches(X4)); Y4 := InchesToPixelsVertical(MMToInches(Y4));
      end;
  end;
	if DryRun then
  	Pages.StoreArc(X1,Y1,X2,Y2,X3,Y3,X4,Y4);
  if PixelsPerInchHorizontal > PixelsPerInchVertical then
  	ScreenToPrinter := PixelsPerInchHorizontal / Screen.PixelsPerInch
  else
  	ScreenToPrinter := PixelsPerInchVertical / Screen.PixelsPerInch;
	TheCanvas.Arc(Trunc(X1*ScreenToPrinter*ScaleByValue)-GutterLeft,
  							Trunc(Y1*ScreenToPrinter*ScaleByValue)-GutterTop,
  							Trunc(X2*ScreenToPrinter*ScaleByValue)-GutterLeft,
                Trunc(Y2*ScreenToPrinter*ScaleByValue)-GutterTop,
  							Trunc(X3*ScreenToPrinter*ScaleByValue)-GutterLeft,
                Trunc(Y3*ScreenToPrinter*ScaleByValue)-GutterTop,
                Trunc(X4*ScreenToPrinter*ScaleByValue)-GutterLeft,
                Trunc(Y4*ScreenToPrinter*ScaleByValue)-GutterTop);
end;

procedure TMWPrintObject.BltTBitmapAsDib(DestDc : hdc;   {Handle of where to blt}
                          x,       				{Bit at x}
                          y,       				{Blt at y}
                          Width,   				{Width to stretch}
                          Height: integer;{Height to stretch}
                          bm : TBitmap);  {the TBitmap to Blt}
var
  OriginalWidth :LongInt;               {width of BM}
  dc : hdc;                             {screen dc}
  IsPaletteDevice : bool;               {if the device uses palettes}
  IsDestPaletteDevice : bool;           {if the device uses palettes}
  BitmapInfoSize : integer;             {sizeof the bitmapinfoheader}
  lpBitmapInfo : PBitmapInfo;           {the bitmap info header}
  hBm : hBitmap;                        {handle to the bitmap}
  hPal : hPalette;                      {handle to the palette}
  OldPal : hPalette;                    {temp palette}
  hBits : THandle;                      {handle to the DIB bits}
  pBits : pointer;                      {pointer to the DIB bits}
  lPPalEntriesArray : PPalEntriesArray; {palette entry array}
  NumPalEntries : integer;              {number of palette entries}
  i : integer;                          {looping variable}
begin
{If range checking is on - lets turn it off for now}
{we will remember if range checking was on by defining}
{a define called CKRANGE if range checking is on.}
{We do this to access array members past the arrays}
{defined index range without causing a range check}
{error at runtime. To satisfy the compiler, we must}
{also access the indexes with a variable. ie: if we}
{have an array defined as a: array[0..0] of byte,}
{and an integer i, we can now access a[3] by setting}
{i := 3; and then accessing a[i] without error}
{$IFOPT R+}
  {$DEFINE CKRANGE}
  {$R-}
{$ENDIF}

 {Save the original width of the bitmap}
  OriginalWidth := bm.Width;

 {Get the screen's dc to use since memory dc's are not reliable}
  dc := GetDc(0);
 {Are we a palette device?}
  IsPaletteDevice :=
    GetDeviceCaps(dc, RASTERCAPS) and RC_PALETTE = RC_PALETTE;
 {Give back the screen dc}
  {dc := }ReleaseDc(0, dc);

 {Allocate the BitmapInfo structure}
  if IsPaletteDevice then
    BitmapInfoSize := sizeof(TBitmapInfo) + (sizeof(TRGBQUAD) * 255)
  else
    BitmapInfoSize := sizeof(TBitmapInfo);
  GetMem(lpBitmapInfo, BitmapInfoSize);

 {Zero out the BitmapInfo structure}
  FillChar(lpBitmapInfo^, BitmapInfoSize, #0);

 {Fill in the BitmapInfo structure}
  lpBitmapInfo^.bmiHeader.biSize := sizeof(TBitmapInfoHeader);
  lpBitmapInfo^.bmiHeader.biWidth := OriginalWidth;
  lpBitmapInfo^.bmiHeader.biHeight := bm.Height;
  lpBitmapInfo^.bmiHeader.biPlanes := 1;
  if IsPaletteDevice then
    lpBitmapInfo^.bmiHeader.biBitCount := 8
  else
    lpBitmapInfo^.bmiHeader.biBitCount := 24;
  lpBitmapInfo^.bmiHeader.biCompression := BI_RGB;
  lpBitmapInfo^.bmiHeader.biSizeImage :=
    ((lpBitmapInfo^.bmiHeader.biWidth *
      longint(lpBitmapInfo^.bmiHeader.biBitCount)) div 8) *
      lpBitmapInfo^.bmiHeader.biHeight;
  lpBitmapInfo^.bmiHeader.biXPelsPerMeter := 0;
  lpBitmapInfo^.bmiHeader.biYPelsPerMeter := 0;
  if IsPaletteDevice then begin
    lpBitmapInfo^.bmiHeader.biClrUsed := 256;
    lpBitmapInfo^.bmiHeader.biClrImportant := 256;
  end else begin
    lpBitmapInfo^.bmiHeader.biClrUsed := 0;
    lpBitmapInfo^.bmiHeader.biClrImportant := 0;
  end;

 {Take ownership of the bitmap handle and palette}
  hBm := bm.ReleaseHandle;
  hPal := bm.ReleasePalette;

 {Get the screen's dc to use since memory dc's are not reliable}
  dc := GetDc(0);

  if IsPaletteDevice then begin
   {If we are using a palette, it must be}
   {selected into the dc during the conversion}
    OldPal := SelectPalette(dc, hPal, TRUE);
   {Realize the palette}
    RealizePalette(dc);
  end;
 {Tell GetDiBits to fill in the rest of the bitmap info structure}
  GetDiBits(dc,
            hBm,
            0,
            lpBitmapInfo^.bmiHeader.biHeight,
            nil,
            TBitmapInfo(lpBitmapInfo^),
            DIB_RGB_COLORS);

 {Allocate memory for the Bits}
  hBits := GlobalAlloc(GMEM_MOVEABLE,
                       lpBitmapInfo^.bmiHeader.biSizeImage);
  pBits := GlobalLock(hBits);
 {Get the bits}
  GetDiBits(dc,
            hBm,
            0,
            lpBitmapInfo^.bmiHeader.biHeight,
            pBits,
            TBitmapInfo(lpBitmapInfo^),
            DIB_RGB_COLORS);


  if IsPaletteDevice then begin
   {Lets fix up the color table for buggy video drivers}
    GetMem(lPPalEntriesArray, sizeof(TPaletteEntry) * 256);
   {$IFDEF VER100}
      NumPalEntries := GetPaletteEntries(hPal,
                                         0,
                                         256,
                                         lPPalEntriesArray^);
   {$ELSE}
      NumPalEntries := GetSystemPaletteEntries(dc,
                                               0,
                                               256,
                                               lPPalEntriesArray^);
   {$ENDIF}
    for i := 0 to (NumPalEntries - 1) do begin
      lpBitmapInfo^.bmiColors[i].rgbRed :=
        lPPalEntriesArray^[i].peRed;
      lpBitmapInfo^.bmiColors[i].rgbGreen :=
        lPPalEntriesArray^[i].peGreen;
      lpBitmapInfo^.bmiColors[i].rgbBlue :=
        lPPalEntriesArray^[i].peBlue;
    end;
    FreeMem(lPPalEntriesArray, sizeof(TPaletteEntry) * 256);
  end;

  if IsPaletteDevice then begin
   {Select the old palette back in}
    SelectPalette(dc, OldPal, TRUE);
   {Realize the old palette}
    RealizePalette(dc);
  end;

 {Give back the screen dc}
  {dc := }ReleaseDc(0, dc);

 {Is the Dest dc a palette device?}
  IsDestPaletteDevice :=
    GetDeviceCaps(DestDc, RASTERCAPS) and RC_PALETTE = RC_PALETTE;


  if IsPaletteDevice then begin
   {If we are using a palette, it must be}
   {selected into the dc during the conversion}
    OldPal := SelectPalette(DestDc, hPal, TRUE);
   {Realize the palette}
    RealizePalette(DestDc);
  end;

 {Do the blt}
  StretchDiBits(DestDc,
                x,
                y,
                Width,
                Height,
                0,
                0,
                OriginalWidth,
                lpBitmapInfo^.bmiHeader.biHeight,
                pBits,
                lpBitmapInfo^,
                DIB_RGB_COLORS,
                SrcCopy);

  if IsDestPaletteDevice then begin
   {Select the old palette back in}
    SelectPalette(DestDc, OldPal, TRUE);
   {Realize the old palette}
    RealizePalette(DestDc);
  end;

 {De-Allocate the Dib Bits}
  GlobalUnLock(hBits);
  GlobalFree(hBits);

 {De-Allocate the BitmapInfo}
  FreeMem(lpBitmapInfo, BitmapInfoSize);

 {Set the ownership of the bimap handles back to the bitmap}
  bm.Handle := hBm;
  bm.Palette := hPal;

  {Turn range checking back on if it was on when we started}
{$IFDEF CKRANGE}
  {$UNDEF CKRANGE}
  {$R+}
{$ENDIF}
end;

function TMWPrintObject.CalculateLineHeight: integer;
   { Calculate the height of a line plus the normal amount of space between
     each line }
begin
	Result := Trunc(TheCanvas.TextHeight('A') / ScaleByValue);
end;

procedure TMWPrintObject.CalculateMeasurements;
   { Calculate some necessary measurements.  Thanks to Robert Fabiszak
     CompuServe: 70304,2047 for the Escape() Windows API calls. }
var
	pt: TPoint;

begin
   { Call the Windows API function GetTextMetrics() to get the specifics
     of the particular font. }
	GetTextMetrics( TheCanvas.Handle,TextMetrics );

   { Calculate the number of pixels per inch vertical and horizontal.
     'GetDeviceCaps' is a Windows API call. }
  PixelsPerInchVertical := GetDeviceCaps( TheCanvas.Handle,LOGPIXELSY );
  PixelsPerInchHorizontal := GetDeviceCaps( TheCanvas.Handle,LOGPIXELSX );

   { Get the gutter on the left and top.  'Escape' is a Windows API
     call. }
  Escape( TheCanvas.Handle,GETPRINTINGOFFSET,0,Nil,@pt );
  if ImagePrinting or PreviewMode then
  begin
   	GutterLeft := 0;
    GutterTop := 0;
  end
  else
  begin
   	GutterLeft := pt.X;
   	GutterTop := pt.Y;
  end;
  Escape( TheCanvas.Handle,GETPHYSPAGESIZE,0,Nil,@pt );
   {If printing to a TImage, the size doesn't come back as expected so we get the
    size of the preview image}
  if PreviewMode then
  begin
  	pt.X := PreviewForm.GetWidth;
    pt.Y := PreviewForm.GetHeight;
  end
  else if ImagePrinting then
  begin
  	pt.X := RightMargin;
    pt.Y := BottomMargin;
  end;
  TotalPageWidthPixels := pt.X;
  TotalPageHeightPixels := pt.Y;
  TotalPageWidthInches := pt.X / PixelsPerInchHorizontal;
  TotalPageHeightInches := pt.Y / PixelsPerInchVertical;
   {Need to set these using the scaling value if in preview mode}
  if ImagePrinting or PreviewMode then
  begin
   	GutterRight := 0;
    GutterBottom := 0;
  end
  else
  begin
 		GutterRight := TotalPageWidthPixels - GutterLeft - Printer.PageWidth;
 		GutterBottom := TotalPageHeightPixels - GutterTop - Printer.PageHeight;
  end;
  if ( TopMargin < GutterTop ) then
  	TopMargin := GutterTop;
  if ( BottomMargin > TotalPageHeightPixels - GutterBottom ) then
  	BottomMargin := TotalPageHeightPixels - GutterBottom;
  if ( LeftMargin < GutterLeft ) then
  	LeftMargin := GutterLeft;
  if ( RightMargin > TotalPageWidthPixels - GutterRight ) then
  	RightMargin := TotalPageWidthPixels - GutterRight;
end;

procedure TMWPrintObject.Cleanup;
var
	x: integer;

begin
	for x := 1 to HeaderLines do
  begin
  	Header[x].Text := '';
    Header[x].Font.Free;
    Header[x].Font := nil;
  end;
  for x := 1 to FooterLines do
  begin
  	Footer[x].Text := '';
    Footer[x].Font.Free;
    Footer[x].Font := nil;
  end;
  for x := 1 to Columns do
  begin
  	ColumnInformation[x].XPosition := 0.0;
    ColumnInformation[x].Length := 0.0;
  end;
  PageNumber.Text := '';
  PageNumber.Font.Free;
  PageNumber.Font := nil;
  SetTab(0.0);
end;

{ The ClearCanvas and ClearCanvasArea are only used for drawing/printing to
	an image or canvas other than the printer. }
procedure TMWPrintObject.ClearCanvas(iColor: TColor);
var
	oldColor: TColor;

begin
	if not ImagePrinting then
  	exit;
  oldColor := TheCanvas.Brush.Color;
  TheCanvas.Brush.Color := iColor;
	TheCanvas.FillRect(rect(0,0,RightMargin,BottomMargin));
  TheCanvas.Brush.Color := oldColor;
end;

procedure TMWPrintObject.ClearCanvasArea(XTop,YTop,XBottom,YBottom: integer; iColor: TColor);
var
	oldColor: TColor;

begin
	if not ImagePrinting then
  	exit;
  case Measure of
  	mtInches:
    	begin
      	XTop := InchesToPixelsHorizontal(XTop); YTop := InchesToPixelsVertical(YTop);
      	XBottom := InchesToPixelsHorizontal(XBottom); YBottom := InchesToPixelsVertical(YBottom);
      end;
    mtMM:
    	begin
      	XTop := InchesToPixelsHorizontal(MMToInches(XTop));
        YTop := InchesToPixelsVertical(MMToInches(YTop));
      	XBottom := InchesToPixelsHorizontal(MMToInches(XBottom));
        YBottom := InchesToPixelsVertical(MMToInches(YBottom));
      end;
  end;
  oldColor := TheCanvas.Brush.Color;
  TheCanvas.Brush.Color := iColor;
	TheCanvas.FillRect(rect(XTop,YTop,XBottom,YBottom));
  TheCanvas.Brush.Color := oldColor;
end;

procedure TMWPrintObject.CreateColumn( Number:word; XPosition:single; Length:single );
{Stores the column information. There is a maximum of 20 columns}
begin
	if Not PrintingOK then
  	exit;
	if (Number > Columns) or (Number < 1) then
  begin
  	ShowMessage('Column value must be between 1 and ' + IntToStr(Columns) + '.');
    exit;
  end;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels:
      	begin
        	XPosition := PixelsToInchesHorizontal(Trunc(XPosition));
          Length := PixelsToInchesHorizontal(Trunc(Length));
        end;
      mtMM:
      	begin
        	XPosition := MMToInches(XPosition);
          Length := MMToInches(Length);
        end;
    end;
	ColumnInformation[Number].XPosition := XPosition;
  ColumnInformation[Number].Length := Length;
	if DryRun then
  	Pages.StoreColumn(Number,XPosition,Length);
end;

function TMWPrintObject.CurrentFont: TFont;
begin
	result := TheCanvas.Font;
end;

function TMWPrintObject.CurrentFontName: string;
begin
	result := TheCanvas.Font.Name;
end;

function TMWPrintObject.CurrentFontSize: word;
begin
	result := TheCanvas.Font.Size;
end;

function TMWPrintObject.CurrentFontStyle: TFontStyles;
begin
	result := TheCanvas.Font.Style;
end;

function TMWPrintObject.CurrentPageNumber: integer;
begin
	if PreviewMode then
  	result := PreviewForm.GetPageNumber
  else
  	result := Printer.PageNumber;
end;

procedure TMWPrintObject.DrawBox( XTop,YTop,XBottom,YBottom:single;
																LineWidth:word );
   { Draw a box at the X,Y coordinates passed in the parameters.
   	 The box is drawn using Line commands because certain printers
     such as HP Laserjets tend to fill the block overwriting
     any text inside a printed box. }
var
  oldWidth: integer;
  oldColor: TColor;

begin
	if Not PrintingOK then
  	exit;
  oldWidth := TheCanvas.Pen.Width;
  oldColor := TheCanvas.Brush.Color;
  SetBrushColor(RGB(0,0,0));
  SetPenWidth(LineWidth);
  FrameRect(XTop,YTop,XBottom,YBottom);
	SetPenWidth(oldWidth);
  SetBrushColor(oldColor);
end;

procedure TMWPrintObject.DrawBoxShaded( XTop,YTop,XBottom,YBottom:single;
																			LineWidth:word; Shading:word );
   { Draw a box at the X,Y coordinates passed in the parameters }
var
  {oldX,oldY,}oldWidth: integer;
  oldBColor: TColor;

begin
	if Not PrintingOK then
  	exit;
  oldWidth := TheCanvas.Pen.Width;
  oldBColor := TheCanvas.Brush.Color;
	SetPenWidth(LineWidth);
  SetBrushColor(RGB(Byte(Shading),Byte(Shading),Byte(Shading)));
  FillRect(XTop,YTop,XBottom,YBottom);
  SetBrushColor(RGB(0,0,0));
  FrameRect(XTop,YTop,XBottom,YBottom);
  SetPenWidth(oldWidth);
  SetBrushColor(oldBColor);
end;

procedure TMWPrintObject.DrawBoxShade( XTop,YTop,XBottom,YBottom:single;
																			LineWidth:word; Shading:TColor );
   { Draw a box at the X,Y coordinates passed in the parameters }
var
  {oldX,oldY,}oldWidth: integer;
  oldBColor: TColor;

begin
	if Not PrintingOK then
  	exit;
  oldWidth := TheCanvas.Pen.Width;
  oldBColor := TheCanvas.Brush.Color;
	SetPenWidth(LineWidth);
  SetBrushColor(Shading);
  FillRect(XTop,YTop,XBottom,YBottom);
  SetBrushColor(RGB(0,0,0));
  FrameRect(XTop,YTop,XBottom,YBottom);
  SetPenWidth(oldWidth);
  SetBrushColor(oldBColor);
end;

procedure TMWPrintObject.DrawLine( TopX,TopY,BottomX,BottomY:single; LineWidth:word );
   { Draw a line beginning at a particular X,Y coordinate and ending at a
     particular X,Y coordinate. }
var
	TopXPixels, BottomXPixels, TopYPixels, BottomYPixels: integer;
  oldWidth: integer;

begin
	if Not PrintingOK then
  	exit;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels:
      	begin
        	TopX := PixelsToInchesHorizontal(Trunc(TopX));
          TopY := PixelsToInchesVertical(Trunc(TopY));
          BottomX := PixelsToInchesHorizontal(Trunc(BottomX));
          BottomY := PixelsToInchesVertical(Trunc(BottomY));
        end;
      mtMM:
      	begin
        	TopX := MMToInches(TopX);
          TopY := MMToInches(TopY);
          BottomX := MMToInches(BottomX);
          BottomY := MMToInches(BottomY);
        end;
    end;
	if DryRun then
  	Pages.StoreLine(TopX,TopY,BottomX,BottomY,LineWidth);
	TopXPixels := InchesToPixelsHorizontal( TopX );
  BottomXPixels := InchesToPixelsHorizontal( BottomX);

  TopYPixels := InchesToPixelsVertical( TopY );
  BottomYPixels := InchesToPixelsVertical( BottomY );
 	Dec( TopXPixels,GutterLeft );
 	Dec( BottomXPixels,GutterLeft );
 	Dec( TopYPixels,GutterTop );
 	Dec( BottomYPixels,GutterTop );
  oldWidth := TheCanvas.Pen.Width;
  if ImagePrinting then
  	TheCanvas.Pen.Width := LineWidth
  else
		TheCanvas.Pen.Width := Trunc(((LineWidth * TotalPageWidthPixels) /
    																Printer.PageWidth) * ScaleByValue);
  TheCanvas.MoveTo( TopXPixels,TopYPixels );
	TheCanvas.LineTo( BottomXPixels,BottomYPixels );
  TheCanvas.Pen.Width := oldWidth;
end;

procedure TMWPrintObject.DrawTextBox( XTop,YTop,XBottom,YBottom:single;
																		LineWidth:word; Shading:word; Text: string;
                                    Column: integer; Alignment: word );
{Routine to draw a shaded box with text printed inside. Added this to make it easier
 than drawing the box and then writing the text.}
var
  ColorTmp: TColor;
  WidthTmp: integer;
  {YposTmp: single;}

begin
	if Not PrintingOK then
  	exit;
  WidthTmp := TheCanvas.Pen.Width;
  ColorTmp := TheCanvas.Brush.Color;
  SetPenWidth(LineWidth);
  SetBrushColor(RGB(Byte(Shading),Byte(Shading),Byte(Shading)));
  FillRect(XTop,YTop,XBottom,YBottom);
  SetPenWidth(WidthTmp);
  SetBrushColor(RGB(0,0,0));
  FrameRect(XTop,YTop,XBottom,YBottom);
  SetBrushColor(ColorTmp);
  case Alignment of
  	0: WriteLineColumn(Column,-2,Text);
   	1: WriteLineColumnCenter(Column,-2,Text);
   	2: WriteLineColumnRight(Column,-2,Text);
  end;
end;

procedure TMWPrintObject.TextColumnBox( XTop,YTop,XBottom,YBottom:single;
																		LineWidth:word; Shading:TColor; Text: string;
                                    Column: integer; Alignment: word );
{Routine to draw a shaded box with text printed inside. Added this to make it easier
 than drawing the box and then writing the text.}
var
  ColorTmp: TColor;
  WidthTmp: integer;

begin
	if Not PrintingOK then
  	exit;
  WidthTmp := TheCanvas.Pen.Width;
  ColorTmp := TheCanvas.Brush.Color;
  SetPenWidth(LineWidth);
  SetBrushColor(Shading);
  FillRect(XTop,YTop,XBottom,YBottom);
  SetPenWidth(WidthTmp);
  SetBrushColor(RGB(0,0,0));
  FrameRect(XTop,YTop,XBottom,YBottom);
  SetBrushColor(ColorTmp);
  case Alignment of
  	0: WriteLineColumn(Column,-2,Text);
   	1: WriteLineColumnCenter(Column,-2,Text);
   	2: WriteLineColumnRight(Column,-2,Text);
  end;
end;

procedure TMWPrintObject.Ellipse(X1,Y1,X2,Y2: single);
var
	ScreenToPrinter: single;

begin
	if DryRun or ImagePrinting then
  case Measure of
  	mtInches:
    	begin
      	X1 := InchesToPixelsHorizontal(X1); Y1 := InchesToPixelsVertical(Y1);
      	X2 := InchesToPixelsHorizontal(X2); Y2 := InchesToPixelsVertical(Y2);
      end;
    mtMM:
    	begin
      	X1 := InchesToPixelsHorizontal(MMToInches(X1)); Y1 := InchesToPixelsVertical(MMToInches(Y1));
      	X2 := InchesToPixelsHorizontal(MMToInches(X2)); Y2 := InchesToPixelsVertical(MMToInches(Y2));
      end;
  end;
	if DryRun then
  	Pages.StoreEllipse(X1,Y1,X2,Y2);
  if PixelsPerInchHorizontal > PixelsPerInchVertical then
  	ScreenToPrinter := PixelsPerInchHorizontal / Screen.PixelsPerInch
  else
  	ScreenToPrinter := PixelsPerInchVertical / Screen.PixelsPerInch;
	TheCanvas.Ellipse(Trunc(X1*ScreenToPrinter*ScaleByValue)-GutterLeft,
  									Trunc(Y1*ScreenToPrinter*ScaleByValue)-GutterTop,
  									Trunc(X2*ScreenToPrinter*ScaleByValue)-GutterLeft,
                    Trunc(Y2*ScreenToPrinter*ScaleByValue)-GutterTop);
end;

procedure TMWPrintObject.FillRect(X1, Y1, X2, Y2: single);
var
	ScreenToPrinter: single;

begin
	if DryRun or ImagePrinting then
  	case Measure of
    	mtInches:
      	begin
        	X1 := InchesToPixelsHorizontal(X1); Y1 := InchesToPixelsVertical(Y1);
          X2 := InchesToPixelsHorizontal(X2); Y2 := InchesToPixelsVertical(Y2);
        end;
      mtMM:
      	begin
        	X1 := MMToPixelsHorizontal(X1); Y1 := MMToPixelsVertical(Y1);
          X2 := MMToPixelsHorizontal(X2); Y2 := MMToPixelsVertical(Y2);
        end;
    end;
	if DryRun then
    Pages.StoreFillRect(X1,Y1,X2,Y2);
  if PixelsPerInchHorizontal > PixelsPerInchVertical then
  	ScreenToPrinter := PixelsPerInchHorizontal / Screen.PixelsPerInch
  else
  	ScreenToPrinter := PixelsPerInchVertical / Screen.PixelsPerInch;
  TheCanvas.FillRect(Rect(Trunc(X1*ScreenToPrinter*ScaleByValue)-GutterLeft,
  												Trunc(Y1*ScreenToPrinter*ScaleByValue)-GutterTop,
                          Trunc(X2*ScreenToPrinter*ScaleByValue)-GutterLeft,
                          Trunc(Y2*ScreenToPrinter*ScaleByValue)-GutterTop));
end;

procedure TMWPrintObject.FloodFill(X,Y: single;Color: TColor;FillStyle: TFillStyle);
var
	ScreenToPrinter: single;

begin
	if DryRun or ImagePrinting then
  	case Measure of
    	mtInches:
      	begin
        	X := InchesToPixelsHorizontal(X); Y := InchesToPixelsVertical(Y);
        end;
      mtMM:
      	begin
        	X := MMToPixelsHorizontal(X); Y := MMToPixelsVertical(Y);
        end;
    end;
	if DryRun then
  	Pages.StoreFloodFill(X,Y,Color,FillStyle);
  if PixelsPerInchHorizontal > PixelsPerInchVertical then
  	ScreenToPrinter := PixelsPerInchHorizontal / Screen.PixelsPerInch
  else
  	ScreenToPrinter := PixelsPerInchVertical / Screen.PixelsPerInch;
  TheCanvas.FloodFill(Trunc(X*ScreenToPrinter*ScaleByValue)-GutterLeft,
  										Trunc(Y*ScreenToPrinter*ScaleByValue)-GutterTop,Color,FillStyle);
end;

procedure TMWPrintObject.FrameRect(X1, Y1, X2, Y2: single);
var
	ScreenToPrinter: single;

begin
	if DryRun or ImagePrinting then
  	case Measure of
    	mtInches:
      	begin
        	X1 := InchesToPixelsHorizontal(X1); Y1 := InchesToPixelsVertical(Y1);
          X2 := InchesToPixelsHorizontal(X2); Y2 := InchesToPixelsVertical(Y2);
        end;
      mtMM:
      	begin
        	X1 := MMToPixelsHorizontal(X1); Y1 := MMToPixelsVertical(Y1);
          X2 := MMToPixelsHorizontal(X2); Y2 := MMToPixelsVertical(Y2);
        end;
    end;
	if DryRun then
    Pages.StoreFrameRect(X1,Y1,X2,Y2);
  if PixelsPerInchHorizontal > PixelsPerInchVertical then
  	ScreenToPrinter := PixelsPerInchHorizontal / Screen.PixelsPerInch
  else
  	ScreenToPrinter := PixelsPerInchVertical / Screen.PixelsPerInch;
  TheCanvas.FrameRect(Rect(Trunc(X1*ScreenToPrinter*ScaleByValue)-GutterLeft,
  												Trunc(Y1*ScreenToPrinter*ScaleByValue)-GutterTop,
                          Trunc(X2*ScreenToPrinter*ScaleByValue)-GutterLeft,
                          Trunc(Y2*ScreenToPrinter*ScaleByValue)-GutterTop));
end;

function TMWPrintObject.GetBrushColor: TColor;
begin
	result := TheCanvas.Brush.Color;
end;

function TMWPrintObject.GetBrushStyle: TBrushStyle;
begin
	result := TheCanvas.Brush.Style;
end;

function TMWPrintObject.GetColumnLeft( Number:word): single;
{Function to return the left X coordinate of the desired column.}
begin
	Result := ColumnInformation[Number].XPosition;
end;

function TMWPrintObject.GetColumnRight( Number:word): single;
{Function to return the Right X coordinate of the desired column.}
begin
	Result := ColumnInformation[Number].XPosition + ColumnInformation[Number].Length;
end;

function TMWPrintObject.GetColumnsPerLine: integer;
   { How many columns are there in a Line? }
var
	Pixels: integer;

begin
	Pixels := TotalPageWidthPixels - GutterLeft - GutterRight;
  Result := Pixels div TheCanvas.TextWidth( 'B' );
end;

function TMWPrintObject.GetFontColor: TColor;
begin
	result := TheCanvas.Font.Color;
end;

procedure TMWPrintObject.GetGutter( var Top:word; var Bottom:word; var Left:word;
            											var Right:word );
{ Returns the gutter (non-printable) setting of the page }
begin
	Top := GutterTop;
  Bottom := GutterBottom;
  Left := GutterLeft;
  Right := GutterRight;
end;

function TMWPrintObject.GetLineHeightMM: single;
begin
	result := PixelsToMMVertical( GetLineHeightPixels );
end;

function TMWPrintObject.GetLineHeightInches: single;
{ Returns the height of current line in inches }
begin
	Result := PixelsToInchesVertical( GetLineHeightPixels );
end;

function TMWPrintObject.GetLineHeightPixels: word;
{ Returns the height of current line in pixels }
begin
	Result := CalculateLineHeight;
end;

function TMWPrintObject.GetLinesInDetailArea: word;
   { Return the number of lines in the detail area }
begin
  Result := InchesToPixelsVertical( DetailBottom - DetailTop ) div CalculateLineHeight;
end;

function TMWPrintObject.GetLinesLeft: word;
   { Return the number of lines left in the detail area }
var
	Lines: single;

begin
	if LastYPosition > DetailBottom then
  	Lines := 0
  else
		Lines := (DetailBottom - LastYPosition) / GetLineHeightInches;
  Result := Trunc(Lines);
end;

function TMWPrintObject.GetLinesPerPage: integer;
   { Return the number of lines on the entire page }
begin
	Result := (TotalPageHeightPixels - GutterTop - GutterBottom) div CalculateLineHeight;
end;

function TMWPrintObject.GetLineWidth: word;
{ Returns the current drawing width of the pen }
begin
	Result := TheCanvas.Pen.Width;
end;

function TMWPrintObject.GetPageNumber;
   { Return the current page number }
begin
	if ImagePrinting or Not PrintingOK then
  begin
  	result := -1;
  	exit;
  end;
	if PreviewMode then
   	Result := PreviewForm.GetPageNumber
  else
   	Result := Printer.PageNumber;
end;

function TMWPrintObject.GetPenColor: TColor;
begin
	result := TheCanvas.Pen.Color;
end;

function TMWPrintObject.GetPenMode: TPenMode;
begin
	result := TheCanvas.Pen.Mode;
end;

function TMWPrintObject.GetPenStyle: TPenStyle;
begin
	result := TheCanvas.Pen.Style;
end;

function TMWPrintObject.GetPenWidth: integer;
begin
	result := TheCanvas.Pen.Width;
end;

procedure TMWPrintObject.GetPixelsPerMM( var X: word; var Y: word );
begin
	X := Trunc(PixelsPerInchHorizontal / 25.4);
  Y := Trunc(PixelsPerInchVertical / 25.4);
end;

procedure TMWPrintObject.GetPixelsPerInch( var X:word; var Y:word );
{ Returns the current pixels per inch of the canvas }
begin
	X := PixelsPerInchHorizontal;
  Y := PixelsPerInchVertical;
end;

procedure TMWPrintObject.GetPixelsPerPage( var X:word; var Y:word );
{ Returns the number of pixels across the printable area of the page }
begin
	X := TotalPageWidthPixels - GutterLeft - GutterRight;
  Y := TotalPageHeightPixels - GutterTop - GutterBottom;
end;

function TMWPrintObject.GetScale: single;
{Returns to current scale multiplier}
begin
	result := ScaleByValue;
end;

function TMWPrintObject.GetShowTotalPages: boolean;
{ Function to return the setting of showing total page numbers }
begin
	result := PageNumber.ShowTotalPages;
end;

function TMWPrintObject.GetTextWidth( Text:string ): integer;
   { Return the width of the text contained in 'Text' in pixels }
begin
	Result := Trunc(TheCanvas.TextWidth( Text ) / ScaleByValue);
end;

function TMWPrintObject.GetTextWidthInches( Text:string ): single;
   { Return the width of the text contained in 'Text' in inches }
begin
	Result := PixelsToInchesHorizontal(GetTextWidth( Text ));
end;

function TMWPrintObject.GetTextWidthMM( Text: string ): single;
begin
	result := PixelsToMMHorizontal(GetTextWidth( Text ));
end;

function TMWPrintObject.GetYPosition: single;
{ Returns the current vertical position of pen on the canvas }
begin
	case Measure of
  	mtInches: result := LastYPosition;
    mtPixels: result := InchesToPixelsVertical(LastYPosition);
    mtMM: result := InchesToMM(LastYPosition);
  else
  	result := 0.0;
  end;
end;

procedure TMWPrintObject.IncBar(x: integer);
{ Increments the progress bar value by X }
begin
	if Not PrintingOK then
  	exit;
	if UseProgress then
		ProgressBar.IncBar(x);
end;

function TMWPrintObject.MMToPixelsHorizontal( MM: single): integer;
begin
	result := InchesToPixelsHorizontal(MMToInches(MM));
end;

function TMWPrintObject.MMToPixelsVertical( MM: single): integer;
begin
	result := InchesToPixelsVertical(MMToInches(MM));
end;

function TMWPrintObject.InchesToPixelsHorizontal( Inches: single ): integer;
   { Convert the horizontal inches represented in 'Inches' to pixels }
var
	Value: single;

begin
	Value := Inches * PixelsPerInchHorizontal * ScaleByValue;
  Result := Trunc(Value);
end;

function TMWPrintObject.InchesToPixelsVertical( Inches: single ): integer;
   { Convert the vertical inches represented in 'Inches' to pixels }
var
	Value: single;

begin
	Value := Inches * PixelsPerInchVertical * ScaleByValue;
  Result := Trunc(Value);
end;

procedure TMWPrintObject.Increment;
{ Increment the progress bar with the value of ProgressInc }
begin
	if Not PrintingOK then
  	exit;
	if UseProgress then
  	ProgressBar.IncBar(ProgressInc);
end;

function TMWPrintObject.LinesToPixels( Line:integer ): integer;
   { Calculate the number of vertical pixels in 'Line' }
begin
	if ( Line <= 0 ) then
  	Line := 1;
  Result := (Line-1) * CalculateLineHeight;
end;

procedure TMWPrintObject.LineTo(X1,Y1: single);
var
	ScreenToPrinter: single;

begin
	if DryRun or ImagePrinting then
  case Measure of
  	mtInches:
    	begin
      	X1 := InchesToPixelsHorizontal(X1); Y1 := InchesToPixelsVertical(Y1);
      end;
    mtMM:
    	begin
      	X1 := InchesToPixelsHorizontal(MMToInches(X1)); Y1 := InchesToPixelsVertical(MMToInches(Y1));
      end;
  end;
	if DryRun then
		Pages.StoreLineTo(X1,Y1);
  if PixelsPerInchHorizontal > PixelsPerInchVertical then
  	ScreenToPrinter := PixelsPerInchHorizontal / Screen.PixelsPerInch
  else
  	ScreenToPrinter := PixelsPerInchVertical / Screen.PixelsPerInch;
	TheCanvas.LineTo(Trunc(X1*ScreenToPrinter*ScaleByValue)-GutterLeft,
  								 Trunc(Y1*ScreenToPrinter*ScaleByValue)-GutterTop);
end;

procedure TMWPrintObject.MoveTo(X1,Y1: single);
var
	ScreenToPrinter: single;

begin
	if DryRun or ImagePrinting then
  case Measure of
  	mtInches:
    	begin
      	X1 := InchesToPixelsHorizontal(X1); Y1 := InchesToPixelsVertical(Y1);
      end;
    mtMM:
    	begin
      	X1 := InchesToPixelsHorizontal(MMToInches(X1)); Y1 := InchesToPixelsVertical(MMToInches(Y1));
      end;
  end;
	if DryRun then
		Pages.StoreMoveTo(X1,Y1);
  if PixelsPerInchHorizontal > PixelsPerInchVertical then
  	ScreenToPrinter := PixelsPerInchHorizontal / Screen.PixelsPerInch
  else
  	ScreenToPrinter := PixelsPerInchVertical / Screen.PixelsPerInch;
	TheCanvas.MoveTo(Trunc(X1*ScreenToPrinter*ScaleByValue)-GutterLeft,
  								 Trunc(Y1*ScreenToPrinter*ScaleByValue)-GutterTop);
end;

procedure TMWPrintObject.NewLines( Number:word );
   { Generate the number of line feeds represented in 'Number' }
var
	I: word;

begin
	if Not PrintingOK then
  	exit;
	for I := 1 to Number do
	begin
  	NextLine;
    if (abs(LastYPosition - DetailTop) < 0.001) then
    	break;
  end;
end;

procedure TMWPrintObject.NewPage;
   { Issue a new page }
var
	oldAuto: boolean;

begin
	if ImagePrinting or Not PrintingOK then
  	exit;
  SaveCurrentFont;
	WriteHeader;
  WriteFooter;
  WritePageNumber;
	oldAuto := AutomaticPaging;
	SetAutoPaging(false);
  OnPageChange;
  SetAutoPaging(oldAuto);
  if DryRun then
  begin
  	Pages.NewPage;
//    SetFontInfo(CurrentFont);
    inc(TotalPages);
  	LastYPosition := DetailTop - GetLineHeightInches;
  	LastXPosition := LeftMargin;
  end
  else if not PreviewMode then
  begin
  	Printer.NewPage;
  	LastYPosition := DetailTop - GetLineHeightInches;
  	LastXPosition := LeftMargin;
  end;
	oldAuto := AutomaticPaging;
	SetAutoPaging(false);
  AfterPageChange;
  SetAutoPaging(oldAuto);
  SetTopOfPage;
  RestoreCurrentFont;
end;

procedure TMWPrintObject.NextLine;
{ Advances pen pos to next line on canvas }
begin
	if Not PrintingOK then
  	exit;
  LastYPosition := LastYPosition + GetLineHeightInches;
 	if DryRun and AutoPaging and ( LastYPosition + GetLineHeightInches > (DetailBottom / ScaleByValue)) then
   	NewPage
  else
  if DryRun then
  	Pages.StoreGeneral(commNewLine);
  LastXPosition := LeftMargin;
end;

procedure TMWPrintObject.OnCancelPrint;
begin
	ProgressBar.Hide;
	if MessageDlg('Abort printing?',mtConfirmation,[mbYes,mbNo],0) = mrYes then
  begin
  	PrintingOK := false;
		if Not PrintingInternal then
			if assigned(FOnCancelPrint) then
    		FOnCancelPrint(self);
  end;
  ProgressBar.Show;
end;

procedure TMWPrintObject.OnPageChange;
begin
	if assigned(FPageChange) then FPageChange(self);
end;

procedure TMWPrintObject.Pie(X1,Y1,X2,Y2,X3,Y3,X4,Y4: single);
var
	ScreenToPrinter: single;

begin
  if DryRun or ImagePrinting then
  case Measure of
  	mtInches:
    	begin
      	X1 := InchesToPixelsHorizontal(X1); Y1 := InchesToPixelsVertical(Y1);
      	X2 := InchesToPixelsHorizontal(X2); Y2 := InchesToPixelsVertical(Y2);
      	X3 := InchesToPixelsHorizontal(X3); Y3 := InchesToPixelsVertical(Y3);
      	X4 := InchesToPixelsHorizontal(X4); Y4 := InchesToPixelsVertical(Y4);
      end;
    mtMM:
    	begin
      	X1 := InchesToPixelsHorizontal(MMToInches(X1)); Y1 := InchesToPixelsVertical(MMToInches(Y1));
      	X2 := InchesToPixelsHorizontal(MMToInches(X2)); Y2 := InchesToPixelsVertical(MMToInches(Y2));
      	X3 := InchesToPixelsHorizontal(MMToInches(X3)); Y3 := InchesToPixelsVertical(MMToInches(Y3));
      	X4 := InchesToPixelsHorizontal(MMToInches(X4)); Y4 := InchesToPixelsVertical(MMToInches(Y4));
      end;
  end;
	if DryRun then
  	Pages.StorePie(X1,Y1,X2,Y2,X3,Y3,X4,Y4);
  if PixelsPerInchHorizontal > PixelsPerInchVertical then
  	ScreenToPrinter := PixelsPerInchHorizontal / Screen.PixelsPerInch
  else
  	ScreenToPrinter := PixelsPerInchVertical / Screen.PixelsPerInch;
	TheCanvas.Pie(Trunc(X1*ScreenToPrinter*ScaleByValue)-GutterLeft,
  							Trunc(Y1*ScreenToPrinter*ScaleByValue)-GutterTop,
  							Trunc(X2*ScreenToPrinter*ScaleByValue)-GutterLeft,
                Trunc(Y2*ScreenToPrinter*ScaleByValue)-GutterTop,
  							Trunc(X3*ScreenToPrinter*ScaleByValue)-GutterLeft,
                Trunc(Y3*ScreenToPrinter*ScaleByValue)-GutterTop,
                Trunc(X4*ScreenToPrinter*ScaleByValue)-GutterLeft,
                Trunc(Y4*ScreenToPrinter*ScaleByValue)-GutterTop);
end;

function TMWPrintObject.PixelsToMMHorizontal( Pixels: integer): single;
begin
	result := InchesToMM(PixelsToInchesHorizontal(Pixels));
end;

function TMWPrintObject.PixelsToMMVertical( Pixels: integer): single;
begin
	result := InchesToMM(PixelsToInchesVertical(Pixels));
end;

function TMWPrintObject.PixelsToInchesHorizontal( Pixels: integer ): single;
{ Converts "Pixels" to inches using horizontal resolution }
begin
	Result := Pixels / PixelsPerInchHorizontal;
end;

function TMWPrintObject.PixelsToInchesVertical( Pixels: integer ): single;
{ Converts "Pixels" to inches using vertical resolution }
begin
	Result := Pixels / PixelsPerInchVertical;
end;

procedure TMWPrintObject.PrintFromPreview;
{ Used to print the actual commands that were stored either from the preview
  form or directly when Quit is called to end the print job. }
var
	x: integer;
  xrInc, xrCurrent: single;
  oldCanvas: TCanvas;

begin
	if ImagePrinting then
  	exit;
	AutomaticPaging := false;
	WritePrinterSpecs(false);
	if ShowDialog then
		if not Pages.SetPrintOptions then
  		exit;
	PreviewMode := false;
  xrInc := 100 / ((Pages.ToPage + 1) - Pages.FromPage);
  xrCurrent := 0.0;
	if UseProgress then
  begin
  	ProgressBar := TPrintBarForm.Create(Application);
    ProgressBar.CancelBtn.Visible := true;
    PrintingInternal := true;
  	with ProgressBar do
  	begin
  		SetDisplayText(LoadStr(PRINTCAPTIONTEXT));
  		Left := Application.MainForm.Left + (Application.MainForm.Width - Width) div 3;
  		Top := Application.MainForm.Top + (Application.MainForm.Height - Height) div 3;
  		Show;
  		UpdateBar(0);
  	end;
    BarPrn := self;
    BarShowing := true;
  end;
  IsPrinting := true;
  oldCanvas := TheCanvas;
  if assigned(FStartPrint) then
  	FStartPrint(self);
  with Printer do
  begin
 		Title := DocumentTitle;
 		BeginDoc;
  end;
 	TheCanvas := Printer.Canvas;
 	CalculateMeasurements;
  if assigned(FFirstPage) then
  	FFirstPage(self);
 	for x := Pages.FromPage to Pages.ToPage do
 	begin
 		PrintPage(Pages.Get(x),x);
   	if x < Pages.ToPage then
   	begin
   		Printer.NewPage;
     	SetTopOfPage;
   	end;
   	xrCurrent := xrCurrent + xrInc;
   	if UseProgress then
   		ProgressBar.UpdateBar(Round(xrCurrent));
   	Application.ProcessMessages;
   	if Not PrintingOK then
   		break;
 	end;
  if assigned(FLastPage) then
  	FLastPage(self);
  if UseProgress then
  	ProgressBar.UpdateBar(100);
 	Printer.EndDoc;
  if assigned(FEndPrint) then
  	FEndPrint(self);
  PreviewMode := true;
  TheCanvas := oldCanvas;
  if UseProgress then
  begin
  	ProgressBar.Close;
  	ProgressBar.Destroy;
  end;
  BarShowing := false;
  ImagePrinting := false;
  IsPrinting := false;
end;

procedure TMWPrintObject.PrintGraphic(X,Y,W,H: single;thePicture: TImage);
{ Used to copy contents of TImage to printing canvas }
var
  x1,x2,y1,y2: integer;
  ScreenToPrinter: single;

begin
	if Not PrintingOK then
  	exit;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels:
      	begin
        	X := PixelsToInchesHorizontal(Trunc(X)); Y := PixelsToInchesVertical(Trunc(Y));
          W := PixelsToInchesHorizontal(Trunc(W)); H := PixelsToInchesVertical(Trunc(H));
        end;
      mtMM:
      	begin
        	X := MMToInches(X); Y := MMToInches(Y);
          W := MMToInches(W); H := MMToInches(H);
        end;
    end;
	if DryRun then
  begin
  	Pages.StoreGraphic(X,Y,W,H,thePicture);
    exit;
  end;
  if PixelsPerInchHorizontal > PixelsPerInchVertical then
  	ScreenToPrinter := PixelsPerInchHorizontal / Screen.PixelsPerInch
  else
  	ScreenToPrinter := PixelsPerInchVertical / Screen.PixelsPerInch;
  if W = -1.0 then
  	x2 := Trunc(thePicture.Width * ScreenToPrinter * ScaleByValue)
  else
  	x2 := Trunc(InchesToPixelsHorizontal(W));
  W := PixelsToInchesHorizontal(x2)/ScaleByValue;
  if X = -1.0 then
  	if TotalPageWidthPixels > InchesToPixelsHorizontal(W) then
    	x1 := Trunc(((TotalPageWidthPixels*ScaleByValue) -
      							InchesToPixelsHorizontal(W))-GutterLeft) div 2
    else
    	x1 := 0
  else
		x1 := Trunc(InchesToPixelsHorizontal(X) - GutterLeft);
  if H = -1.0 then
  	y2 := Trunc(thePicture.Height * ScreenToPrinter * ScaleByValue)
  else
  	y2 := Trunc(InchesToPixelsVertical(H));
  H := PixelsToInchesVertical(y2)/ScaleByValue;
  if Y = -1.0 then
  	if TotalPageHeightPixels > InchesToPixelsVertical(H) then
    	y1 := Trunc(((TotalPageHeightPixels*ScaleByValue) -
      							InchesToPixelsVertical(H))-GutterTop) div 2
    else
     	y1 := 0
  else
  	y1 := Trunc(InchesToPixelsVertical(Y) - GutterTop);
	if ImagePrinting or (thePicture.Picture.Graphic.ClassName = 'TIcon') then
		TheCanvas.StretchDraw(rect(x1,y1,x1+x2,y1+y2),thePicture.Picture.Graphic)
  else if thePicture.Picture.Graphic.ClassName = 'TBitmap' then
  	BltTBitmapAsDib(TheCanvas.Handle,x1,y1,x2,y2,thePicture.Picture.Bitmap);
end;

procedure TMWPrintObject.PrintPage(Page: TMWPageList;iPage: integer);
{ This procedure will loop through a given pages command list and output that
  information to the current printing canvas }
var
	x,y: integer;
  oldColor: TColor;
  tCommand: TMWPrintCommand;
  Buffer: string;
  SkipNext: integer;

begin
	SkipNext := 0;
  SetTopOfPage;
  for x := 1 to Page.Count do
  begin
  	if SkipNext = 0 then
    begin
  	tCommand := Page.Get(x);
    case tCommand.Command of
      commLine:
      	try
      	with tCommand as TMWLine do
        	DrawLine(X1,Y1,X2,Y2,LineWidth);
        except
        	ShowMessage('Error in Line Drawing command.');
        end;
      commNewLine:
      	try
        	NextLine;
        except
        	ShowMessage('Error in Next Line command.');
        end;
      commFColor:
      	try
        with tCommand as TMWFColor do
        	SetFontColor(Color);
        except
        	ShowMessage('Error in Font Color change.');
        end;
      commBColor:
      	try
        with tCommand as TMWBColor do
        	SetBrushColor(Color);
        except
        	ShowMessage('Error in Brush Color change.');
        end;
      commPColor:
      	try
        with tCommand as TMWPColor do
        	SetPenColor(Color);
        except
        	ShowMessage('Error in Pen Color change.');
        end;
      commGraphic:
      	try
      	with tCommand as TMWGraphic do
        	PrintGraphic(X,Y,Height,Width,Bitmap);
        except
        	ShowMessage('Error in Graphics Drawing routine.');
        end;
      commDetailArea:
      	try
      	with tCommand as TMWDetail do
        	SetDetailTopBottom(X,Y);
        except
        	ShowMessage('Error in Setting Detail Top/Bottom settings.');
        end;
      commFont:
      	try
      	with tCommand as TMWFont do
        	SetFontInfo(Font);
        except
        	ShowMessage('Error in Changing Font information');
        end;
      commFooterDim:
      	try
      	with tCommand as TMWFooterDim do
        	SetFooterDim(X1,Y1,X2,Y2,Boxed,LineWidth,Shading);
        except
        	ShowMessage('Error in Setting Footer Dimensions.');
        end;
      commFooterInf:
      	try
      	with tCommand as TMWFooterInf do
        	SetFooterInfo(Line,yPosition,Text,Alignment,Font);
        except
        	ShowMessage('Error in Setting Footer Information.');
        end;
      commHeaderDim:
      	try
      	with tCommand as TMWHeaderDim do
        	SetHeaderDim(X1,Y1,X2,Y2,Boxed,LineWidth,Shading);
        except
        	ShowMessage('Error in Setting Header Dimensions.');
        end;
      commHeaderInf:
      	try
      	with tCommand as TMWHeaderInf do
        	SetHeaderInfo(Line,yPosition,Text,Alignment,Font);
        except
        	ShowMessage('Error in Setting Header Information.');
        end;
      commLineWidth:
      	try
      	with tCommand as TMWLineWidth do
        	SetLineWidth(LineWidth);
        except
        	ShowMessage('Error in Setting Line Width.');
        end;
      commMargins:
      	try
      	with tCommand as TMWMargins do
        	SetMargins(X1,Y1,X2,Y2);
        except
        	ShowMessage('Error in Setting Margins.');
        end;
      commOrient:
      	try
      	with tCommand as TMWOrient do
        	PageOrientation := Orientation;
        except
        	ShowMessage('Error in Setting Page Orientation.');
        end;
      commWritePage:
      	try
          y := 1;
          tCommand := Page.Get(x+y);
          inc(y);
          if tCommand.Command = commTab then
          begin
      			with tCommand as TMWTab do
        			SetTab(Tab);
          	tCommand := Page.Get(x+y);
            inc(SkipNext);
            inc(y);
          end;
          if tCommand.Command = commMeasure then
          begin
          	with tCommand as TMWMeasure do
            	SetMeasure(MeasureType(Measure));
            tCommand := Page.Get(x+y);
            inc(SkipNext);
            inc(y);
          end;
          if tCommand.Command = commSetY then
          begin
          	with tCommand as TMWSetY do
          		SetYPosition(YPosition);
            tCommand := Page.Get(x+y);
            inc(SkipNext);
            inc(y);
          end;
          if tCommand.Command = commMeasure then
          begin
          	with tCommand as TMWMeasure do
            	SetMeasure(MeasureType(Measure));
            tCommand := Page.Get(x+y);
            inc(SkipNext);
            inc(y);
          end;
          with tCommand as TMWText do
          begin
            Buffer := Format( PageNumber.Text,[iPage] );
            if PageNumber.ShowTotalPages then
              Buffer := Buffer + ' of ' + IntToStr(TotalPages);
            WriteLine(X,Y,Buffer);
          end;
          inc(SkipNext);
        except
          ShowMessage('Error writing page number information.');
        end;
      commPageNumber:
      	try
      	with tCommand as TMWPageNumber do
        	SetPageNumberInfo(yPosition,Text,Alignment,IncludeTotal,Font);
        except
        	ShowMessage('Error Setting Page Number Information.');
        end;
      commTab:
      	try
      	with tCommand as TMWTab do
        	SetTab(Tab);
        except
        	ShowMessage('Error Setting Tab.');
        end;
      commTopOfPage:
      	try
      		SetTopOfPage;
        except
        	ShowMessage('Error Setting Top of Page.');
        end;
      commSetY:
      	try
      	with tCommand as TMWSetY do
        	SetYPosition(yPosition);
        except
        	ShowMessage('Error Setting Vertical Position.');
        end;
      commText:
      	try
      	with tCommand as TMWText do
        begin
        	oldColor := TheCanvas.Brush.Color;
        	TheCanvas.Brush.Color := BrushColor;
        	WriteLine(X,Y,Text);
          TheCanvas.Brush.Color := oldColor;
        end;
      	except
        	ShowMessage('Error Writing Line of Text.');
        end;
      commColumn:
      	try
      	with tCommand as TMWColumn do
        	CreateColumn(Number,XPosition,Length);
        except
        	ShowMessage('Error Creating Column Setting.');
        end;
      commAutoPageTrue:
      	SetAutoPaging(true);
      commAutoPageFalse:
      	SetAutoPaging(false);
      commSaveY:
      	SaveCurrentY;
      commRestoreY:
      	RestoreCurrentY;
      commMoveTo:
      	try
        	with tCommand as TMWGraphicPoint do
          	MoveTo(X1,Y1);
        except
        	ShowMessage('Error in MoveTo command.');
        end;
      commLineTo:
      	try
        	with tCommand as TMWGraphicPoint do
          	LineTo(X1,Y1);
        except
        	ShowMessage('Error in LineTo command.');
        end;
      commEllipse:
      	try
        	with tCommand as TMWEllipse do
          	Ellipse(X1,Y1,X2,Y2);
        except
        	ShowMessage('Error in Ellipse command.');
        end;
			commBrushStyle:
      	try
        	with tCommand as TMWBrushStyle do
          	SetBrushStyle(Style);
        except
        	ShowMessage('Error Setting Brush Style.');
        end;
      commFillRect:
      	try
        	with tCommand as TMWFillRect do
          	FillRect(X1,Y1,X2,Y2);
        except
        	ShowMessage('Error in FillRect command.');
        end;
      commFloodFill:
      	try
        	with tCommand as TMWFloodFill do
          	FloodFill(X,Y,Color,FillStyle);
        except
        	ShowMessage('Error in FloodFill command.');
      	end;
      commFrameRect:
      	try
        	with tCommand as TMWFrameRect do
          	FrameRect(X1, Y1, X2, Y2);
        except
        	ShowMessage('Error in FrameRect command.');
        end;
      commPie:
      	try
        	with tCommand as TMWPieArc do
          	Pie(X1,Y1,X2,Y2,X3,Y3,X4,Y4);
        except
        	ShowMessage('Error in Pie command.');
        end;
      commArc:
      	try
        	with tCommand as TMWPieArc do
          	Arc(X1,Y1,X2,Y2,X3,Y3,X4,Y4);
        except
        	ShowMessage('Error in Arc command.');
        end;
      commPolyLine:
      	try
        	with tCommand as TMWPolygon do
          	PolyLine(slice(Points,Num));
        except
        	ShowMessage('Error in PolyLine command.');
        end;
      commPolygon:
      	try
        	with tCommand as TMWPolygon do
          	Polygon(slice(Points,Num));
        except
        	ShowMessage('Error in Polygon command.');
        end;
//      commMeasure:
//      	try
//        	with tCommand as TMWMeasure do
//          	self.Measure := MeasureType(Measure);
//        except
//        	ShowMessage('Error setting Measure units.');
//        end;
      commPStyle:
      	try
        	with tCommand as TMWPStyle do
          	self.SetPenStyle(Style);
        except
        	ShowMessage('Error setting pen style.');
        end;
      commPMode:
      	try
        	with tCommand as TMWPMode do
          	self.SetPenMode(Mode);
        except
        	ShowMessage('Error setting pen mode.');
        end;
    end
    end
    else
    	dec(SkipNext);
  end;
end;

procedure TMWPrintObject.PolyLine(Points: array of single);
var
	x,y: integer;
  ScreenToPrinter: single;

begin
	if DryRun or ImagePrinting then
  	for x := low(Points) to High(Points) do
  		case Measure of
    		mtInches: Points[x] := InchesToPixelsHorizontal(Points[x]);
        mtMM: Points[x] := MMToPixelsHorizontal(Points[x]);
      end;
	if DryRun then
  	Pages.StorePolyLine(Points);
  if PixelsPerInchHorizontal > PixelsPerInchVertical then
  	ScreenToPrinter := PixelsPerInchHorizontal / Screen.PixelsPerInch
  else
  	ScreenToPrinter := PixelsPerInchVertical / Screen.PixelsPerInch;
  for x := low(Points) to high(Points) do
  	Points[x] := Trunc(Points[x] * ScaleByValue*ScreenToPrinter) - GutterLeft;
	y := 0;
  x := low(Points);
  while x < high(Points) do
  begin
		PointArray[y].X := Trunc(Points[x]);
    PointArray[y].Y := Trunc(Points[x+1]);
    inc(x,2);
    inc(y);
  end;
  TheCanvas.PolyLine(slice(PointArray,y));
end;

procedure TMWPrintObject.Polygon(Points: array of single);
var
	x,y: integer;
  ScreenToPrinter: single;

begin
	if DryRun or ImagePrinting then
  	for x := low(Points) to High(Points) do
  		case Measure of
    		mtInches: Points[x] := InchesToPixelsHorizontal(Points[x]);
        mtMM: Points[x] := MMToPixelsHorizontal(Points[x]);
      end;
	if DryRun then
  	Pages.StorePolygon(Points);
  if PixelsPerInchHorizontal > PixelsPerInchVertical then
  	ScreenToPrinter := PixelsPerInchHorizontal / Screen.PixelsPerInch
  else
  	ScreenToPrinter := PixelsPerInchVertical / Screen.PixelsPerInch;
  for x := low(Points) to high(Points) do
  	Points[x] := Trunc(Points[x]*ScreenToPrinter*ScaleByValue)-GutterLeft;
	y := 0;
  x := low(Points);
  while x < high(Points) do
  begin
		PointArray[y].X := Trunc(Points[x]);
    PointArray[y].Y := Trunc(Points[x+1]);
    inc(x,2);
    inc(y);
  end;
  TheCanvas.Polygon(slice(PointArray,y));
end;

procedure TMWPrintObject.Quit;
   { 'Quit' must always be called when printing is completed. If preview
   		mode is set, then it displays the preview form. }
var
	oldPaging: boolean;
  oldMeasure: MeasureType;

begin
	if ImagePrinting then
  begin
  	PrinterCanvas := nil;
  	PrintingOK := false;
  	exit;
  end;
	if PrintingOK then
  begin
		try
			WriteHeader;
  		WriteFooter;
  		WritePageNumber;
  		OnPageChange;
  	except
  		ShowMessage('Error in completing last page.');
  	end;
  	DryRun := false;
  	try
  		if UseProgress then
  		begin
  			ProgressBar.Close;
  			ProgressBar.Destroy;
  		end;
    	BarShowing := false;
  		Pages.FromPage := 1;
  		Pages.ToPage := Pages.Count;
  	except
  		ShowMessage('Error preparing final report.');
  	end;
    oldPaging := AutomaticPaging;
    AutomaticPaging := false;
    oldMeasure := Measure;
    Measure := mtInches;
		try
  		if ActualPreview then
    		ShowPreview
  		else
  			PrintFromPreview;
  	except
  		ShowMessage('Error showing/printing final report.');
  	end;
    Measure := oldMeasure;
    AutomaticPaging := oldPaging;
  end
  else
  begin
  	if UseProgress then
  	begin
  		ProgressBar.Close;
  		ProgressBar.Destroy;
    end;
    BarShowing := false;
  end;
  try
  	Cleanup;
  	Pages.Destroy;
  except
  	ShowMessage('Error cleaning up report pages.');
  end;
  PrintingOK := false;
  WritePrinterSpecs(true);
end;

procedure TMWPrintObject.ReadPrinterSpecs(SaveState: boolean);
var
	MyHandle: THandle;
  MyDevMode: pDevMode;
  MyDevice,
  MyDriver,
  MyPort: array [0..255] of char;

begin
	if Not PrintingOK then
  	exit;
	Printer.GetPrinter(MyDevice,MyDriver,MyPort,MyHandle);
  MyDevMode := GlobalLock(MyHandle);
  try
  	IsColor := (MyDevMode^.dmFields = DM_COLOR);
  	MyDevMode^.dmFields := MyDevMode^.dmFields or (DM_PAPERSIZE or DM_ORIENTATION);
    if Not SaveState then
    begin
    	PaperSize := PaperSizes(MyDevMode^.dmPaperSize-1);
    	if MyDevMode^.dmOrientation = DMORIENT_LANDSCAPE then
    		Orientation := poLandscape
    	else
    		Orientation := poPortrait;
    end
    else
    begin
    	OrigPaperSize := MyDevMode^.dmPaperSize;
      OrigPaperOrient := MyDevMode^.dmOrientation;
    end;
  finally
  	GlobalUnLock(MyHandle);
  end;
end;


procedure Register;
{ Register this component under the System Tab }
begin
  RegisterComponents('Print Utils', [TMWPrintObject]);
end;

procedure TMWPrintObject.RestoreCurrentFont;
{ Restores the font information after being saved }
begin
	if Not PrintingOK then
  	exit;
  if (CurrentFontRecord in [1..10]) then
  begin
		SetFontInfo( CurrentFonts[CurrentFontRecord].Font );
    CurrentFonts[CurrentFontRecord].Font.Free;
    CurrentFonts[CurrentFontRecord].Font := nil;
		dec(CurrentFontRecord);
  end;
end;

procedure TMWPrintObject.RestoreCurrentY;
begin
	if CurrentYRecord in [1..10] then
  	LastYPosition := CurrentYPosition[CurrentYRecord];
  if DryRun then
  	Pages.StoreGeneral(commRestoreY);
  if CurrentYRecord > 0 then
  	dec(CurrentYRecord);
end;

procedure TMWPrintObject.SaveCurrentFont;
{ Saves the current font information }
begin
	if Not PrintingOK then
  	exit;
	inc(CurrentFontRecord);
  if CurrentFontRecord in [1..10] then
  begin
  	if CurrentFonts[CurrentFontRecord].Font = nil then
    	CurrentFonts[CurrentFontRecord].Font := TFont.Create;
  	with CurrentFonts[CurrentFontRecord].Font do
    begin
  		Name := TheCanvas.Font.Name;
      Size := TheCanvas.Font.Size;
      Style := TheCanvas.Font.Style;
      Color := TheCanvas.Font.Color;
    end;
  end;
end;

procedure TMWPrintObject.SaveCurrentY;
begin
	inc(CurrentYRecord);
  if CurrentYRecord in [1..10] then
  	CurrentYPosition[CurrentYRecord] := LastYPosition;
  if DryRun then
  	Pages.StoreGeneral(commSaveY);
end;

procedure TMWPrintObject.SetAutoPaging( Value: boolean );
{ Controls whether automatic paging is used when reaching the end
  of the detail area of the page }
begin
	if DryRun then
  	if Value then
    	Pages.StoreGeneral(commAutoPageTrue)
    else
    	Pages.StoreGeneral(commAutoPageFalse);
	AutoPaging := Value;
end;

procedure TMWPrintObject.SetBrushColor(iColor: TColor);
begin
	if DryRun then
  	Pages.StoreBColor(iColor);
//  if IsColor or not IsPrinting then
		TheCanvas.Brush.Color := iColor;
end;

procedure TMWPrintObject.SetBrushStyle(Style: TBrushStyle);
begin
	if DryRun then
  	Pages.StoreBStyle(Style);
	TheCanvas.Brush.Style := Style;
end;

procedure TMWPrintObject.SetDetailTopBottom( Top: single; Bottom: single );
{ Sets the top and bottom margins of the detail printing area of the
  report }
begin
	if Not PrintingOK then
  	exit;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels:
      	begin
        	Top := PixelsToInchesHorizontal(Trunc(Top));
          Bottom := PixelsToInchesVertical(Trunc(Bottom));
        end;
      mtMM:
      	begin
        	Top := MMToInches(Top);
          Bottom := MMToInches(Bottom);
        end;
    end;
	if DryRun then
  	Pages.StoreDetailArea(Top,Bottom);
	DetailTop := Top;
  DetailBottom := Bottom;
  LastYPosition := Top - GetLineHeightInches;
end;

procedure TMWPrintObject.SetFontColor(iColor: TColor);
begin
	if DryRun then
  	Pages.StoreFColor(iColor);
  if IsColor or not IsPrinting then
		TheCanvas.Font.Color := iColor;
end;

procedure TMWPrintObject.SetFontInformation( Name:string; Size:word; Style: TFontStyles );
   { Change the current font information }
begin
	if Not PrintingOK then
  	exit;
	if DryRun then
  	Pages.StoreFontChange(Name,Size,Style,TheCanvas.Font.Color);
	TheCanvas.Font.Name := Name;
  TheCanvas.Font.Size := Size;
  TheCanvas.Font.Style := Style;
//  TheCanvas.Pen.Mode := pmMask;
  CalculateMeasurements;
end;

procedure TMWPrintObject.SetFontInfo( Font: TFont );
   { Change the current font information }
begin
	if Not PrintingOK then
  	exit;
	if DryRun then
  	Pages.StoreFontChange(Font.Name,Font.Size,Font.Style,Font.Color);
	TheCanvas.Font.Name := Font.Name;
  TheCanvas.Font.Size := Font.Size;
  TheCanvas.Font.Style := Font.Style;
  if IsColor or not IsPrinting then
  	TheCanvas.Font.Color := Font.Color;
//  TheCanvas.Pen.Mode := pmMask;
  CalculateMeasurements;
end;

procedure TMWPrintObject.SetFooterDimensions( XTop,YTop,XBottom,YBottom:single;
																						Boxed: boolean; LineWidth:word;
                                            Shading:word );
{ Sets the area of the page footer and whether it should be boxed and shaded }
begin
	if Not PrintingOK then
  	exit;
	FooterCoordinates.XTop := XTop;
  FooterCoordinates.XBottom := XBottom;
  FooterCoordinates.YTop := YTop;
  FooterCoordinates.YBottom := YBottom;
  FooterCoordinates.Boxed := Boxed;
  FooterCoordinates.LineWidth := LineWidth;
  FooterCoordinates.Shading := RGB(Byte(Shading),Byte(Shading),Byte(Shading));
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels:
      	begin
        	XTop := PixelsToInchesHorizontal(Trunc(XTop));
          YTop := PixelsToInchesVertical(Trunc(YTop));
          XBottom := PixelsToInchesHorizontal(Trunc(XBottom));
          YBottom := PixelsToInchesVertical(Trunc(YBottom));
        end;
      mtMM:
      	begin
        	XTop := MMToInches(XTop); YTop := MMToInches(YTop);
          XBottom := MMToInches(XBottom); YBottom := MMToInches(YBottom);
        end;
    end;
	if DryRun then
  	Pages.StoreFooterDim(XTop,YTop,XBottom,YBottom,Boxed,
    		LineWidth,RGB(Byte(Shading),Byte(Shading),Byte(Shading)));
end;

procedure TMWPrintObject.SetFooterDim( XTop,YTop,XBottom,YBottom:single;
																						Boxed: boolean; LineWidth:word;
                                            Shading:TColor );
{ Sets the area of the page footer and whether it should be boxed and shaded }
begin
	if Not PrintingOK then
  	exit;
	FooterCoordinates.XTop := XTop;
  FooterCoordinates.XBottom := XBottom;
  FooterCoordinates.YTop := YTop;
  FooterCoordinates.YBottom := YBottom;
  FooterCoordinates.Boxed := Boxed;
  FooterCoordinates.LineWidth := LineWidth;
  FooterCoordinates.Shading := Shading;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels:
      	begin
        	XTop := PixelsToInchesHorizontal(Trunc(XTop));
          YTop := PixelsToInchesVertical(Trunc(YTop));
          XBottom := PixelsToInchesHorizontal(Trunc(XBottom));
          YBottom := PixelsToInchesVertical(Trunc(YBottom));
        end;
      mtMM:
      	begin
        	XTop := MMToInches(XTop); YTop := MMToInches(YTop);
          XBottom := MMToInches(XBottom); YBottom := MMToInches(YBottom);
        end;
    end;
	if DryRun then
  	Pages.StoreFooterDim(XTop,YTop,XBottom,YBottom,Boxed,LineWidth,Shading);
end;

procedure TMWPrintObject.SetFooterInformation( Line:integer; YPosition: single;
            Text:string; Alignment:word; FontName:string; FontSize: word;
            FontStyle: TFontStyles );
{ Sets the footer information to be printed }
begin
	if Not PrintingOK then
  	exit;
	if ( Line > FooterLines ) then
  	Exit;
  Footer[Line].Text := Text;
  Footer[Line].YPosition := YPosition;
  Footer[Line].Alignment := Alignment;
  if Footer[Line].Font = nil then
  	Footer[Line].Font := TFont.Create;
  Footer[Line].Font.Name := FontName;
  Footer[Line].Font.Size := FontSize;
  Footer[Line].Font.Style := FontStyle;
  Footer[Line].Font.Color := TheCanvas.Font.Color;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels: YPosition := PixelsToInchesVertical(Trunc(YPosition));
      mtMM: YPosition := MMToInches(YPosition);
  	end;
  if DryRun then
  	Pages.StoreFooterInf(Line,YPosition,Text,Alignment,FontName,FontSize,FontStyle,TheCanvas.Font.Color);
end;

procedure TMWPrintObject.SetFooterInfo( Line:integer; YPosition: single;
            Text:string; Alignment:word; Font: TFont );
{ Sets the footer information to be printed }
begin
	if Not PrintingOK then
  	exit;
	if ( Line > FooterLines ) then
  	Exit;
  Footer[Line].Text := Text;
  Footer[Line].YPosition := YPosition;
  Footer[Line].Alignment := Alignment;
  if Footer[Line].Font = nil then
  	Footer[Line].Font := TFont.Create;
  Footer[Line].Font.Assign(Font);
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels: YPosition := PixelsToInchesVertical(Trunc(YPosition));
      mtMM: YPosition := MMToInches(YPosition);
  	end;
  if DryRun then
  	Pages.StoreFooterInf(Line,YPosition,Text,Alignment,Font.Name,Font.Size,Font.Style,Font.Color);
end;

procedure TMWPrintObject.SetHeaderDimensions( XTop,YTop,XBottom,YBottom:single;
																						Boxed: boolean; LineWidth:word;
                                            Shading:word );
{ Sets the area of the header for the page }
begin
	if Not PrintingOK then
  	exit;
	HeaderCoordinates.XTop := XTop;
  HeaderCoordinates.XBottom := XBottom;
  HeaderCoordinates.YTop := YTop;
  HeaderCoordinates.YBottom := YBottom;
  HeaderCoordinates.Boxed := Boxed;
  HeaderCoordinates.LineWidth := LineWidth;
  HeaderCoordinates.Shading := RGB(Byte(Shading),Byte(Shading),Byte(Shading));
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels:
      	begin
        	XTop := PixelsToInchesHorizontal(Trunc(XTop));
          YTop := PixelsToInchesVertical(Trunc(YTop));
          XBottom := PixelsToInchesHorizontal(Trunc(XBottom));
          YBottom := PixelsToInchesVertical(Trunc(YBottom));
        end;
      mtMM:
      	begin
        	XTop := MMToInches(XTop); YTop := MMToInches(YTop);
          XBottom := MMToInches(XBottom); YBottom := MMToInches(YBottom);
        end;
    end;
	if DryRun then
  	Pages.StoreHeaderDim(XTop,YTop,XBottom,YBottom,Boxed,
    		LineWidth,RGB(Byte(Shading),Byte(Shading),Byte(Shading)));
end;

procedure TMWPrintObject.SetHeaderDim( XTop,YTop,XBottom,YBottom:single;
																						Boxed: boolean; LineWidth:word;
                                            Shading:TColor );
{ Sets the area of the header for the page }
begin
	if Not PrintingOK then
  	exit;
	HeaderCoordinates.XTop := XTop;
  HeaderCoordinates.XBottom := XBottom;
  HeaderCoordinates.YTop := YTop;
  HeaderCoordinates.YBottom := YBottom;
  HeaderCoordinates.Boxed := Boxed;
  HeaderCoordinates.LineWidth := LineWidth;
  HeaderCoordinates.Shading := Shading;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels:
      	begin
        	XTop := PixelsToInchesHorizontal(Trunc(XTop));
          YTop := PixelsToInchesVertical(Trunc(YTop));
          XBottom := PixelsToInchesHorizontal(Trunc(XBottom));
          YBottom := PixelsToInchesVertical(Trunc(YBottom));
        end;
      mtMM:
      	begin
        	XTop := MMToInches(XTop); YTop := MMToInches(YTop);
          XBottom := MMToInches(XBottom); YBottom := MMToInches(YBottom);
        end;
    end;
	if DryRun then
  	Pages.StoreHeaderDim(XTop,YTop,XBottom,YBottom,Boxed,LineWidth,Shading);
end;

procedure TMWPrintObject.SetHeaderInformation( Line:integer; YPosition: single;
            Text:string; Alignment:word; FontName:string; FontSize: word;
            FontStyle: TFontStyles );
{ Sets the header information to be printed }
begin
	if Not PrintingOK then
  	exit;
	if ( Line > HeaderLines ) then
		Exit;
  Header[Line].Text := Text;
  Header[Line].YPosition := YPosition;
  Header[Line].Alignment := Alignment;
  if Header[Line].Font = nil then
  	Header[Line].Font := TFont.Create;
  Header[Line].Font.Name := FontName;
  Header[Line].Font.Size := FontSize;
  Header[Line].Font.Style := FontStyle;
  Header[Line].Font.Color := TheCanvas.Font.Color;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels: YPosition := PixelsToInchesVertical(Trunc(YPosition));
      mtMM: YPosition := MMToInches(YPosition);
  	end;
  if DryRun then
  	Pages.StoreHeaderInf(Line,YPosition,Text,Alignment,FontName,FontSize,FontStyle,TheCanvas.Font.Color);
end;

procedure TMWPrintObject.SetHeaderInfo( Line:integer; YPosition: single;
            Text:string; Alignment:word; Font: TFont );
{ Sets the header information to be printed }
begin
	if Not PrintingOK then
  	exit;
	if ( Line > HeaderLines ) then
		Exit;
  Header[Line].Text := Text;
  Header[Line].YPosition := YPosition;
  Header[Line].Alignment := Alignment;
  if Header[Line].Font = nil then
  	Header[Line].Font := TFont.Create;
  Header[Line].Font.Assign(Font);
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels: YPosition := PixelsToInchesVertical(Trunc(YPosition));
      mtMM: YPosition := MMToInches(YPosition);
  	end;
  if DryRun then
  	Pages.StoreHeaderInf(Line,YPosition,Text,Alignment,Font.Name,Font.Size,Font.Style,Font.Color);
end;

procedure TMWPrintObject.SetLineWidth( Width:word );
{ Sets the current pen width for drawing }
begin
	if DryRun then
  	Pages.StoreLineWidth(Width);
  if ImagePrinting then
  	TheCanvas.Pen.Width := Width
  else
		TheCanvas.Pen.Width := Trunc(((Width * TotalPageWidthPixels) /
    																Printer.PageWidth) * ScaleByValue);
end;

procedure TMWPrintObject.SetMargins( Top,Bottom,Left,Right:Single );
   { Set the top, bottom, left and right margins in inches }
begin
   { If the sum of the left and right margins exceeds the width of the page,
     set the left margin to the value of 'GutterLeft' and set the right
     margin to the value of 'GutterRight' }
	if Not PrintingOK then
  	exit;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels:
      	begin
        	Top := PixelsToInchesVertical(Trunc(Top));
          Bottom := PixelsToInchesVertical(Trunc(Bottom));
          Left := PixelsToInchesHorizontal(Trunc(Left));
          Right := PixelsToInchesHorizontal(Trunc(Right));
        end;
      mtMM:
      	begin
        	Top := MMToInches(Top); Bottom := MMToInches(Bottom);
          Left := MMToInches(Left); Right := MMToInches(Right);
        end;
    end;
  if ImagePrinting then
  begin
    TopMargin := InchesToPixelsVertical(Top);
    BottomMargin := InchesToPixelsVertical(Bottom);
    LeftMargin := InchesToPixelsHorizontal(Left);
    RightMargin := InchesToPixelsHorizontal(Right);
    CalculateMeasurements;
    exit;
  end;
	if DryRun then
  	Pages.StoreMargins(Top,Bottom,Left,Right);
	if ( Left + Right > TotalPageWidthInches ) then
  begin
  	Left := PixelsToInchesHorizontal(GutterLeft);
    Right := TotalPageWidthInches - PixelsToInchesHorizontal(GutterRight);
  end;
  if ( Left <= 0 ) then
  	Left := PixelsToInchesHorizontal(GutterLeft);
  if ( Right <= 0 ) then
  	Right := TotalPageWidthInches - PixelsToInchesHorizontal(GutterRight);
   { If the sum of the top and bottom margins exceeds the height of the
     page, set the top margin to the value of 'GutterTop' and set the
     bottom margin to the value of 'GutterBottom' }
  if ( Top + Bottom >= TotalPageHeightInches ) then
  begin
  	Top := PixelsToInchesVertical(GutterTop);
    Bottom := TOtalPageHeightInches - PixelsToInchesVertical(GutterBottom);
  end;
  if ( Top <= 0 ) then
  	Top := PixelsToInchesVertical(GutterTop);
  if ( Bottom <= 0 ) then
  	Bottom := TotalPageHeightInches - PixelsToInchesVertical(GutterBottom);
   { Convert everything to pixels }
  TopMargin := Trunc(InchesToPixelsVertical( Top ) * ScaleByValue);
  if ( TopMargin < GutterTop ) then
  	TopMargin := GutterTop;
  BottomMargin := Trunc(InchesToPixelsVertical( Bottom ) * ScaleByValue);
  if ( BottomMargin > TotalPageHeightPixels - GutterBottom ) then
  	BottomMargin := TotalPageHeightPixels - GutterBottom;
  LeftMargin := Trunc(InchesToPixelsHorizontal( Left ) * ScaleByValue);
  if ( LeftMargin < GutterLeft ) then
  	LeftMargin := GutterLeft;
  RightMargin := Trunc(InchesToPixelsHorizontal( Right ) * ScaleByValue);
  if ( RightMargin > TotalPageWidthPixels - GutterRight ) then
  	RightMargin := TotalPageWidthPixels - GutterRight;
end;

procedure TMWPrintObject.SetOrientation(Orient: TPrinterOrientation);
begin
	Orientation := Orient;
end;

procedure TMWPrintObject.SetPageNumberInformation( YPosition:single;
   Text:string; Alignment:word; IncludeTotal: boolean;FontName:string;
   FontSize:word; FontStyle:TFontStyles );
{ Sets the manner of printing the page number. The "Text" parameter should be in
  the form of a format string }
begin
	if Not PrintingOK then
  	exit;
	PageNumber.Text := Text;
  PageNumber.YPosition := YPosition;
  PageNumber.Alignment := Alignment;
  if PageNumber.Font = nil then
  	PageNumber.Font := TFont.Create;
  PageNumber.Font.Name := FontName;
  PageNumber.Font.Size := FontSize;
  PageNumber.Font.Style := FontStyle;
  PageNumber.Font.Color := TheCanvas.Font.Color;
  PageNumber.ShowTotalPages := IncludeTotal;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels: YPosition := PixelsToInchesVertical(Trunc(YPosition));
      mtMM: YPosition := MMToInches(YPosition);
    end;
	if DryRun then
  	Pages.StorePageNumber(YPosition,Text,Alignment,IncludeTotal,FontName,
    											FontSize,FontStyle,TheCanvas.Font.Color);
end;

procedure TMWPrintObject.SetPageNumberInfo( YPosition:single;
   Text:string; Alignment:word; IncludeTotal: boolean; Font:TFont );
{ Sets the manner of printing the page number. The "Text" parameter should be in
  the form of a format string }
begin
	if Not PrintingOK then
  	exit;
	PageNumber.Text := Text;
  PageNumber.YPosition := YPosition;
  PageNumber.Alignment := Alignment;
  if PageNumber.Font = nil then
  	PageNumber.Font := TFont.Create;
  PageNumber.Font.Assign(Font);
  PageNumber.ShowTotalPages := IncludeTotal;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels: YPosition := PixelsToInchesVertical(Trunc(YPosition));
      mtMM: YPosition := MMToInches(YPosition);
    end;
	if DryRun then
  	Pages.StorePageNumber(YPosition,Text,Alignment,IncludeTotal,
    											Font.Name,Font.Size,Font.Style,Font.Color);
end;

procedure TMWPrintObject.SetPaperSize(Size: PaperSizes);
begin
  PaperDimension := Size;
end;

procedure TMWPrintObject.SetPenColor(iColor: TColor);
begin
	if DryRun then
  	Pages.StorePColor(iColor);
	TheCanvas.Pen.Color := iColor;
end;

procedure TMWPrintObject.SetPenStyle(Style: TPenStyle);
begin
	if DryRun then
  	Pages.StorePStyle(Style);
	TheCanvas.Pen.Style := Style;
end;

procedure TMWPrintObject.SetPenMode(Mode: TPenMode);
begin
	if DryRun then
  	Pages.StorePMode(Mode);
	TheCanvas.Pen.Mode := Mode;
end;

procedure TMWPrintObject.SetPenWidth(iWidth: integer);
begin
	if DryRun then
  	Pages.StoreLineWidth(iWidth);
  TheCanvas.Pen.Width := iWidth;
end;

procedure TMWPrintObject.SetPreviewMode(Mode: boolean);
{ Sets the preview mode and canvas }
begin
	if Not PrintingOK then
  	exit;
	Case Mode of
  True:
  	begin
      ThePrinter := PreviewForm.GetCurrentPage;
    	TheCanvas := ThePrinter.Canvas;
    end;
  end;
  PreviewMode := Mode;
end;

procedure TMWPrintObject.SetPrnPrinter(Current: TImage);
{ Sets the current printing canvas of the preview form }
begin
	ThePrinter := Current;
  TheCanvas := ThePrinter.Canvas;
end;

procedure TMWPrintObject.SetProgressMax(Max: integer);
begin
	ProgressBarMax := Max;
  if BarShowing then
  	ProgressBar.PrintBar.Max := Max;
end;

procedure TMWPrintObject.SetScale(ScaleFactor: single);
{Sets the current scale multiplier}
begin
	ScaleByValue := ScaleFactor;
  CalculateMeasurements;
end;

procedure TMWPrintObject.SetShowTotalPages(Mode: boolean);
{ Sets whether total page numbers appears in page numbering }
begin
	PageNumber.ShowTotalPages := Mode
end;

procedure TMWPrintObject.SetTab( Inches:single );
{ Set a tab location on the page }
begin
	if Not PrintingOK then
  	exit;
 	if DryRun then
  	Pages.StoreTab(Inches);
  CurrentTab := Inches;
end;

procedure TMWPrintObject.SetTopOfPage;
{ Sets the printing canvas to the top of the detail area on the page }
begin
	if Not PrintingOK then
  	exit;
	if DryRun then
  	Pages.StoreGeneral(commTopOfPage);
  LastYPosition := DetailTop;
	LastXPosition := LeftMargin;
end;

procedure TMWPrintObject.SetYPosition( YPosition:single );
{ Sets the current line position on the printing canvas }
begin
	if Not PrintingOK then
  	exit;
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels: YPosition := PixelsToInchesVertical(Trunc(YPosition));
      mtMM: YPosition := MMToInches(YPosition);
    end;
	if DryRun then
  	Pages.StoreSetY(YPosition);
	LastYPosition := YPosition;
end;

procedure TMWPrintObject.ShowPreview;
{ Displays the preview form }
{ This function is obsolete and should not be called. It is invoked internally
  now through the call to Quit. }
begin
	If not PreviewMode then
  	exit;
  PreviewForm.StartPercent := ord(PreviewPercent);
  PreviewForm.ShowModal;
end;

procedure TMWPrintObject.Start;
   { This function MUST be called first before any other printing function }
var
	Top,Bottom,Left,Right: single;
  I: integer;

Begin
{Added this to implement the stored commands procedures. We force the printing to
 run through first in DryRun mode. This gives us the ability to store all print
 commands and then replay them when the Quit command is executed. If the preview
 mode is set, then we need to pass control to the preview form. It will drive the
 page printing through a procedure call hook that we set with OnPrintPage event of
 the preview object.}

 	ImagePrinting := ImageCanvas <> nil;
	PrintingOK := true;
  if not ImagePrinting then
  begin
  	PreviewForm := TPreviewForm.Create(nil);
    with PreviewForm do
    begin
    	Caption := LoadStr(PREVIEWFORMCAPTION);
    	CloseBtn.Caption := LoadStr(CLOSETEXT);
    	CloseBtn.Hint := LoadStr(CLOSEHINT);
      PrintBtn.Caption := LoadStr(PRINTTEXT);
      PrintBtn.Hint := LoadStr(PRINTHINT);
      ZoomLabel.Caption := LoadStr(ZOOMTEXT);
      FirstPage.Hint := LoadStr(FIRSTPAGEHINT);
      PrevPage.Hint := LoadStr(PREVPAGEHINT);
      NextPage.Hint := LoadStr(NEXTPAGEHINT);
      LastPage.Hint := LoadStr(LASTPAGEHINT);
    end;
  end;
  ReadPrinterSpecs(true); {first save the current printer specs to restore later}
  WritePrinterSpecs(false); {now set them to what we need}
  tPageHeight := PrinterSizes[ord(PaperDimension)+1].Height;
  tPageWidth := PrinterSizes[ord(PaperDimension)+1].Width;
	SetPreviewMode(not ImagePrinting);
  if not ImagePrinting then
  begin
  	Pages := TMWPages.Create;
  	Pages.NewPage;
  	Pages.FromPage := 1;
  	Pages.ToPage := 1;
  end;
  DryRun := not ImagePrinting;
	TotalPages := 1;
  ScaleByValue := 1.0;
  if not ImagePrinting and UseProgress then
  begin
  	ProgressBar := TPrintBarForm.Create(Application);
    ProgressBar.PrintPanel.Color := BarFormColor;
    ProgressBar.PrintCaption.Font.Color := BarTextColor;
    if ShowCancel then
    	ProgressBar.CancelBtn.Visible := true
    else
    	ProgressBar.CancelBtn.Visible := false;
    BarPrn := self;
    with ProgressBar do
    begin
      SetDisplayText(LoadStr(PREPARETEXT));
      CancelBtn.Caption := LoadStr(CANCELBTNTEXT);
      PrintBar.Max := ProgressMax;
  		Show;
  		UpdateBar(0);
    end;
    BarShowing := true;
  end;
  PrintingInternal := false;
  if not ImagePrinting then
  begin
 		PreviewForm.SetOrient(PageOrientation);
		PreviewForm.SetPreviewPrn(self);
 		SetPrnPrinter(PreviewForm.GetCurrentPage);
   end
  else
  	TheCanvas := ImageCanvas;
  CalculateMeasurements;
  PageNumber.Text := '';
  Top := PixelsToInchesVertical( GutterTop );
  Bottom := TotalPageHeightInches - PixelsToInchesVertical( GutterBottom );
  Left := PixelsToInchesHorizontal( GutterLeft );
  Right := TotalPageWidthInches - PixelsToInchesHorizontal( GutterRight );
  SetMargins( Top,Bottom,Left,Right );
  for I := 1 to HeaderLines do
  	Header[I].Text := '';
  HeaderCoordinates.Boxed := False;
  HeaderCoordinates.Shading := 0;
  for I := 1 to FooterLines do
  	Footer[I].Text := '';
  FooterCoordinates.Boxed := False;
  FooterCoordinates.Shading := 0;
  CurrentTab := 0.0;
  LastYPosition := 0.0;
  LastXPosition := 0.0;
  SetAutoPaging(AutoPaging);
  SetOrientation(Orientation);
  SetPaperSize(PaperDimension);
end;

procedure TMWPrintObject.UpdateBar(x: integer);
{ Sets the current progress bar value }
begin
	if ImagePrinting then
  	exit;
	if Not PrintingOK then
  	exit;
	if UseProgress then
		ProgressBar.UpdateBar(x);
end;

procedure TMWPrintObject.WrapText(Text: string; var theText: TStringList; X,Y: single);
var
	s: string;
  LastX, LastSpace,
  CurrentX: integer;

begin
	s := '';
  LastX := 1;
  LastSpace := 0;
  Case Measure of
  	mtPixels:
    	begin
      	X := PixelsToInchesHorizontal(Trunc(X)); Y := PixelsToInchesVertical(Trunc(Y));
      end;
    mtMM:
    	begin
      	X := MMToInches(X); Y := MMToInches(Y);
      end;
  end;
  for CurrentX := 0 to Length(Text)-1 do
  begin
  	if Text[CurrentX] = ' ' then
    	LastSpace := CurrentX;
    s := s + Text[CurrentX];
    if GetTextWidthInches(s) > (Y-X) then
    begin
    	s := copy(Text,LastX,LastSpace-LastX);
      theText.Add(s);
      LastX := LastSpace + 1;
      s := '';
    end;
  end;
  if theText.Count = 0 then
  	theText.Add(Text)
  else
  	theText.Add(copy(Text,LastX,length(Text)));
end;

procedure TMWPrintObject.WriteFooter;
   { If any footers are defined, write them }
var
	I: integer;
  Temp: boolean;

begin
	if Not PrintingOK then
  	exit;
	SaveCurrentFont;
   { Set 'AutoPaging' off.  Otherwise the footer will not get written
     correctly. }
  Temp := AutoPaging;
   { Does the user desire a box around the footer? }
  if ( FooterCoordinates.Boxed = True ) then
  begin
  	if ( FooterCoordinates.Shading > 0 ) then
    	DrawBoxShade( FooterCoordinates.XTop,FooterCoordinates.YTop,
      	FooterCoordinates.XBottom,FooterCoordinates.YBottom,
      	FooterCoordinates.LineWidth,FooterCoordinates.Shading)
    else
    	DrawBox( FooterCoordinates.XTop,FooterCoordinates.YTop,
      	FooterCoordinates.XBottom,FooterCoordinates.YBottom,
        FooterCoordinates.LineWidth );
  end;
  AutoPaging := False;
  for I := 1 to FooterLines do
  begin
  	if ( Length(Footer[I].Text) > 0 ) then
    begin
    	with Footer[I] do
      begin
      	SetFontInfo( Font );
        if ( Alignment = 0 ) then
        	WriteLine( FooterCoordinates.XTop, YPosition, Text );
        if ( Alignment = 1 ) then
        	case Measure of
          	mtMM: WriteLine( (FooterCoordinates.XTop + ((FooterCoordinates.XBottom -
            		FooterCoordinates.XTop) / 2)) - PixelsToMMHorizontal(
                TheCanvas.TextWidth(Text) div 2),
                YPosition, Text);
          	mtPixels: WriteLine( Trunc((FooterCoordinates.XTop + ((FooterCoordinates.XBottom -
            		FooterCoordinates.XTop) / 2))) - (TheCanvas.TextWidth(Text) / 2),
                YPosition, Text);
          	mtInches: WriteLine( (FooterCoordinates.XTop + ((FooterCoordinates.XBottom -
            		FooterCoordinates.XTop) / 2)) - PixelsToInchesHorizontal(
                TheCanvas.TextWidth(Text) div 2),
                YPosition, Text);
          end;
        if ( Alignment = 2 ) then
        	case Measure of
          	mtMM: WriteLine( FooterCoordinates.XBottom -
            					PixelsToMMHorizontal(TheCanvas.TextWidth( Text )), YPosition, Text );
            mtPixels: WriteLine( FooterCoordinates.XBottom - TheCanvas.TextWidth( Text ),
            					YPosition, Text );
            mtInches: Writeline( FooterCoordinates.XBottom -
            					PixelsToInchesHorizontal(TheCanvas.TextWidth( Text )), YPosition, Text );
          end;
      end;
    end;
  end;
  RestoreCurrentFont;
  AutoPaging := Temp;
end;

procedure TMWPrintObject.WriteHeader;
   { If any headers are defined, write them }
var
	I: Integer;

begin
	if Not PrintingOK then
  	exit;
   { Does the user desire a box around the header? }
  if ( HeaderCoordinates.Boxed = True ) then
  begin
  	if ( HeaderCoordinates.Shading > 0 ) then
    	DrawBoxShade( HeaderCoordinates.XTop,HeaderCoordinates.YTop,
      	HeaderCoordinates.XBottom,HeaderCoordinates.YBottom,
        HeaderCoordinates.LineWidth,HeaderCoordinates.Shading)
    Else
    	DrawBox( HeaderCoordinates.XTop,HeaderCoordinates.YTop,
      	HeaderCoordinates.XBottom,HeaderCoordinates.YBottom,
        HeaderCoordinates.LineWidth );
  End;
	SaveCurrentFont;
  for I := 1 to HeaderLines do
  begin
  	if ( Length(Header[I].Text) > 0 ) then
    begin
    	with Header[I] do
      begin
      	SetFontInfo( Font );
        if ( Alignment = 0 ) then
        	WriteLine( HeaderCoordinates.XTop, YPosition, Text );
        if ( Alignment = 1 ) then
        	case Measure of
          	mtMM: WriteLine( (HeaderCoordinates.XTop + ((HeaderCoordinates.XBottom -
            		HeaderCoordinates.XTop) / 2)) - PixelsToMMHorizontal(
                TheCanvas.TextWidth(Text) div 2),
                YPosition, Text);
          	mtPixels: WriteLine( Trunc((HeaderCoordinates.XTop + ((HeaderCoordinates.XBottom -
            		HeaderCoordinates.XTop) / 2))) - (TheCanvas.TextWidth(Text) / 2),
                YPosition, Text);
          	mtInches: WriteLine( (HeaderCoordinates.XTop + ((HeaderCoordinates.XBottom -
            		HeaderCoordinates.XTop) / 2)) - PixelsToInchesHorizontal(
                TheCanvas.TextWidth(Text) div 2),
                YPosition, Text);
          end;
        if ( Alignment = 2 ) then
        	case Measure of
          	mtMM: WriteLine( HeaderCoordinates.XBottom -
            					PixelsToMMHorizontal(TheCanvas.TextWidth( Text )), YPosition, Text );
            mtPixels: WriteLine( HeaderCoordinates.XBottom - TheCanvas.TextWidth( Text ),
            					YPosition, Text );
            mtInches: Writeline( HeaderCoordinates.XBottom -
            					PixelsToInchesHorizontal(TheCanvas.TextWidth( Text )), YPosition, Text );
          end;
      end;
    end;
  end;
  RestoreCurrentFont;
End;

procedure TMWPrintObject.WriteLine( X:single; Y:single; Text:string );
   { Write some text.  The parameters represent inches from the left ('X')
     and top ('Y') margins. }
var
	XPixels: integer;
  YPixels: integer;
  oldStyle: TBrushStyle;
  oldColor: TColor;
  oldMeasure: MeasureType;

begin
	if Not PrintingOK then
  	exit;
   { How many pixels are there in the inches represented by 'X'? }
  if DryRun or ImagePrinting then
  	case Measure of
    	mtPixels:
      	begin
        	if X > -0.01 then
        		X := PixelsToInchesHorizontal(Trunc(X));
          if Y > -0.01 then
          	Y := PixelsToInchesVertical(Trunc(Y));
        end;
      mtMM:
      	begin
        	if X > -0.01 then
        		X := MMToInches(X);
          if Y > -0.01 then
          	Y := MMToInches(Y);
        end;
    end;
	if ( X >= 0.0 ) then
  	XPixels := InchesToPixelsHorizontal( X )
  else
  	if ( X = -1 ) then
    	XPixels := InchesToPixelsHorizontal(LastXPosition)
    else
  		XPixels := LeftMargin;
  if ( XPixels < GutterLeft ) then
  	XPixels := GutterLeft;
   { If there is a tab set, increase 'XPixels' by the amount of the tab }
  if ( CurrentTab > 0.0 ) then
  	Inc( XPixels,InchesToPixelsHorizontal(CurrentTab) );
   { How many pixels are there in the inches represented by 'Y'? }
  YPixels := 0;
  if ( Y > -0.01 ) then
   { Printing will occur at an absolute location from the top of the
     page. }
  begin
  	YPixels := InchesToPixelsVertical( Y );
    if ( YPixels < GutterTop ) then
    	YPixels := GutterTop;
    if ( YPixels > TotalPageHeightPixels - GutterBottom) then
    	YPixels := TotalPageHeightPixels - GutterBottom;
    LastYPosition := Y;
  end;
  if ( Y = -1 ) then
   { Write the text at the next line }
  begin
  	if DryRun and ( AutoPaging = True ) then
    begin
     { If the next line we're going to write to exceeds beyond the
       bottom of the detail section, issue a new page }
     	if ( LastYPosition + GetLineHeightInches > (DetailBottom / ScaleByValue)) then
      	NewPage;
    end;
    YPixels := InchesToPixelsVertical( LastYPosition + GetLineHeightInches );
    LastYPosition := LastYPosition + GetLineHeightInches;
  end;
  if ( Y = -2 ) then
   { Write the text on the current line }
  begin
  	if DryRun and ( AutoPaging = True ) then
    begin
     	if ( LastYPosition > (DetailBottom / ScaleByValue)) then
      	NewPage;
    end;
    YPixels := InchesToPixelsVertical( LastYPosition );
  end;
  oldStyle := TheCanvas.Brush.Style;
  oldColor := TheCanvas.Brush.Color;
  if PrintTransparent then
  	TheCanvas.Brush.Style := bsClear
  else
  	TheCanvas.Brush.Style := bsSolid;
  oldMeasure := Measure;
  SetMeasure(mtInches);
  SetYPosition(LastYPosition);
  SetMeasure(oldMeasure);
  LastXPosition := PixelsToInchesHorizontal(Trunc(XPixels/ScaleByValue) + GetTextWidth(Text));
  if not DryRun then
   	TheCanvas.TextOut( XPixels-GutterLeft, YPixels-GutterTop, Text )
  else
  	Pages.StoreText(X,LastYPosition,Text,TheCanvas.Brush.Color);
  TheCanvas.Brush.Style := oldStyle;
  TheCanvas.Brush.Color := oldColor;
end;

procedure TMWPrintObject.WriteLineCenter( Y:single; Text:string );
   { Print a line of text centered at Y inches from the top }
var
	PixelLength: integer;
  StartPixel: integer;

begin
	if Not PrintingOK then
  	exit;
   { How many pixels does the text in 'Text' require? }
	PixelLength := TheCanvas.TextWidth( Text );
   { Calculate where printing should start }
//  StartPixel := ((GutterLeft+(TotalPageWidthPixels-GutterRight)) - PixelLength) div 2;
 	StartPixel := (((RightMargin - LeftMargin) - PixelLength) div 2) + LeftMargin;
  SetTab( 0.0 );
  if DryRun or Imageprinting then
  begin
  	if Measure = mtMM then
    	WriteLine( PixelsToMMHorizontal(StartPixel),Y,Text)
    else if Measure = mtPixels then
    	WriteLine( StartPixel, Y, Text)
  	else WriteLine( PixelsToInchesHorizontal(StartPixel),Y,Text );
  end
  else
  	WriteLine( PixelsToInchesHorizontal(StartPixel),Y,Text );
  SetTab( CurrentTab );
end;

procedure TMWPrintObject.WriteLineColumn( ColumnNumber:word; Y:single; Text:string );
   { Write text, left aligned against the column represented by
     'ColumnInformation[ColumnNumber]' }
begin
	if Not PrintingOK then
  	exit;
  if Measure = mtMM then
  	WriteLine(InchesToMM(ColumnInformation[ColumnNumber].XPosition+0.02),Y,Text)
  else if Measure = mtPixels then
  	WriteLine(InchesToPixelsHorizontal(ColumnInformation[ColumnNumber].XPosition+0.02),Y,Text)
  else
		WriteLine( ColumnInformation[ColumnNumber].XPosition+0.02,Y,Text );
end;

procedure TMWPrintObject.WriteLineColumnArray(Y: single;Cols: array of variant;
																Justif: array of variant;Strings: array of variant;
                                KeepY, SamePage: boolean);
	 { This will allow you to print an array of columns and have them all start
     on the next page if any of them will extend to another page.}
var
	x,w,z: integer;
  oldPage: integer;
  theText: array [0..Columns-1] of TStringList;

begin
{ test to make sure all arrays are same size....}
	if (High(Cols) <> High(Justif)) or (High(Cols) <> High(Strings)) then
  begin
  	ShowMessage('TMWPrintObject Error: array sizes different.');
  	exit;
  end;
  w := 0;
{ Set up a TStringList object for each column we need to print....}
  for x := 0 to High(Cols) do
  begin
  	theText[x] := TStringList.Create;
    WrapText(Strings[x],theText[x],GetColumnLeft(Cols[x]),GetColumnRight(Cols[x]));
    if theText[x].Count > w then
    	w := theText[x].Count;
  end;
  if Y = -1 then
  	NextLine
  else if Y <> -2 then
  	SetYPosition(Y);
  if (w > GetLinesLeft) and SamePage then
  	NewPage;
  if KeepY then
  	SaveCurrentY;
  oldPage := TotalPages;
{ now we need to loop through the columns and print each line....}
  for z := 0 to w-1 do
  begin
  	for x := 0 to High(Cols) do
  	begin
    	if (theText[x].Count > (z + 1)) then
	    	Case Justif[x] of
  	    	0: WriteLineColumn(Cols[x],-2.0,theText[x].Strings[z]);
      		1: WriteLineColumnCenter(Cols[x],-2.0,theText[x].Strings[z]);
	      	2: WriteLineColumnRight(Cols[x],-2.0,theText[x].Strings[z]);
    	  end;
  	end;
    NextLine;
    if Not AutomaticPaging and (GetYPosition + GetLineHeightInches > DetailBottom) then
    	NewPage;
  end;
  if KeepY then
  	if oldPage <> TotalPages then
    	SetTopOfPage
    else
    	RestoreCurrentY;
{ Now clean up the memos we created....}
	for x := 0 to High(Cols) do
  	theText[x].Destroy;
end;

procedure TMWPrintObject.WriteLineColumnCenter( ColumnNumber:word; Y:single; Text:string );
   { Print a line of text centered within the column number represented by
     'ColumnNumber', at Y inches from the top }
var
	PixelLength: Integer;
  StartPixel: Integer;

begin
	if Not PrintingOK then
  	exit;
   { How many pixels does the text in 'Text' require? }
	PixelLength := TheCanvas.TextWidth( Text );
   { Calculate where printing should start }
	 { Pixels := InchesToPixelsHorizontal( ColumnInformation[ColumnNumber].Length );}
  StartPixel := (InchesToPixelsHorizontal( ColumnInformation[ColumnNumber].Length )
  	div 2) + InchesToPixelsHorizontal(ColumnInformation[ColumnNumber].XPosition) -
    (PixelLength div 2);
  SetTab( 0.0 );
  if DryRun or Imageprinting then
  begin
  	if Measure = mtMM then
    	WriteLine( PixelsToMMHorizontal(StartPixel),Y,Text)
    else if Measure = mtPixels then
    	WriteLine( StartPixel, Y, Text)
  	else WriteLine( PixelsToInchesHorizontal(StartPixel),Y,Text );
  end
  else
  	WriteLine( PixelsToInchesHorizontal(StartPixel),Y,Text );
  SetTab( CurrentTab );
end;

procedure TMWPrintObject.WriteLineColumnRight( ColumnNumber:word; Y:single; Text:string );
   { Write text, right aligned against the column represented by
     'ColumnInformation[ColumnNumber]' }
var
	PixelLength: word;
  StartPixel: word;

begin
	if Not PrintingOK then
  	exit;
   { How many pixels does the text in 'Text' require? }
	PixelLength := TheCanvas.TextWidth( Text );
   { Calculate where printing should start }
  StartPixel := InchesToPixelsHorizontal( ColumnInformation[ColumnNumber].XPosition +
  	ColumnInformation[ColumnNumber].Length ) - PixelLength;
  SetTab( 0.0 );
  if DryRun or Imageprinting then
  begin
  	if Measure = mtMM then
    	WriteLine( PixelsToMMHorizontal(StartPixel)-InchesToMM(0.02),Y,Text)
    else if Measure = mtPixels then
    	WriteLine( StartPixel, Y, Text)
  	else WriteLine( PixelsToInchesHorizontal(StartPixel) - 0.02,Y,Text );
  end
  else
  	WriteLine( PixelsToInchesHorizontal(StartPixel) - 0.02,Y,Text );
  SetTab( CurrentTab );
end;

procedure TMWPrintObject.WriteLineColumnWrap(ColumnNumber:word; Y:single;
																						Text:string; KeepY,SamePage:boolean);
   { Word wrap text in a given column starting at Y inches from the top }
begin
	if Not PrintingOK then
  	exit;
	WriteLineWrap(GetColumnLeft(ColumnNumber),GetColumnRight(ColumnNumber),
  							Y,Text,KeepY,SamePage);
end;

procedure TMWPrintObject.WriteLineRight( Y:single; Text:string );
   { Print a line of text right justified 'Y' inches from the top }
var
	PixelLength: word;
  StartPixel: word;

begin
	if Not PrintingOK then
  	exit;
   { How many pixels does the text in 'Text' require? }
	PixelLength := TheCanvas.TextWidth( Text );
   { Calculate where printing should start }
  StartPixel := RightMargin - PixelLength;
  SetTab( 0.0 );
  if DryRun or Imageprinting then
  begin
  	if Measure = mtMM then
    	WriteLine( PixelsToMMHorizontal(StartPixel),Y,Text)
    else if Measure = mtPixels then
    	WriteLine( StartPixel, Y, Text)
  	else WriteLine( PixelsToInchesHorizontal(StartPixel),Y,Text );
  end
  else
  	WriteLine( PixelsToInchesHorizontal(StartPixel),Y,Text );
  SetTab( CurrentTab );
end;

procedure TMWPrintObject.WriteLineWrap(XL,XR,Y:single; Text:string; KeepY,SamePage: boolean);
	 { Word wrap text within the bounds set by XR and XL at Y inches from top }
var
  x: integer;
  theText: TStringList;

begin
	if Not PrintingOK then
  	exit;
	theText := TStringList.Create;
  WrapText(Text,theText,XL,XR);
  { remove excess blank lines on bottom if any..}
  while (theText.Count > 0) and (trim(theText.Strings[theText.Count-1]) = '') do
  	theText.Delete(theText.Count-1);
  if KeepY then
  	SaveCurrentY;
	if (Y = -1.0) then
	begin
		NextLine;
	end
  else if (Y <> -2.0) then
  	SetYPosition(Y);
  if SamePage and (theText.Count > GetLinesLeft) then
  begin
    RestoreCurrentY;
  	NewPage;
    SaveCurrentY;
  end;
  for x := 0 to theText.Count-1 do
  begin
  	WriteLine(XL,-2.0,theText.Strings[x]);
    if x < theText.Count-1 then
    	NextLine;
  end;
  theText.Free;
  if KeepY then
  	RestoreCurrentY;
end;

procedure TMWPrintObject.WritePageNumber;
{ Print the current page number on page if page numbering is set }
var
	Buffer: string;
  Temp: boolean;

begin
	if Not PrintingOK then
  	exit;
	if Not PageNumbering  or (PageNumber.Text = '') then
  	exit;
  try
		if PreviewMode then
  		Buffer := Format( PageNumber.Text,[PreviewForm.GetPageNumber] )
  	else
  		Buffer := Format( PageNumber.Text,[Printer.PageNumber] );
  except
  	ShowMessage('Error in page number formatting.');
    exit;
  end;
  if PageNumber.ShowTotalPages then
  	Buffer := Buffer + ' of ' + IntToStr(TotalPages);
  SaveCurrentFont;
  SetFontInfo( PageNumber.Font );
  Temp := AutoPaging;
	SetAutoPaging(false);
	if DryRun then
  	Pages.StoreGeneral(commWritePage);
  if ( PageNumber.Alignment = 0 ) then
  		WriteLine( PixelsToInchesHorizontal(LeftMargin), PageNumber.YPosition, Buffer );
  if ( PageNumber.Alignment = 1 ) then
  	WriteLineCenter( PageNumber.YPosition, Buffer );
  if ( PageNumber.Alignment = 2 ) then
  	WriteLineRight( PageNumber.YPosition, Buffer );
  SetAutoPaging(temp);
  RestoreCurrentFont;
end;

procedure TMWPrintObject.WritePrinterSpecs(RestoreState: boolean);
var
	MyHandle: THandle;
  MyDevMode: pDevMode;
  MyDevice,
  MyDriver,
  MyPort: array [0..255] of char;

begin
	if Not (PrintingOK or RestoreState) then
  	exit;
	Printer.GetPrinter(MyDevice,MyDriver,MyPort,MyHandle);
  MyDevMode := GlobalLock(MyHandle);
  try
  	MyDevMode^.dmFields := MyDevMode^.dmFields or (DM_PAPERSIZE or DM_ORIENTATION);
    if Not RestoreState then
    begin
    	MyDevMode^.dmPaperSize := ord(PaperSize)+1;
    	if Orientation = poLandscape then
    		MyDevMode^.dmOrientation := DMORIENT_LANDSCAPE
    	else
    		MyDevMode^.dmOrientation := DMORIENT_PORTRAIT;
    end
    else
    begin
    	MyDevMode^.dmPaperSize := OrigPaperSize;
      MyDevMode^.dmOrientation := OrigPaperOrient;
    end;
    Printer.SetPrinter(MyDevice,MyDriver,MyPort,MyHandle);
  finally
  	GlobalUnLock(MyHandle);
  end;
end;

function TMWPrintObject.MMToInches(mm: single): single;
begin
	result := (mm / 25.4);
end;

function TMWPrintObject.InchesToMM(inches: single): single;
begin
	result := (inches * 25.4);
end;

procedure TMWPrintObject.GetPrinterSpecs;
var
	oldOK: boolean;

begin
	oldOK := PrintingOK;
	PrintingOK := true;
  ReadPrinterSpecs(false);
  PrintingOK := oldOK;
end;

procedure TMWPrintObject.SetPrinterSpecs;
var
	oldOK: boolean;

begin
	oldOK := PrintingOK;
	PrintingOK := true;
  WritePrinterSpecs(false);
  PrintingOK := oldOK;
end;

procedure TMWPrintObject.SetMeasure(Meas: MeasureType);
begin
	if DryRun then
  	Pages.StoreMeasure(ord(Meas));
  Measurement := Meas;
end;

end.

