lazarus/components/turbopower_ipro/iphtmlpv.pas
2016-04-02 08:36:20 +00:00

466 lines
12 KiB
ObjectPascal

{******************************************************************}
{* IPHTMLPV.PAS - HTML Browser Print Preview *}
{******************************************************************}
(* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is TurboPower Internet Professional
*
* The Initial Developer of the Original Code is
* TurboPower Software
*
* Portions created by the Initial Developer are Copyright (C) 2000-2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** *)
{ Global defines potentially affecting this unit }
{$I IPDEFINE.INC}
unit IpHtmlPv;
{$IFNDEF Html_Print}
{$ERROR requires -dHTML_Print}
{$ENDIF}
interface
uses
{$IFDEF IP_LAZARUS}
LCLType,
GraphType,
LCLIntf,
Buttons,
{$ELSE}
Windows,
{$ENDIF}
Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, Spin, IpHtml;
resourcestring
rsIpHTMLPreviewPrintPreview = 'Print preview';
rsIpHTMLPreviewPrint = 'Print';
rsIpHTMLPreviewZoom = 'Zoom:';
rsIpHTMLPreviewClose = 'Close';
rsIpHTMLPreviewFitAll = 'Fit all';
rsIpHTMLPreviewFitWidth = 'Width';
rsIpHTMLPreviewFitHeight = 'Height';
rsIpHTMLPreviewPage = 'Page:';
rsIpHTMLPreviewOf = 'of';
rsIpHTMLPreviewSelectPrinter = 'Select printer ...';
type
{ TIpHTMLPreview }
TIpHTMLPreview = class(TForm)
btnFitHeight: TButton;
btnFitWidth: TButton;
btnFit: TButton;
btnSelectPrinter: TButton;
Label3: TLabel;
PaperPanel: TPanel;
PaintBox1: TPaintBox;
edtZoom: TSpinEdit;
ToolbarPanel: TPanel;
btnPrint: TButton;
btnFirst: TButton;
btnPrev: TButton;
btnNext: TButton;
btnLast: TButton;
btnClose: TButton;
edtPage: TEdit;
Label1: TLabel;
Label2: TLabel;
lblMaxPage: TLabel;
ScrollBox1: TScrollBox;
procedure btnFirstClick(Sender: TObject);
procedure btnFitClick(Sender: TObject);
procedure btnFitHeightClick(Sender: TObject);
procedure btnFitWidthClick(Sender: TObject);
procedure btnLastClick(Sender: TObject);
procedure btnNextClick(Sender: TObject);
procedure btnPrevClick(Sender: TObject);
procedure btnPrintClick(Sender: TObject);
procedure btnSelectPrinterClick(Sender: TObject);
procedure edtPageChange(Sender: TObject);
procedure edtZoomChange(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure PaintBox1Paint(Sender: TObject);
private
SourceRect: TRect;
Scratch: TBitmap;
FScale: double;
FZoom: Integer;
FZoomToFit: Integer;
FLockZoomUpdate: Integer;
procedure SetCurPage(const Value: Integer);
procedure SetZoom(const Value: Integer);
protected
procedure AlignPaintBox;
procedure Render;
procedure ResizeCanvas;
// procedure ScaleSourceRect;
procedure UpdateBtnStates;
public
FCurPage: Integer;
HTML : TIpHtml;
PageRect: TRect;
OwnerPanel: TIpHtmlInternalPanel;
procedure RenderPage(PageNo: Integer);
property CurPage: Integer read FCurPage write SetCurPage;
property Scale: double read FScale;
property Zoom: Integer read FZoom write SetZoom;
end;
implementation
uses
Printers;
{$IFNDEF IP_LAZARUS}
{$R *.DFM}
{$ELSE}
{$R *.lfm}
{$ENDIF}
const
SCRATCH_WIDTH = 800; //640;
SCRATCH_HEIGHT = 600; //480;
ZOOM_FACTOR = 1.1;
function ScaleRect(ARect: TRect; AFactor: Double): TRect;
begin
Result.Left := round(ARect.Left * AFactor);
Result.Top := round(ARect.Top * AFactor);
Result.Right := round(ARect.Right * AFactor);
Result.Bottom := round(ARect.Bottom * AFactor);
end;
procedure TIpHTMLPreview.AlignPaintBox;
var
sb: Integer;
begin
sb := GetSystemMetrics(SM_CXVSCROLL);
if PaperPanel.Width < ClientWidth - sb then
PaperPanel.Left := (ClientWidth - sb - PaperPanel.Width) div 2
else
PaperPanel.Left := 0;
sb := GetSystemMetrics(SM_CXHSCROLL);
if PaperPanel.Height < ClientHeight - sb - ToolbarPanel.Height then
PaperPanel.Top := (ClientHeight - sb - ToolbarPanel.Height - PaperPanel.Height) div 2
else
PaperPanel.Top := 0;
end;
procedure TIpHTMLPreview.btnFirstClick(Sender: TObject);
begin
CurPage := 1;
end;
procedure TIpHTMLPreview.btnFitClick(Sender: TObject);
begin
SetZoom(ZOOM_TO_FIT);
end;
procedure TIpHTMLPreview.btnFitHeightClick(Sender: TObject);
begin
SetZoom(ZOOM_TO_FIT_HEIGHT);
end;
procedure TIpHTMLPreview.btnFitWidthClick(Sender: TObject);
begin
SetZoom(ZOOM_TO_FIT_WIDTH);
end;
procedure TIpHTMLPreview.btnLastClick(Sender: TObject);
begin
CurPage := OwnerPanel.PageCount;
end;
procedure TIpHTMLPreview.btnNextClick(Sender: TObject);
begin
CurPage := CurPage + 1;
end;
procedure TIpHTMLPreview.btnPrevClick(Sender: TObject);
begin
CurPage := CurPage - 1;
end;
procedure TIpHTMLPreview.btnSelectPrinterClick(Sender: TObject);
begin
if OwnerPanel <> nil then
if OwnerPanel.SelectPrinterDlg then
SetZoom(Zoom); {force recalc of preview sizes}
end;
procedure TIpHTMLPreview.btnPrintClick(Sender: TObject);
begin
Screen.Cursor := crHourglass;
ScaleFonts := False;
try
OwnerPanel.PrintPages(1, OwnerPanel.PageCount);
finally
ScaleFonts := True;
Screen.Cursor := crDefault;
Close;
end;
end;
procedure TIpHTMLPreview.edtPageChange(Sender: TObject);
begin
CurPage := StrToInt(edtPage.Text);
end;
procedure TIpHTMLPreview.edtZoomChange(Sender: TObject);
var
newZoom: Double;
begin
if (FLockZoomUpdate = 0) and TryStrToFloat(edtZoom.Text, newZoom) then
SetZoom(Round(newZoom));
end;
procedure TIpHTMLPreview.FormCreate(Sender: TObject);
begin
FZoom := 100;
FZoomToFit := ZOOM_TO_FIT;
Scratch := TBitmap.Create;
Scratch.Width := SCRATCH_WIDTH;
Scratch.Height := SCRATCH_HEIGHT;
// localization
Self.Caption := rsIpHTMLPreviewPrintPreview;
btnPrint.Caption := rsIpHTMLPreviewPrint;
Label3.Caption := rsIpHTMLPreviewZoom;
btnClose.Caption := rsIpHTMLPreviewClose;
Label1.Caption := rsIpHTMLPreviewPage;
Label2.Caption := rsIpHTMLPreviewOf;
btnSelectPrinter.Caption := rsIpHTMLPreviewSelectPrinter;
btnFit.Caption := rsIpHTMLPreviewFitAll;
btnFitWidth.Caption := rsIpHTMLPreviewFitWidth;
btnFitHeight.Caption := rsIpHTMLPreviewFitHeight;
end;
procedure TIpHTMLPreview.FormDestroy(Sender: TObject);
begin
Scratch.Free;
end;
procedure TIpHTMLPreview.FormResize(Sender: TObject);
begin
if (FZoomToFit <= 0) and (OwnerPanel <> nil) then
SetZoom(FZoomToFit) {force recalc of preview sizes}
else
AlignPaintbox;
end;
procedure TIpHTMLPreview.FormShow(Sender: TObject);
begin
UpdateBtnStates;
RenderPage(CurPage);
end;
procedure TIpHTMLPreview.PaintBox1Paint(Sender: TObject);
begin
SourceRect := ScaleRect(PaintBox1.Canvas.ClipRect, 1.0/Scale);
OffsetRect(SourceRect, 0, PageRect.Top);
Render;
end;
procedure TIpHTMLPreview.Render;
var
TileTop, TileLeft,
WindowTop, WindowLeft: Integer;
R, Rscr: TRect;
begin
{GDI won't let us create a bitmap for a whole page
since it would become too big for large resolutions,
so we have to do banding by hand}
Screen.Cursor := crHourglass;
try
Application.ProcessMessages;
PaintBox1.Canvas.Brush.Color := clWhite;
PaintBox1.Canvas.FillRect(PaintBox1.Canvas.ClipRect);
PaintBox1.Canvas.AntialiasingMode := OwnerPanel.PreviewAntiAliasingMode;
WindowTop := SourceRect.Top;
TileTop := 0;
while WindowTop < SourceRect.Bottom do begin
WindowLeft := SourceRect.Left;
TileLeft := 0;
while WindowLeft < SourceRect.Right do begin
R.Left := WindowLeft;
R.Top := WindowTop;
R.Right := R.Left + SCRATCH_WIDTH + 1;
R.Bottom := R.Top + SCRATCH_HEIGHT + 1;
Rscr := R;
if R.Bottom - SourceRect.Top > OwnerPanel.PrintHeight then begin
Scratch.Canvas.FillRect(0, 0, R.Right-R.Left, R.Bottom-R.Top);
R.Bottom := SourceRect.Top + OwnerPanel.PrintHeight;
end;
HTML.Render(Scratch.Canvas, R, PageRect.Top, PageRect.Bottom, False, Point(0, 0));
OffsetRect(RScr, 0, -PageRect.Top);
Rscr := ScaleRect(Rscr, Scale);
PaintBox1.Canvas.StretchDraw(Rscr, Scratch);
inc(WindowLeft, SCRATCH_WIDTH);
inc(TileLeft, SCRATCH_WIDTH);
end;
inc(WindowTop, SCRATCH_HEIGHT);
inc(TileTop, SCRATCH_HEIGHT);
end;
finally
Screen.Cursor := crDefault;
end;
(*
This is an untiled version ...
var
R: TRect;
begin
// Render to single "scratch" bitmap which has the original print size and
// then is stretch-drawn into the preview paintbox.
Screen.Cursor := crHourglass;
try
Application.ProcessMessages;
Paintbox1.Canvas.Brush.Color := clWhite;
Paintbox1.Canvas.FillRect(Paintbox1.Canvas.ClipRect);
PaintBox1.Canvas.AntialiasingMode := OwnerPanel.PreviewAntiAliasingMode;
Scratch.Clear;
Scratch.Width := SourceRect.Right - SourceRect.Left;
Scratch.Height := SourceRect.Bottom - SourceRect.Top;
// probably not needed
Scratch.Canvas.Brush.Color := clWhite;
Scratch.Canvas.FillRect(SourceRect);
HTML.Render(Scratch.Canvas, SourceRect, PageRect.Top, PageRect.Bottom, False, Point(0, 0));
R := Paintbox1.Canvas.ClipRect;
PaintBox1.Canvas.StretchDraw(R, Scratch);
finally
Screen.Cursor := crDefault;
end;
*)
end;
procedure TIpHTMLPreview.RenderPage(PageNo: Integer);
var
CR : TRect;
begin
CR := Rect(0, 0, OwnerPanel.PrintWidth, 0);
CR.Top := (PageNo - 1) * OwnerPanel.PrintHeight;
CR.Bottom := Cr.Top + OwnerPanel.PrintHeight;
PageRect := CR;
PaintBox1.Invalidate;
end;
procedure TIpHTMLPreview.ResizeCanvas;
begin
ScrollBox1.HorzScrollBar.Position := 0;
ScrollBox1.VertScrollBar.Position := 0;
{$IFDEF IP_LAZARUS}
if Printer.PageHeight > 0 then
PaperPanel.Height := round(Printer.PageHeight * Scale)
else
PaperPanel.Height := round(500 * Scale);
if Printer.PageWidth > 0 then
PaperPanel.Width := round(Printer.PageWidth * Scale)
else
PaperPanel.Width := round(500 * Scale);
{$ELSE}
PaperPanel.Width := round(Printer.PageWidth * Scale);
PaperPanel.Height := round(Printer.PageHeight * Scale);
{$ENDIF}
PaintBox1.Left := round(OwnerPanel.PrintTopLeft.x * Scale);
PaintBox1.Top := round(OwnerPanel.PrintTopLeft.y * Scale);
Paintbox1.Width := PaperPanel.Width - Paintbox1.Left;
Paintbox1.Height := PaperPanel.Height - Paintbox1.top;
AlignPaintBox;
end;
procedure TIpHTMLPreview.SetCurPage(const Value: Integer);
begin
if (Value <> FCurPage) and (Value >= 1) and (Value <= OwnerPanel.PageCount) then
begin
FCurPage := Value;
RenderPage(Value);
edtPage.Text := IntToStr(CurPage);
UpdateBtnStates;
end;
end;
procedure TIpHTMLPreview.SetZoom(const Value: Integer);
var
ClientHeightDbl, ClientWidthDbl: Double;
PrnPgHeight, PrnPgWidth: Double;
scaleW, scaleH: Integer;
sb: Integer;
begin
FZoomToFit := Value;
// Available client area in inches, without scrollbars
sb := GetSystemMetrics(SM_CXHSCROLL);
ClientHeightDbl := (ClientHeight - sb - ToolbarPanel.Height) / ScreenInfo.PixelsPerInchY;
sb := GetSystemMetrics(SM_CXVSCROLL);
ClientWidthDbl := (ClientWidth - sb)/ ScreenInfo.PixelsPerInchX;
// Printer page size in inches
PrnPgHeight := Printer.PageHeight / Printer.YDpi;
PrnPgWidth := Printer.PageWidth / Printer.XDpi;
case Value of
ZOOM_TO_FIT:
begin
scaleW := round(ClientWidthDbl / PrnPgWidth * 100);
scaleH := round(ClientHeightDbl / PrnPgHeight * 100);
if scaleW < scaleH then FZoom := scaleW else FZoom := scaleH;
end;
ZOOM_TO_FIT_WIDTH:
FZoom := round(ClientWidthDbl / PrnPgWidth * 100);
ZOOM_TO_FIT_HEIGHT:
FZoom := round(ClientHeightDbl / PrnPgHeight * 100);
else
FZoom := Value;
end;
inc(FLockZoomUpdate);
edtZoom.Value := FZoom;
dec(FLockZoomUpdate);
FScale := ScreenInfo.PixelsPerInchX / Printer.XDpi * FZoom * 0.01;
ResizeCanvas;
end;
procedure TIpHtmlPreview.UpdateBtnStates;
begin
btnFirst.Enabled := (FCurPage > 1);
btnPrev.Enabled := (FCurPage > 1);
btnNext.Enabled := (FCurPage < OwnerPanel.PageCount);
btnLast.Enabled := (FCurPage < OwnerPanel.PageCount);
end;
end.