mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-07 14:58:09 +02:00
466 lines
12 KiB
ObjectPascal
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.
|