{------------------------------------------------------------------------------- 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: SynEditPrintPreview.pas, released 2000-06-01. The Initial Author of the Original Code is Morten J. Skovrup. Portions written by Morten J. Skovrup are copyright 2000 Morten J. Skovrup. Portions written by Michael Hieke are copyright 2000 Michael Hieke. Unicode translation by Maël Hörz. All Rights Reserved. Contributors to the SynEdit project are listed in the Contributors.txt file. Alternatively, the contents of this file may be used under the terms of the GNU General Public License Version 2 or later (the "GPL"), in which case the provisions of the GPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the GPL. $Id: SynEditPrintPreview.pas,v 1.18.2.2 2008/09/14 16:24:59 maelh Exp $ You may retrieve the latest version of this file at the SynEdit home page, located at http://SynEdit.SourceForge.net Known Issues: -------------------------------------------------------------------------------} {------------------------------------------------------------------------------- CONTENTS: Print preview component. Allmost identical to code developed by Michael Hieke. It is important to call UpdatePreview whenever things change (i.e. just before the preview is shown, and when the printer is changed) -------------------------------------------------------------------------------} {$IFNDEF QSYNEDITPRINTPREVIEW} unit SynEditPrintPreview; {$ENDIF} {$I SynEdit.inc} {$M+} interface uses {$IFDEF SYN_COMPILER_7} Themes, {$ENDIF} {$IFDEF SYN_COMPILER_17_UP} Types, {$ENDIF} Windows, Controls, Messages, Graphics, Forms, SynEditPrint, Classes, SysUtils; type //Event raised when page is changed in preview TPreviewPageEvent = procedure(Sender: TObject; PageNumber: Integer) of object; TSynPreviewScale = (pscWholePage, pscPageWidth, pscUserScaled); {$IFNDEF SYN_COMPILER_4_UP} TWMMouseWheel = record Msg: Cardinal; Keys: SmallInt; WheelDelta: SmallInt; case Integer of 0: ( XPos: Smallint; YPos: Smallint); 1: ( Pos: TSmallPoint; Result: Longint); end; {$ENDIF} TSynEditPrintPreview = class(TCustomControl) protected FBorderStyle: TBorderStyle; FSynEditPrint: TSynEditPrint; FScaleMode: TSynPreviewScale; FScalePercent: Integer; // these are in pixels ( = screen device units) FVirtualSize: TPoint; FVirtualOffset: TPoint; FPageSize: TPoint; FScrollPosition: TPoint; FPageBG: TColor; FPageNumber: Integer; FShowScrollHint: Boolean; FOnPreviewPage: TPreviewPageEvent; FOnScaleChange: TNotifyEvent; // JD 2002-01-9 FWheelAccumulator: Integer; procedure SetBorderStyle(Value: TBorderStyle); procedure SetPageBG(Value: TColor); procedure SetSynEditPrint(Value: TSynEditPrint); procedure SetScaleMode(Value: TSynPreviewScale); procedure SetScalePercent(Value: Integer); private procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; procedure WMHScroll(var Msg: TWMHScroll); message WM_HSCROLL; procedure WMSize(var Msg: TWMSize); message WM_SIZE; procedure WMVScroll(var Msg: TWMVScroll); message WM_VSCROLL; procedure WMMouseWheel(var Message: TWMMouseWheel); message {$IFDEF SYN_COMPILER_3_UP} WM_MOUSEWHEEL {$ELSE} $020A {$ENDIF}; procedure PaintPaper; function GetPageCount: Integer; protected procedure CreateParams(var Params: TCreateParams); override; function GetPageHeightFromWidth(AWidth: Integer): Integer; function GetPageHeight100Percent: Integer; function GetPageWidthFromHeight(AHeight: Integer): Integer; function GetPageWidth100Percent: Integer; procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure ScrollHorzFor(Value: Integer); procedure ScrollHorzTo(Value: Integer); virtual; procedure ScrollVertFor(Value: Integer); procedure ScrollVertTo(Value: Integer); virtual; procedure UpdateScrollbars; virtual; procedure SizeChanged; virtual; public constructor Create(AOwner: TComponent); override; procedure Paint; override; procedure UpdatePreview; procedure NextPage; procedure PreviousPage; procedure FirstPage; procedure LastPage; procedure Print; property PageNumber: Integer read FPageNumber; property PageCount: Integer read GetPageCount; published property Align default alClient; property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle; property Color default clAppWorkspace; property Cursor; property PageBGColor: TColor read FPageBG write SetPageBG default clWhite; property PopupMenu; // JD 2002-01-9 property SynEditPrint: TSynEditPrint read FSynEditPrint write SetSynEditPrint; property ScaleMode: TSynPreviewScale read FScaleMode write SetScaleMode default pscUserScaled; property ScalePercent: Integer read FScalePercent write SetScalePercent default 100; property Visible default True; property ShowScrollHint: Boolean read FShowScrollHint write FShowScrollHint default True; property OnClick; property OnMouseDown; property OnMouseUp; property OnPreviewPage: TPreviewPageEvent read FOnPreviewPage write FOnPreviewPage; property OnScaleChange: TNotifyEvent read FOnScaleChange // JD 2002-01-9 write FOnScaleChange; // JD 2002-01-9 end; implementation uses SynEditStrConst; const MARGIN_X = 12; // margin width left and right of page MARGIN_Y = 12; // margin height above and below page SHADOW_SIZE = 2; // page shadow width { TSynEditPrintPreview } constructor TSynEditPrintPreview.Create(AOwner: TComponent); begin inherited; {$IFDEF SYN_COMPILER_7_UP} ControlStyle := ControlStyle + [csNeedsBorderPaint]; {$ENDIF} FBorderStyle := bsSingle; FScaleMode := pscUserScaled; FScalePercent := 100; FPageBG := clWhite; Width := 200; Height := 120; ParentColor := False; Color := clAppWorkspace; Visible := True; FPageNumber := 1; FShowScrollHint := True; Align := alClient; FWheelAccumulator := 0; end; procedure TSynEditPrintPreview.CreateParams(var Params: TCreateParams); const BorderStyles: array[TBorderStyle] of DWord = (0, WS_BORDER); begin inherited; with Params do begin Style := Style or WS_HSCROLL or WS_VSCROLL or BorderStyles[FBorderStyle] or WS_CLIPCHILDREN; if NewStyleControls and Ctl3D and (FBorderStyle = bsSingle) then begin Style := Style and not WS_BORDER; ExStyle := ExStyle or WS_EX_CLIENTEDGE; end; end; end; function TSynEditPrintPreview.GetPageHeightFromWidth(AWidth: Integer): Integer; begin if Assigned(FSynEditPrint) then begin with FSynEditPrint.PrinterInfo do Result := MulDiv(AWidth, PhysicalHeight, PhysicalWidth); end else Result := MulDiv(AWidth, 141, 100); // fake A4 size end; function TSynEditPrintPreview.GetPageWidthFromHeight(AHeight: Integer): Integer; begin if Assigned(FSynEditPrint) then begin with FSynEditPrint.PrinterInfo do Result := MulDiv(AHeight, PhysicalWidth, PhysicalHeight); end else Result := MulDiv(AHeight, 100, 141); // fake A4 size end; function TSynEditPrintPreview.GetPageHeight100Percent: Integer; var DC: HDC; ScreenDPI: Integer; begin Result := 0; DC := GetDC(0); ScreenDPI := GetDeviceCaps(DC, LogPixelsY); ReleaseDC(0, DC); if Assigned(FSynEditPrint) then with FSynEditPrint.PrinterInfo do Result := MulDiv(PhysicalHeight, ScreenDPI, YPixPrInch); end; function TSynEditPrintPreview.GetPageWidth100Percent: Integer; var DC: HDC; ScreenDPI: Integer; begin Result := 0; DC := GetDC(0); ScreenDPI := GetDeviceCaps(DC, LogPixelsX); ReleaseDC(0, DC); if Assigned(FSynEditPrint) then with FSynEditPrint.PrinterInfo do Result := MulDiv(PhysicalWidth, ScreenDPI, XPixPrInch); end; procedure TSynEditPrintPreview.Notification(AComponent: TComponent; Operation: TOperation); begin inherited; if (Operation = opRemove) and (AComponent = FSynEditPrint) then SynEditPrint := nil; end; procedure TSynEditPrintPreview.PaintPaper; var rcClip, rcPaper: TRect; rgnPaper: HRGN; i: Integer; begin with Canvas do begin // we work in MM_TEXT mapping mode here... rcClip := ClipRect; if IsRectEmpty(rcClip) then Exit; Brush.Color := Self.Color; Brush.Style := bsSolid; Pen.Color := clBlack; Pen.Width := 1; Pen.Style := psSolid; if (csDesigning in ComponentState) or (not Assigned(FSynEditPrint)) then begin FillRect(rcClip); Brush.Color := FPageBG; Rectangle(MARGIN_X, MARGIN_Y, MARGIN_X + 30, MARGIN_Y + 43); Exit; end; // fill background around paper with rcPaper do begin Left := FVirtualOffset.X + FScrollPosition.X; if ScaleMode = pscWholePage then Top := FVirtualOffset.Y else Top := FVirtualOffset.Y + FScrollPosition.Y; Right := Left + FPageSize.X; Bottom := Top + FPageSize.Y; rgnPaper := CreateRectRgn(Left, Top, Right + 1, Bottom + 1); end; if (NULLREGION <> ExtSelectClipRgn(Handle, rgnPaper, RGN_DIFF)) then FillRect(rcClip); // paper shadow Brush.Color := clDkGray; with rcPaper do begin for i := 1 to SHADOW_SIZE do PolyLine([Point(Left + i, Bottom + i), Point(Right + i, Bottom + i), Point(Right + i, Top + i)]); end; // paint paper background SelectClipRgn(Handle, rgnPaper); Brush.Color := FPageBG; with rcPaper do Rectangle(Left, Top, Right + 1, Bottom + 1); DeleteObject(rgnPaper); end; end; procedure TSynEditPrintPreview.Paint; var ptOrgScreen: TPoint; begin with Canvas do begin PaintPaper; if (csDesigning in ComponentState) or (not Assigned(FSynEditPrint)) then Exit; // paint the contents, clipped to the area inside of the print margins // correct scaling for output: SetMapMode(Handle, MM_ANISOTROPIC); // compute the logical point (0, 0) in screen pixels with FSynEditPrint.PrinterInfo do begin SetWindowExtEx(Handle, PhysicalWidth, PhysicalHeight, nil); SetViewPortExtEx(Handle, FPageSize.X, FPageSize.Y, nil); ptOrgScreen.X := MulDiv(LeftGutter, FPageSize.X, PhysicalWidth); ptOrgScreen.Y := MulDiv(TopGutter, FPageSize.Y, PhysicalHeight); Inc(ptOrgScreen.X, FVirtualOffset.X + FScrollPosition.X); if ScaleMode = pscWholePage then Inc(ptOrgScreen.Y, FVirtualOffset.Y) else Inc(ptOrgScreen.Y, FVirtualOffset.Y + FScrollPosition.Y); SetViewPortOrgEx(Handle, ptOrgScreen.X, ptOrgScreen.Y, nil); // clip the output to the print margins IntersectClipRect(Handle, 0, 0, PrintableWidth, PrintableHeight); end; FSynEditPrint.PrintToCanvas(Canvas, FPageNumber); end; end; procedure TSynEditPrintPreview.ScrollHorzFor(Value: Integer); begin ScrollHorzTo(FScrollPosition.X + Value); end; procedure TSynEditPrintPreview.ScrollHorzTo(Value: Integer); var nW, n: Integer; begin nW := ClientWidth; n := nW - FVirtualSize.X; if (Value < n) then Value := n; if (Value > 0) then Value := 0; if (Value <> FScrollPosition.X) then begin n := Value - FScrollPosition.X; FScrollPosition.X := Value; UpdateScrollbars; if (Abs(n) > nW div 2) then Invalidate else begin ScrollWindow(Handle, n, 0, nil, nil); Update; end; end; end; procedure TSynEditPrintPreview.ScrollVertFor(Value: Integer); begin ScrollVertTo(FScrollPosition.Y + Value); end; procedure TSynEditPrintPreview.ScrollVertTo(Value: Integer); var nH, n: Integer; begin nH := ClientHeight; n := nH - FVirtualSize.Y; if (Value < n) then Value := n; if (Value > 0) then Value := 0; if (Value <> FScrollPosition.Y) then begin n := Value - FScrollPosition.Y; FScrollPosition.Y := Value; UpdateScrollbars; if (Abs(n) > nH div 2) then Invalidate else begin ScrollWindow(Handle, 0, n, nil, nil); Update; end; end; end; procedure TSynEditPrintPreview.SizeChanged; var nWDef: Integer; begin if not (HandleAllocated and Assigned(FSynEditPrint)) then Exit; // compute paper size case fScaleMode of pscWholePage: begin FPageSize.X := ClientWidth - 2 * MARGIN_X - SHADOW_SIZE; FPageSize.Y := ClientHeight - 2 * MARGIN_Y - SHADOW_SIZE; nWDef := GetPageWidthFromHeight(FPageSize.Y); if (nWDef < FPageSize.X) then FPageSize.X := nWDef else FPageSize.Y := GetPageHeightFromWidth(FPageSize.X); end; pscPageWidth: begin FPageSize.X := ClientWidth - 2 * MARGIN_X - SHADOW_SIZE; FPageSize.Y := GetPageHeightFromWidth(FPageSize.X); end; pscUserScaled: begin FPageSize.X := MulDiv(GetPageWidth100Percent, fScalePercent, 100); FPageSize.Y := MulDiv(GetPageHeight100Percent, fScalePercent, 100); end; end; FVirtualSize.X := FPageSize.X + 2 * MARGIN_X + SHADOW_SIZE; FVirtualSize.Y := FPageSize.Y + 2 * MARGIN_Y + SHADOW_SIZE; FVirtualOffset.X := MARGIN_X; if (FVirtualSize.X < ClientWidth) then Inc(FVirtualOffset.X, (ClientWidth - FVirtualSize.X) div 2); FVirtualOffset.Y := MARGIN_Y; if (FVirtualSize.Y < ClientHeight) then Inc(FVirtualOffset.Y, (ClientHeight - FVirtualSize.Y) div 2); UpdateScrollbars; // TODO FScrollPosition.X := 0; FScrollPosition.Y := 0; end; procedure TSynEditPrintPreview.UpdateScrollbars; var si: TScrollInfo; begin FillChar(si, SizeOf(TScrollInfo), 0); si.cbSize := SizeOf(TScrollInfo); si.fMask := SIF_ALL; case FScaleMode of pscWholePage: begin // hide horizontal scrollbar ShowScrollbar(Handle, SB_HORZ, False); // show vertical scrollbar, enable if more than one page si.fMask := si.fMask or SIF_DISABLENOSCROLL; si.nMin := 1; if Assigned(FSynEditPrint) then begin si.nMax := FSynEditPrint.PageCount; si.nPos := FPageNumber; end else begin si.nMax := 1; si.nPos := 1; end; si.nPage := 1; SetScrollInfo(Handle, SB_VERT, si, True); end; pscPageWidth: begin // hide horizontal scrollbar ShowScrollbar(Handle, SB_HORZ, False); // show vertical scrollbar si.fMask := si.fMask or SIF_DISABLENOSCROLL; si.nMax := FVirtualSize.Y; si.nPos := -FScrollPosition.Y; si.nPage := ClientHeight; SetScrollInfo(Handle, SB_VERT, si, True); end; pscUserScaled: begin ShowScrollbar(Handle, SB_HORZ, True); ShowScrollbar(Handle, SB_VERT, True); si.fMask := si.fMask or SIF_DISABLENOSCROLL; // show horizontal scrollbar si.nMax := FVirtualSize.X; si.nPos := -FScrollPosition.X; si.nPage := ClientWidth; SetScrollInfo(Handle, SB_HORZ, si, True); // show vertical scrollbar si.nMax := FVirtualSize.Y; si.nPos := -FScrollPosition.Y; si.nPage := ClientHeight; SetScrollInfo(Handle, SB_VERT, si, True); end; end; end; procedure TSynEditPrintPreview.SetBorderStyle(Value: TBorderStyle); begin if (Value <> FBorderStyle) then begin FBorderStyle := Value; RecreateWnd; end; end; procedure TSynEditPrintPreview.SetPageBG(Value: TColor); begin if (FPageBG <> Value) then begin FPageBG := Value; Invalidate; end; end; procedure TSynEditPrintPreview.SetSynEditPrint(Value: TSynEditPrint); begin if (FSynEditPrint <> Value) then begin FSynEditPrint := Value; if Assigned(FSynEditPrint) then FSynEditPrint.FreeNotification(Self); end; end; procedure TSynEditPrintPreview.SetScaleMode(Value: TSynPreviewScale); begin if (FScaleMode <> Value) then begin FScaleMode := Value; FScrollPosition := Point(0, 0); SizeChanged; if Assigned(FOnScaleChange) then FOnScaleChange(Self); Invalidate; end; end; procedure TSynEditPrintPreview.SetScalePercent(Value: Integer); begin if (FScalePercent <> Value) then begin FScaleMode := pscUserScaled; FScrollPosition := Point(0, 0); FScalePercent := Value; SizeChanged; Invalidate; end else ScaleMode := pscUserScaled; if Assigned(FOnScaleChange) then FOnScaleChange(Self); end; procedure TSynEditPrintPreview.WMEraseBkgnd(var Msg: TWMEraseBkgnd); begin Msg.Result := 1; end; procedure TSynEditPrintPreview.WMHScroll(var Msg: TWMHScroll); var nW: Integer; begin if (FScaleMode <> pscWholePage) then begin nW := ClientWidth; case Msg.ScrollCode of SB_TOP: ScrollHorzTo(0); SB_BOTTOM: ScrollHorzTo(-FVirtualSize.X); SB_LINEDOWN: ScrollHorzFor(-(nW div 10)); SB_LINEUP: ScrollHorzFor(nW div 10); SB_PAGEDOWN: ScrollHorzFor(-(nW div 2)); SB_PAGEUP: ScrollHorzFor(nW div 2); SB_THUMBPOSITION, SB_THUMBTRACK: ScrollHorzTo(-Msg.Pos); end; end; end; procedure TSynEditPrintPreview.WMSize(var Msg: TWMSize); begin inherited; if not (csDesigning in ComponentState) then SizeChanged; end; var ScrollHintWnd: THintWindow; function GetScrollHint: THintWindow; begin if ScrollHintWnd = nil then begin ScrollHintWnd := HintWindowClass.Create(Application); ScrollHintWnd.Visible := FALSE; end; Result := ScrollHintWnd; end; procedure TSynEditPrintPreview.WMVScroll(var Msg: TWMVScroll); var nH: Integer; s: string; rc: TRect; pt: TPoint; ScrollHint: THintWindow; begin if (FScaleMode = pscWholePage) then begin if Assigned(FSynEditPrint) then case Msg.ScrollCode of SB_TOP: FPageNumber := 1; SB_BOTTOM: FPageNumber := FSynEditPrint.PageCount; SB_LINEDOWN, SB_PAGEDOWN: begin FPageNumber := FPageNumber + 1; if FPageNumber > FSynEditPrint.PageCount then FPageNumber := FSynEditPrint.PageCount; end; SB_LINEUP, SB_PAGEUP: begin FPageNumber := FPageNumber - 1; if FPageNumber < 1 then FPageNumber := 1; end; SB_THUMBPOSITION, SB_THUMBTRACK: begin FPageNumber := Msg.Pos; //Showing hint window - principle copied from SynEdit.pas if FShowScrollHint then begin ScrollHint := GetScrollHint; if not ScrollHint.Visible then begin ScrollHint.Color := Application.HintColor; ScrollHint.Visible := TRUE; end; s := Format(SYNS_PreviewScrollInfoFmt, [FPageNumber]); {$IFDEF SYN_COMPILER_3_UP} rc := ScrollHint.CalcHintRect(200, s, nil); {$ELSE} rc := Rect(0, 0, TextWidth(ScrollHint.Canvas, s) + 6, TextHeight(ScrollHint.Canvas, s) + 4); {$ENDIF} pt := ClientToScreen(Point(ClientWidth - rc.Right - 4, 10)); OffsetRect(rc, pt.x, pt.y); ScrollHint.ActivateHint(rc, s); {$IFDEF SYN_COMPILER_3} SendMessage(ScrollHint.Handle, WM_NCPAINT, 1, 0); {$ENDIF} {$IFNDEF SYN_COMPILER_3_UP} ScrollHint.Invalidate; {$ENDIF} ScrollHint.Update; end; end; SB_ENDSCROLL: begin if FShowScrollHint then begin ScrollHint := GetScrollHint; ScrollHint.Visible := False; ShowWindow(ScrollHint.Handle, SW_HIDE); end; end; end; {Updating scroll position and redrawing} FScrollPosition.Y := -(FPageNumber - 1); UpdateScrollbars; if Assigned(FOnPreviewPage) then FOnPreviewPage(Self, FPageNumber); Invalidate; end else begin nH := ClientHeight; case Msg.ScrollCode of SB_TOP: ScrollVertTo(0); SB_BOTTOM: ScrollVertTo(-FVirtualSize.Y); SB_LINEDOWN: ScrollVertFor(-(nH div 10)); SB_LINEUP: ScrollVertFor(nH div 10); SB_PAGEDOWN: ScrollVertFor(-(nH div 2)); SB_PAGEUP: ScrollVertFor(nH div 2); SB_THUMBPOSITION, SB_THUMBTRACK: ScrollVertTo(-Msg.Pos); end; end; end; procedure TSynEditPrintPreview.WMMouseWheel(var Message: TWMMouseWheel); {$IFNDEF SYN_COMPILER_3_UP} const WHEEL_DELTA = 120; {$ENDIF} var bCtrl: Boolean; procedure MouseWheelUp; begin if bCtrl and (fPageNumber > 1) then PreviousPage else ScrollVertFor(WHEEL_DELTA); end; procedure MouseWheelDown; begin if bCtrl and (fPageNumber < PageCount) then NextPage else ScrollVertFor(-WHEEL_DELTA); end; var MousePos: TPoint; IsNeg: Boolean; begin { Find modifiers } bCtrl := GetKeyState(VK_CONTROL) < 0; { Find mouse pos and increment accumulator } MousePos:= SmallPointToPoint(Message.Pos); Inc(FWheelAccumulator, Message.WheelDelta); { Do actions while accumulated is bigger than delta } while Abs(FWheelAccumulator) >= WHEEL_DELTA do begin IsNeg := FWheelAccumulator < 0; FWheelAccumulator := Abs(FWheelAccumulator) - WHEEL_DELTA; if IsNeg then begin if FWheelAccumulator <> 0 then FWheelAccumulator := -FWheelAccumulator; MouseWheelDown; end else MouseWheelUp; end; end; procedure TSynEditPrintPreview.UpdatePreview; var OldScale: Integer; OldMode: TSynPreviewScale; begin OldScale := ScalePercent; OldMode := ScaleMode; ScalePercent := 100; if Assigned(FSynEditPrint) then FSynEditPrint.UpdatePages(Canvas); SizeChanged; Invalidate; ScaleMode := OldMode; if ScaleMode = pscUserScaled then ScalePercent := OldScale; if Assigned(FOnPreviewPage) then FOnPreviewPage(Self, FPageNumber); end; procedure TSynEditPrintPreview.FirstPage; begin FPageNumber := 1; if Assigned(FOnPreviewPage) then FOnPreviewPage(Self, FPageNumber); Invalidate; end; procedure TSynEditPrintPreview.LastPage; begin if Assigned(FSynEditPrint) then FPageNumber := FSynEditPrint.PageCount; if Assigned(FOnPreviewPage) then FOnPreviewPage(Self, FPageNumber); Invalidate; end; procedure TSynEditPrintPreview.NextPage; begin FPageNumber := FPageNumber + 1; if Assigned(FSynEditPrint) and (FPageNumber > FSynEditPrint.PageCount) then FPageNumber := FSynEditPrint.PageCount; if Assigned(FOnPreviewPage) then FOnPreviewPage(Self, FPageNumber); Invalidate; end; procedure TSynEditPrintPreview.PreviousPage; begin FPageNumber := FPageNumber - 1; if Assigned(FSynEditPrint) and (FPageNumber < 1) then FPageNumber := 1; if Assigned(FOnPreviewPage) then FOnPreviewPage(Self, FPageNumber); Invalidate; end; procedure TSynEditPrintPreview.Print; begin if Assigned(FSynEditPrint) then begin FSynEditPrint.Print; UpdatePreview; end; end; function TSynEditPrintPreview.GetPageCount: Integer; begin Result := SynEditPrint.PageCount; end; end.