lazarus-ccr/components/thtmlport/package/htmlview.pas

5348 lines
156 KiB
ObjectPascal
Executable File

{Version 9.45}
{*********************************************************}
{* HTMLVIEW.PAS *}
{*********************************************************}
{
Copyright (c) 1995-2008 by L. David Baldwin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Note that the source modules, HTMLGIF1.PAS, PNGZLIB1.PAS, DITHERUNIT.PAS, and
URLCON.PAS are covered by separate copyright notices located in those modules.
}
{$i htmlcons.inc}
unit Htmlview;
interface
uses
{$IFNDEF LCL} WinTypes, WinProcs, Messages, {$ELSE} LclIntf, LMessages, Types, LclType, FPimage, HtmlMisc, {$ENDIF}
SysUtils, Classes, Graphics, Controls, StdCtrls,
{$IFNDEF LCL} vwPrint, MetafilePrinter, mmSystem, {$ENDIF}
HTMLUn2, Forms, Dialogs, ExtCtrls, ReadHTML, HTMLSubs, StyleUn, Printers, Menus,
GDIPL2A;
const
wm_FormSubmit = wm_User+100;
wm_MouseScroll = wm_User+102;
wm_UrlAction = wm_User+103;
type
THTMLViewer = class;
THTMLBorderStyle = (htFocused, htNone, htSingle);
TRightClickParameters = Class(TObject)
URL, Target: string;
Image: TImageObj;
ImageX, ImageY: integer;
ClickWord: WideString;
end;
TRightClickEvent = procedure(Sender: TObject; Parameters: TRightClickParameters) of Object;
THotSpotEvent = procedure(Sender: TObject; const SRC: string) of Object;
THotSpotClickEvent = procedure(Sender: TObject; const SRC: string;
var Handled: boolean) of Object;
TProcessingEvent = procedure(Sender: TObject; ProcessingOn: boolean) of Object;
TPagePrinted = procedure( Sender: TObject;
Canvas : TCanvas ;
NumPage, W, H: Integer ;
var StopPrinting : Boolean) of Object;
ThtmlPagePrinted = procedure(Sender: TObject; HFViewer: ThtmlViewer;
NumPage: Integer; LastPage: boolean;
var XL, XR: integer;
var StopPrinting: Boolean) of Object;
TImageClickEvent = procedure(Sender, Obj: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer) of Object;
TImageOverEvent = procedure(Sender, Obj: TObject; Shift: TShiftState;
X, Y: Integer) of Object;
TMetaRefreshType = procedure(Sender: TObject; Delay: integer; const URL: string) of Object;
TParseEvent = procedure(Sender: TObject; var Source: string) of Object;
htOptionEnum = (htOverLinksActive,htNoLinkUnderline,htPrintTableBackground,
htPrintBackground, htPrintMonochromeBlack, htShowDummyCaret,
htShowVScroll, htNoWheelMouse, htNoLinkHilite);
ThtmlViewerOptions = set of htOptionEnum;
ThtProgressEvent = procedure(Sender: TObject; Stage: TProgressStage;
PercentDone: integer) of Object;
TPaintPanel = class(TCustomPanel)
private
FOnPaint: TNotifyEvent;
FViewer: ThtmlViewer;
Canvas2: TCanvas;
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_EraseBkgnd;
procedure WMLButtonDblClk(var Message: TWMMouse); message WM_LButtonDblClk;
procedure DoBackground(ACanvas: TCanvas);
constructor CreateIt(AOwner: TComponent; Viewer: ThtmlViewer);
property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
public
procedure Paint; override;
end;
{$IFNDEF LCL}
T32ScrollBar = Class(TScrollBar) {a 32 bit scrollbar}
private
FPosition: integer;
FMin, FMax, FPage: integer;
procedure SetPosition(Value: integer);
procedure SetMin(Value: Integer);
procedure SetMax(Value: Integer);
procedure CNVScroll(var Message: TWMVScroll); message CN_VSCROLL;
public
property Position: integer read FPosition write SetPosition;
property Min: integer read FMin write SetMin;
property Max: integer read FMax write SetMax;
procedure SetParams(APosition, APage, AMin, AMax: Integer);
end;
{$ELSE}
T32ScrollBar = class(TScrollBar)
private
procedure DoOnScroll(sender : TObject; ScrollCode: TScrollCode;
var ScrollPos: Integer);
end;
{$ENDIF}
ThtmlFileType = (HTMLType, TextType, ImgType, OtherType);
{$IFDEF LCL} //From MetaFilePrinter.pas
TPageEvent = procedure( Sender: TObject; NumPage: Integer ;
var StopPrinting : Boolean) of Object;
{$ENDIF}
{$IFNDEF LCL}
THTMLViewer = class(TWinControl)
{$ELSE}
THTMLViewer = class(TCustomControl)
{$ENDIF}
private
{$IFNDEF LCL}
vwP, OldPrinter: TvwPrinter;
{$ELSE}
vwP: TPrinter;
{$ENDIF}
fScaleX, fScaleY: single;
FCodePage: integer;
function GetCursor: TCursor;
procedure SetCursor(Value: TCursor);
protected
InCreate: boolean;
FOnDragDrop: TDragDropEvent;
FOnDragOver: TDragOverEvent;
DontDraw: boolean;
FTitle: String;
FURL: String;
FTarget: String;
FBase, FBaseEx: String;
FBaseTarget: String;
FCurrentFile: String;
FNameList: TStringList;
FCurrentFileType: ThtmlFileType;
FOnHotSpotCovered: THotSpotEvent;
FOnHotSpotClick: THotSpotClickEvent;
FOnBitmapRequest: TGetBitmapEvent;
FOnImageRequest: TGetImageEvent;
FOnScript: TScriptEvent;
FOnFormSubmit: TFormSubmitEvent;
FOnHistoryChange: TNotifyEvent;
FOnProcessing: TProcessingEvent;
FOnInclude: TIncludeType;
FOnSoundRequest: TSoundType;
FOnLink: TLinkType;
FOnMeta: TMetaType;
FOnMetaRefresh: TMetaRefreshType;
FOnPanelCreate: TPanelCreateEvent;
FOnPanelDestroy: TPanelDestroyEvent;
FOnPanelPrint: TPanelPrintEvent;
FRefreshURL: string;
FRefreshDelay: Integer;
FOnRightClick: TRightClickEvent;
FOnImageClick: TImageClickEvent;
FOnImageOver: TImageOverEvent;
FOnObjectClick: TObjectClickEvent;
FOnFileBrowse: TFileBrowseEvent;
FOnObjectFocus: ThtObjectEvent;
FOnObjectBlur: ThtObjectEvent;
FOnObjectChange: ThtObjectEvent;
FOnProgress: ThtProgressEvent;
FHistory, FTitleHistory: TStrings;
FPositionHistory: TFreeList;
FHistoryIndex: integer;
FHistoryMaxCount: integer;
FFontName: TFontName;
FPreFontName: String;
FFontColor: TColor;
FHotSpotColor, FVisitedColor, FOverColor: TColor;
FVisitedMaxCount: integer;
FBackGround: TColor;
FFontSize: integer;
FProcessing: boolean;
FAction, FFormTarget, FEncType, FMethod: String;
FStringList: TStringList;
FImageCacheCount: integer;
FNoSelect: boolean;
FScrollBars: TScrollStyle;
FBorderStyle: THTMLBorderStyle;
FDither: boolean;
FCaretPos: integer;
FOptions: ThtmlViewerOptions;
sbWidth: integer;
ScrollWidth: integer;
FMaxVertical: integer;
MouseScrolling: boolean;
LeftButtonDown: boolean;
MiddleScrollOn: boolean;
MiddleY: integer;
Hiliting: boolean;
FPrintMarginLeft,
FPrintMarginRight,
FPrintMarginTop,
FPrintMarginBottom: double;
FCharset: TFontCharset; {see htmlun2.pas for Delphi 2 TFontCharSet definition}
FOnPrintHeader, FOnPrintFooter: TPagePrinted;
FOnPrintHTMLHeader, FOnPrintHTMLFooter: ThtmlPagePrinted;
FPage: integer;
FOnPageEvent: TPageEvent;
FOnMouseDouble: TMouseEvent;
HotSpotAction: boolean;
FMarginHeight, FMarginWidth: integer;
FServerRoot: string;
FSectionList: TSectionList;
FImageStream: TMemoryStream;
FOnExpandName: TExpandNameEvent;
HTMLTimer: TTimer;
FOnhtStreamRequest: TGetStreamEvent;
LocalBitmapList: boolean;
FDocumentSource: string;
FOnParseBegin: TParseEvent;
FOnParseEnd: TNotifyEvent;
FTitleAttr: string;
BGFixed: boolean;
FPrintScale: double;
NoJump: boolean;
FOnLinkDrawn: TLinkDrawnEvent;
FLinkAttributes: TStringList;
FLinkText: WideString;
FLinkStart: TPoint;
FWidthRatio: double;
FOnObjectTag: TObjectTagEvent;
function CreateHeaderFooter: ThtmlViewer;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
procedure ScrollTo(Y: integer);
procedure Scroll(Sender: TObject; ScrollCode: TScrollCode;
var ScrollPos: Integer);
procedure Layout;
procedure SetViewImages(Value: boolean);
function GetViewImages: boolean;
procedure SetColor(Value: TColor);
function GetBase: string;
procedure SetBase(Value: string);
function GetBaseTarget: string;
function GetTitle: string;
function GetCurrentFile: string;
procedure SetBorderStyle(Value: THTMLBorderStyle);
function GetPosition: integer;
procedure SetPosition(Value: integer);
function GetScrollPos: integer;
procedure SetScrollPos(Value: integer);
function GetScrollBarRange: integer;
function GetHScrollPos: integer;
procedure SetHScrollPos(Value: integer);
function GetHScrollBarRange: integer;
procedure SetHistoryIndex(Value: integer);
function GetPreFontName: TFontName;
procedure SetPreFontName(Value: TFontName);
procedure SetFontSize(Value: integer);
procedure SetHotSpotColor(Value: TColor);
procedure SetActiveColor(Value: TColor);
procedure SetVisitedColor(Value: TColor);
procedure SetVisitedMaxCount(Value: integer);
procedure SetOnBitmapRequest(Handler: TGetBitmapEvent);
procedure SetOnImageRequest(Handler: TGetImageEvent);
procedure SetOnScript(Handler: TScriptEvent);
procedure SetOnFormSubmit(Handler: TFormSubmitEvent);
function GetOurPalette: HPalette;
procedure SetOurPalette(Value: HPalette);
procedure SetDither(Value: boolean);
procedure SetCaretPos(Value: integer);
procedure WMGetDlgCode(var Message: TMessage); message WM_GETDLGCODE;
procedure BackgroundChange(Sender: TObject);
procedure SubmitForm(Sender: TObject; const Action, Target, EncType, Method: string;
Results: TStringList);
procedure SetImageCacheCount(Value: integer);
procedure WMFormSubmit(var Message: TMessage); message WM_FormSubmit;
procedure WMMouseScroll(var Message: TMessage); message WM_MouseScroll;
procedure WMUrlAction(var Message: TMessage); message WM_UrlAction;
procedure SetSelLength(Value: integer);
procedure SetSelStart(Value: integer);
function GetSelLength: integer;
function GetSelText: WideString;
procedure SetNoSelect(Value: boolean);
procedure SetHistoryMaxCount(Value: integer);
procedure DrawBorder;
procedure DoHilite(X, Y: integer); virtual;
procedure SetScrollBars(Value: TScrollStyle);
procedure SetProcessing(Value: boolean);
procedure SetCharset(Value: TFontCharset);
function GetFormControlList: TList;
function GetNameList: TStringList;
function GetLinkList: TList;
procedure SetServerRoot(Value: string);
procedure SetOnFileBrowse(Handler: TFileBrowseEvent);
procedure SetOnObjectClick(Handler: TObjectClickEvent);
procedure SetOnObjectFocus(Handler: ThtObjectEvent);
procedure SetOnObjectBlur(Handler: ThtObjectEvent);
procedure SetOnObjectChange(Handler: ThtObjectEvent);
procedure FormControlEnterEvent(Sender: TObject);
procedure HandleMeta(Sender: TObject; const HttpEq, Name, Content: string);
procedure SetOptions(Value: ThtmlViewerOptions);
procedure DoImage(Sender: TObject; const SRC: string; var Stream: TMemoryStream);
procedure SetOnExpandName(Handler: TExpandNameEvent);
function GetWordAtCursor(X, Y: integer; var St, En: integer; var AWord: WideString): boolean;
procedure SetOnPanelCreate(Handler: TPanelCreateEvent);
procedure SetOnPanelDestroy(Handler: TPanelDestroyEvent);
procedure SetOnPanelPrint(Handler: TPanelPrintEvent);
procedure HTMLTimerTimer(Sender: TObject);
function GetDragDrop: TDragDropEvent;
function GetDragOver: TDragOverEvent;
procedure SetDragDrop(const Value: TDragDropEvent);
procedure SetDragOver(const Value: TDragOverEvent);
procedure HTMLDragDrop(Sender, Source: TObject; X, Y: Integer);
procedure HTMLDragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
procedure InitLoad;
function GetFormData: TFreeList;
procedure SetFormData(T: TFreeList);
function GetIDControl(const ID: string): TObject;
function GetIDDisplay(const ID: string): boolean;
procedure SetIDDisplay(const ID: string; Value: boolean);
procedure SetPrintScale(Value: double);
protected
{ Protected declarations }
PaintPanel: TPaintPanel;
BorderPanel: TPanel;
Sel1: integer;
procedure DoLogic;
procedure DoScrollBars;
procedure SetupAndLogic;
function GetURL(X, Y: integer; var UrlTarg: TUrlTarget;
var FormControl: TImageFormControlObj; var ATitle: string): guResultType;
function GetPalette: HPALETTE; override;
procedure HTMLPaint(Sender: TObject); virtual;
procedure HTMLMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); virtual;
{$ifdef ver120_plus}
procedure HTMLMouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint);
function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; override;
{$endif}
procedure HTMLMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer); virtual;
procedure HTMLMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); virtual;
procedure HTMLMouseDblClk(Message: TWMMouse);
function HotSpotClickHandled: boolean; dynamic;
procedure LoadFile(const FileName: string; ft: ThtmlFileType); virtual;
procedure PaintWindow(DC: HDC); override;
procedure UpdateImageCache;
procedure DrawBackground2(ACanvas: TCanvas; ARect: TRect; XStart, YStart, XLast, YLast: integer;
Image: TGpObject; Mask: TBitmap; BW, BH: integer; BGColor: TColor);
procedure DoBackground1(ACanvas: TCanvas; ATop, AWidth, AHeight, FullHeight: integer);
procedure DoBackground2(ACanvas: TCanvas; ALeft, ATop, AWidth, AHeight: integer; AColor: TColor);
procedure LoadString(const Source, Reference: string; ft: ThtmlFileType);
public
{ Public declarations }
FrameOwner: TObject;
VScrollBar: T32ScrollBar;
HScrollBar: TScrollBar;
TablePartRec: TTablePartRec;
Visited: TStringList; {visited URLs}
procedure AddVisitedLink(const S: string);
procedure CheckVisitedLinks;
procedure UrlAction;
procedure TriggerUrlAction;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function HTMLExpandFilename(const Filename: string): string; virtual;
procedure LoadFromFile(const FileName: string);
procedure LoadTextFromString(const S: string);
{$ifdef ver120_plus} {Delphi 4 and higher}
procedure LoadFromString(const S: string; const Reference: string = ''); overload;
{$ifdef Delphi6_Plus}
procedure LoadFromString(const WS: WideString; const Reference: string = ''); overload;
{$endif}
procedure LoadFromStream(const AStream: TStream; const Reference: string = '');
procedure LoadStrings(const Strings: TStrings; const Reference: string = '');
procedure LoadFromBuffer(Buffer: PChar; BufSize: integer; const Reference: string = '');
{$else}
procedure LoadFromString(const S: string; const Reference: string);
procedure LoadFromStream(const AStream: TStream; const Reference: string);
procedure LoadStrings(const Strings: TStrings; const Reference: string);
procedure LoadFromBuffer(Buffer: PChar; BufSize: integer; const Reference: string);
{$endif}
procedure LoadTextFile(const FileName: string);
procedure LoadImageFile(const FileName: string);
procedure LoadTextStrings(Strings: TStrings);
procedure LoadStream(const URL: string; AStream: TMemoryStream; ft: ThtmlFileType);
procedure Print(FromPage, ToPage: integer);
function NumPrinterPages: integer; overload;
function NumPrinterPages(var WidthRatio: double): integer; overload;
{$IFNDEF LCL}
function PrintPreview(MFPrinter: TMetaFilePrinter; NoOutput: boolean = False): integer;
{$ENDIF}
function PositionTo(Dest: string): boolean;
function Find(const S: WideString; MatchCase: boolean): boolean;
function FindEx(const S: WideString; MatchCase, Reverse: boolean): boolean;
procedure Clear; virtual;
procedure CopyToClipboard;
procedure SelectAll;
procedure ClearHistory;
procedure Reload;
procedure BumpHistory(const FileName, Title: string;
OldPos: integer; OldFormData: TFreeList; ft: ThtmlFileType);
function GetSelTextBuf(Buffer: PWideChar; BufSize: integer): integer;
function InsertImage(const Src: string; Stream: TMemoryStream): boolean;
procedure DoEnter; override;
procedure DoExit; override;
procedure Repaint; override;
function FindSourcePos(DisplayPos: integer): integer;
function FindDisplayPos(SourcePos: integer; Prev: boolean): integer;
function DisplayPosToXy(DisplayPos: integer; var X, Y: integer): boolean;
function PtInObject(X, Y: integer; var Obj: TObject): boolean; {X, Y, are client coord}
procedure SetStringBitmapList(BitmapList: TStringBitmapList);
function XYToDisplayPos(X, Y: integer): integer;
procedure ReplaceImage(const NameID: string; NewImage: TStream);
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure Reformat;
procedure htProgress(Percent: Integer);
procedure htProgressEnd;
procedure htProgressInit;
function FullDisplaySize(FormatWidth: integer): TSize;
function MakeBitmap(YTop, FormatWidth, Width, Height: integer): TBitmap;
{$IFNDEF LCL}
function MakeMetaFile(YTop, FormatWidth, Width, Height: integer): TMetaFile;
function MakePagedMetaFiles(Width, Height: integer): TList;
{$ENDIF}
procedure ControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
function GetCharAtPos(Pos: integer; var Ch: WideChar;
var Font: TFont): boolean;
function GetTextByIndices(AStart, ALast: integer): WideString;
procedure OpenPrint;
procedure ClosePrint;
procedure AbortPrint;
property DocumentTitle: string read GetTitle;
property URL: string read FURL write FURL;
property Base: string read GetBase write SetBase;
property BaseTarget: string read GetBaseTarget;
property Position: integer read GetPosition write SetPosition;
property VScrollBarPosition: integer read GetScrollPos write SetScrollPos;
property VScrollBarRange: integer read GetScrollBarRange;
property HScrollBarPosition: integer read GetHScrollPos write SetHScrollPos;
property HScrollBarRange: integer read GetHScrollBarRange;
property CurrentFile: string read GetCurrentFile;
property History: TStrings read FHistory;
property TitleHistory: TStrings read FTitleHistory;
property HistoryIndex: integer read FHistoryIndex write SetHistoryIndex;
property Processing: boolean read FProcessing;
property SelStart: integer read FCaretPos write SetSelStart;
property SelLength: integer read GetSelLength write SetSelLength;
property SelText: WideString read GetSelText;
property Target: string read FTarget write FTarget;
property Palette: HPalette read GetOurPalette write SetOurPalette;
property Dither: boolean read FDither write SetDither default True;
property CaretPos: integer read FCaretPos write SetCaretPos;
property FormControlList: TList read GetFormControlList;
property NameList: TStringList read GetNameList;
property LinkList: TList read GetLinkList;
property SectionList: TSectionList read FSectionList;
property OnPageEvent: TPageEvent read FOnPageEvent write FOnPageEvent;
property OnExpandName: TExpandNameEvent read FOnExpandName write SetOnExpandName;
property FormData: TFreeList read GetFormData write SetFormData;
property DocumentSource: string read FDocumentSource;
property MaxVertical: integer read FMaxVertical;
property TitleAttr: string read FTitleAttr;
property IDDisplay[const ID: string]: boolean read GetIDDisplay write SetIDDisplay;
property IDControl[const ID: string]: TObject read GetIDControl;
property OnLinkDrawn: TLinkDrawnEvent read FOnLinkDrawn write FOnLinkDrawn;
property LinkAttributes: TStringList read FLinkAttributes;
Property LinkText: WideString read FLinkText write FLinkText;
Property LinkStart: TPoint read FLinkStart;
property CodePage: integer read FCodePage write FCodePage;
published
{ Published declarations }
property OnHotSpotCovered: THotSpotEvent read FOnHotSpotCovered
write FOnHotSpotCovered;
property OnHotSpotClick: THotSpotClickEvent read FOnHotSpotClick
write FOnHotSpotClick;
property OnBitmapRequest: TGetBitmapEvent read FOnBitmapRequest
write SetOnBitmapRequest;
property OnImageRequest: TGetImageEvent read FOnImageRequest
write SetOnImageRequest;
property OnScript: TScriptEvent read FOnScript
write SetOnScript;
property OnFormSubmit: TFormSubmitEvent read FOnFormSubmit
write SetOnFormSubmit;
property OnHistoryChange: TNotifyEvent read FOnHistoryChange
write FOnHistoryChange;
property OnProgress: ThtProgressEvent read FOnProgress write FOnProgress;
property ViewImages: boolean read GetViewImages write SetViewImages default True;
property Enabled;
property TabStop;
property TabOrder;
property Align;
property Name;
property Tag;
property PopupMenu;
property ShowHint;
{$ifdef ver120_plus}
property Anchors;
{$endif}
property Height default 150;
property Width default 150;
property DefBackground: TColor read FBackground write SetColor default clBtnFace;
property BorderStyle: THTMLBorderStyle read FBorderStyle write SetBorderStyle;
property Visible;
property HistoryMaxCount: integer read FHistoryMaxCount write SetHistoryMaxCount;
property DefFontName: TFontName read FFontName write FFontName;
property DefPreFontName: TFontName read GetPreFontName write SetPreFontName;
property DefFontSize: integer read FFontSize write SetFontSize default 12;
property DefFontColor: TColor read FFontColor write FFontColor
default clBtnText;
property DefHotSpotColor: TColor read FHotSpotColor write SetHotSpotColor
default clBlue;
property DefVisitedLinkColor: TColor read FVisitedColor write SetVisitedColor
default clPurple;
property DefOverLinkColor: TColor read FOverColor write SetActiveColor
default clBlue;
property VisitedMaxCount: integer read FVisitedMaxCount write SetVisitedMaxCount default 50;
property ImageCacheCount: integer read FImageCacheCount
write SetImageCacheCount default 5;
property NoSelect: boolean read FNoSelect write SetNoSelect;
property ScrollBars: TScrollStyle read FScrollBars write SetScrollBars default ssBoth;
property CharSet: TFontCharset read FCharSet write SetCharset;
property MarginHeight: integer read FMarginHeight write FMarginHeight default 5;
property MarginWidth: integer read FMarginWidth write FMarginWidth default 10;
property ServerRoot: string read FServerRoot write SetServerRoot;
property PrintMarginLeft: double read FPrintMarginLeft write FPrintMarginLeft;
property PrintMarginRight: double read FPrintMarginRight write FPrintMarginRight;
property PrintMarginTop: double read FPrintMarginTop write FPrintMarginTop;
property PrintMarginBottom: double read FPrintMarginBottom write FPrintMarginBottom;
property PrintScale: double read FPrintScale write SetPrintScale;
property htOptions: ThtmlViewerOptions read FOptions write SetOptions
default [htPrintTableBackground, htPrintMonochromeBlack];
property OnMouseMove;
property OnMouseUp;
property OnMouseDown;
{$ifdef ver120_plus}
property OnMouseWheel;
{$endif}
property OnKeyDown;
property OnKeyUp;
property OnKeyPress;
property OnEnter;
property OnExit;
property OnProcessing: TProcessingEvent read FOnProcessing write FOnProcessing;
property OnPrintHeader: TPagePrinted read FOnPrintHeader write FOnPrintHeader;
property OnPrintFooter: TPagePrinted read FOnPrintFooter write FOnPrintFooter;
property OnPrintHTMLHeader: ThtmlPagePrinted read FOnPrintHTMLHeader write FOnPrintHTMLHeader;
property OnPrintHTMLFooter: ThtmlPagePrinted read FOnPrintHTMLFooter write FOnPrintHTMLFooter;
property OnInclude: TIncludeType read FOnInclude write FOnInclude;
property OnSoundRequest: TSoundType read FOnSoundRequest write FOnSoundRequest;
property OnMeta: TMetaType read FOnMeta write FOnMeta;
property OnLink: TLinkType read FOnLink write FOnLink;
property OnMetaRefresh: TMetaRefreshType read FOnMetaRefresh write FOnMetaRefresh;
property OnImageClick: TImageClickEvent read FOnImageClick write FOnImageClick;
property OnImageOver: TImageOverEvent read FOnImageOver write FOnImageOver;
property OnFileBrowse: TFileBrowseEvent read FOnFileBrowse write SetOnFileBrowse;
property OnObjectClick: TObjectClickEvent read FOnObjectClick write SetOnObjectClick;
property OnObjectFocus: ThtObjectEvent read FOnObjectFocus write SetOnObjectFocus;
property OnObjectBlur: ThtObjectEvent read FOnObjectBlur write SetOnObjectBlur;
property OnObjectChange: ThtObjectEvent read FOnObjectChange write SetOnObjectChange;
property OnRightClick: TRightClickEvent read FOnRightClick write FOnRightClick;
property OnMouseDouble: TMouseEvent read FOnMouseDouble write FOnMouseDouble;
property OnPanelCreate: TPanelCreateEvent read FOnPanelCreate write SetOnPanelCreate;
property OnPanelDestroy: TPanelDestroyEvent read FOnPanelDestroy write SetOnPanelDestroy;
property OnPanelPrint: TPanelPrintEvent read FOnPanelPrint write SetOnPanelPrint;
{$IFNDEF LCL}
property OnDragDrop: TDragDropEvent read GetDragDrop write SetDragDrop;
property OnDragOver: TDragOverEvent read GetDragOver write SetDragOver;
{$ELSE} //Previous gives AV on Intel Mac in Laz designer (and inconsistent with framview/frambrwz)
property OnDragDrop: TDragDropEvent read FOnDragDrop write SetDragDrop;
property OnDragOver: TDragOverEvent read FOnDragOver write SetDragOver;
{$ENDIF}
property OnhtStreamRequest: TGetStreamEvent read FOnhtStreamRequest
write FOnhtStreamRequest;
property OnParseBegin: TParseEvent read FOnParseBegin write FOnParseBegin;
property OnParseEnd: TNotifyEvent read FOnParseEnd write FOnParseEnd;
property OnObjectTag: TObjectTagEvent read FOnObjectTag write FOnObjectTag;
property Cursor: TCursor read GetCursor write SetCursor default crIBeam;
end;
implementation
uses
Clipbrd, htmlgif2;
const
ScrollGap = 20;
type
PositionObj = class(TObject)
Pos: integer;
FileType: ThtmlFileType;
FormData: TFreeList;
destructor Destroy; override;
end;
constructor THTMLViewer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
InCreate := True;
ControlStyle := [csAcceptsControls, csCaptureMouse, csClickEvents,
csSetCaption, csDoubleClicks];
Height := 150;
Width := 150;
SetCursor(crIBeam);
FPrintMarginLeft := 2.0;
FPrintMarginRight := 2.0;
FPrintMarginTop := 2.0;
FPrintMarginBottom := 2.0;
FPrintScale := 1.0;
FCharset := DEFAULT_CHARSET;
FMarginHeight := 5;
FMarginWidth := 10;
// LCL port note: BorderPanel presumably used to simulate viewer border
// since TWinControl does not have BorderStyle property. But this use of
// TPanel interferes with Win32/GTK2 text display. However, eliminating
// it altogether interferes with Carbon animated GIFs, so create and add,
// but don't do anything with it.
// Since we're using TCustomControl, which introduces BorderStyle in LCL,
// instead of TWinControl, might eventually be able to set its border.
BorderPanel := TPanel.Create(Self);
BorderPanel.BevelInner := bvNone;
BorderPanel.BevelOuter := bvNone;
{$IFNDEF LCL}
BorderPanel.Ctl3D := False; //Not LCL property
BorderPanel.Align := alClient; //Interferes with GTK2 scrollbar
BorderPanel.ParentCtl3D := False; //Not LCL property
{$ifdef delphi7_plus}
BorderPanel.ParentBackground := False; //Not LCL property
{$endif}
{$ENDIF}
BorderPanel.Parent := Self;
PaintPanel := TPaintPanel.CreateIt(Self, Self);
PaintPanel.ParentFont := False;
PaintPanel.Parent := Self;
PaintPanel.Top := 1;
PaintPanel.Left := 1;
PaintPanel.BevelOuter := bvNone;
PaintPanel.BevelInner := bvNone;
{$IFNDEF LCL}
PaintPanel.ctl3D := False;
{$ENDIF}
PaintPanel.OnPaint := HTMLPaint;
PaintPanel.OnMouseDown := HTMLMouseDown;
PaintPanel.OnMouseMove := HTMLMouseMove;
PaintPanel.OnMouseUp := HTMLMouseUp;
VScrollBar := T32ScrollBar.Create(Self);
VScrollBar.Kind := sbVertical;
VScrollBar.SmallChange := 16;
VScrollBar.Visible := False;
VScrollBar.TabStop := False;
sbWidth := VScrollBar.Width;
VScrollBar.Parent := Self;
{$IFDEF LCL}
VScrollBar.OnScroll := VScrollBar.DoOnScroll;
{$ENDIF}
HScrollBar := TScrollBar.Create(Self);
HScrollBar.Kind := sbHorizontal;
HScrollBar.SmallChange := 15;
HScrollBar.OnScroll := Scroll;
HScrollBar.Visible := False;
HScrollBar.TabStop := False;
HScrollBar.Parent := Self;
HScrollBar.Width := sbWidth;
FScrollBars := ssBoth;
FSectionList := TSectionList.Create(Self, PaintPanel);
FSectionList.ControlEnterEvent := FormControlEnterEvent;
FSectionList.OnBackgroundChange := BackgroundChange;
FSectionList.ShowImages := True;
FNameList := FSectionList.IDNameList;
DefBackground := clBtnFace;
DefFontColor := clBtnText;
DefHotSpotColor := clBlue;
DefOverLinkColor := clBlue;
DefVisitedLinkColor := clPurple;
FVisitedMaxCount := 50;
DefFontSize := 12;
DefFontName := 'Times New Roman';
DefPreFontName := 'Courier New';
SetImageCacheCount(5);
SetOptions([htPrintTableBackground, htPrintMonochromeBlack]);
FHistory := TStringList.Create;
FPositionHistory := TFreeList.Create;
FTitleHistory := TStringList.Create;
FDither := True;
Visited := TStringList.Create;
HTMLTimer := TTimer.Create(Self);
HTMLTimer.Enabled := False;
HTMLTimer.Interval := 200;
HTMLTimer.OnTimer := HTMLTimerTimer;
FLinkAttributes := TStringList.Create;
InCreate := False;
end;
destructor ThtmlViewer.Destroy;
begin
if LocalBitmapList then
begin
FSectionList.Clear;
FSectionList.BitmapList.Free;
end;
FSectionList.Free;
FHistory.Free;
FPositionHistory.Free;
FTitleHistory.Free;
Visited.Free;
HTMLTimer.Free;
FLinkAttributes.Free;
AbortPrint;
inherited Destroy;
end;
procedure THtmlViewer.SetupAndLogic;
begin
FTitle := ReadHTML.Title;
if ReadHTML.Base <> '' then
FBase := ReadHTML.Base
else FBase := FBaseEx;
FBaseTarget := ReadHTML.BaseTarget;
if Assigned(FOnParseEnd) then
FOnParseEnd(Self);
try
DontDraw := True;
{Load the background bitmap if any and if ViewImages set}
FSectionList.GetBackgroundBitmap;
DoLogic;
finally
DontDraw := False;
end;
end;
procedure ThtmlViewer.LoadFile(const FileName: string; ft: ThtmlFileType);
var
I: integer;
Dest, FName, OldFile: string;
SBuffer: string;
OldCursor: TCursor;
FS: TFileStream;
begin
with Screen do
begin
OldCursor := Cursor;
Cursor := crHourGlass;
end;
IOResult; {eat up any pending errors}
FName := FileName;
I := Pos('#', FName);
if I > 0 then
begin
Dest := Copy(FName, I+1, Length(FName)-I); {positioning information}
FName := Copy(FName, 1, I-1);
end
else Dest := '';
FRefreshDelay := 0;
try
SetProcessing(True);
if not FileExists(FName) then
Raise(EInOutError.Create('Can''t locate file: '+FName));
FSectionList.ProgressStart := 75;
htProgressInit;
DontDraw := True;
InitLoad;
CaretPos := 0;
Sel1 := -1;
try
OldFile := FCurrentFile;
FCurrentFile := ExpandFileName(FName);
FCurrentFileType := ft;
if ft in [HTMLType, TextType] then
begin
FS := TFileStream.Create(FName, fmOpenRead or fmShareDenyWrite);
try
SetLength(FDocumentSource, FS.Size);
FS.ReadBuffer(FDocumentSource[1], FS.Size);
finally
FS.Free;
end;
end
else FDocumentSource := '';
if Assigned(FOnParseBegin) then
FOnParseBegin(Self, FDocumentSource);
if ft = HTMLType then
begin
if Assigned(FOnSoundRequest) then
FOnSoundRequest(Self, '', 0, True);
ParseHTMLString(FDocumentSource, FSectionList, FOnInclude, FOnSoundRequest, HandleMeta, FOnLink);
end
else if ft = TextType then
ParseTextString(FDocumentSource, FSectionList)
else
begin
SBuffer := '<img src="'+FName+'">';
ParseHTMLString(SBuffer, FSectionList, Nil, Nil, Nil, Nil);
end;
finally
SetupAndLogic;
CheckVisitedLinks;
if (Dest <> '') and PositionTo(Dest) then {change position, if applicable}
else if FCurrentFile <> OldFile then
begin
ScrollTo(0);
HScrollBar.Position := 0;
end;
{else if same file leave position alone}
DontDraw := False;
PaintPanel.Invalidate;
end;
finally
Screen.Cursor := OldCursor;
htProgressEnd;
SetProcessing(False);
end;
if (FRefreshDelay > 0) and Assigned(FOnMetaRefresh) then
FOnMetaRefresh(Self, FRefreshDelay, FRefreshURL);
end;
procedure ThtmlViewer.LoadFromFile(const FileName: string);
var
OldFile, OldTitle: string;
OldPos: integer;
OldType: ThtmlFileType;
OldFormData: TFreeList;
(*Stream: TMemoryStream; //debugging aid
Indent, Tree: string; *)
begin
if FProcessing then Exit;
if Filename <> '' then
begin
OldFile := FCurrentFile;
OldTitle := FTitle;
OldPos := Position;
OldType := FCurrentFileType;
OldFormData := GetFormData;
try
LoadFile(FileName, HTMLType);
(*Indent := ''; //debugging aid
Tree := '';
FSectionList.FormTree(Indent, Tree);
Stream := TMemoryStream.Create;
Stream.Size := Length(Tree);
Move(Tree[1], Stream.Memory^, Length(Tree));
Stream.SaveToFile('C:\css2\exec\Tree.txt');
Stream.Free; *)
if (OldFile <> FCurrentFile) or (OldType <> FCurrentFileType) then
BumpHistory(OldFile, OldTitle, OldPos, OldFormData, OldType)
else OldFormData.Free;
except
OldFormData.Free;
Raise;
end;
end;
end;
{----------------ThtmlViewer.LoadTextFile}
procedure ThtmlViewer.LoadTextFile(const FileName: string);
var
OldFile, OldTitle: string;
OldPos: integer;
OldType: ThtmlFileType;
OldFormData: TFreeList;
begin
if FProcessing then Exit;
if Filename <> '' then
begin
OldFile := FCurrentFile;
OldTitle := FTitle;
OldPos := Position;
OldType := FCurrentFileType;
OldFormData := GetFormData;
try
LoadFile(FileName, TextType);
if (OldFile <> FCurrentFile) or (OldType <> FCurrentFileType) then
BumpHistory(OldFile, OldTitle, OldPos, OldFormData, OldType)
else OldFormData.Free;
except
OldFormData.Free;
Raise;
end;
end;
end;
{----------------ThtmlViewer.LoadImageFile}
procedure ThtmlViewer.LoadImageFile(const FileName: string);
var
OldFile, OldTitle: string;
OldPos: integer;
OldType: ThtmlFileType;
OldFormData: TFreeList;
begin
if FProcessing then Exit;
if Filename <> '' then
begin
OldFile := FCurrentFile;
OldTitle := FTitle;
OldPos := Position;
OldType := FCurrentFileType;
OldFormData := GetFormData;
try
LoadFile(FileName, ImgType);
if (OldFile <> FCurrentFile) or (OldType <> FCurrentFileType) then
BumpHistory(OldFile, OldTitle, OldPos, OldFormData, OldType)
else OldFormData.Free;
except
OldFormData.Free;
Raise;
end;
end;
end;
{----------------THtmlViewer.LoadStrings}
procedure THtmlViewer.LoadStrings(const Strings: TStrings; const Reference: string);
begin
LoadString(Strings.Text, Reference, HTMLType);
if (FRefreshDelay > 0) and Assigned(FOnMetaRefresh) then
FOnMetaRefresh(Self, FRefreshDelay, FRefreshURL);
end;
{----------------THtmlViewer.LoadTextStrings}
procedure THtmlViewer.LoadTextStrings(Strings: TStrings);
begin
LoadString(Strings.Text, '', TextType);
end;
{----------------ThtmlViewer.LoadFromBuffer}
procedure ThtmlViewer.LoadFromBuffer(Buffer: PChar; BufSize: integer; const Reference: string);
var
S: string;
begin
SetLength(S, BufSize);
Move(Buffer^, S[1], BufSize);
LoadString(S, Reference, HTMLType);
if (FRefreshDelay > 0) and Assigned(FOnMetaRefresh) then
FOnMetaRefresh(Self, FRefreshDelay, FRefreshURL);
end;
{----------------ThtmlViewer.LoadTextFromString}
procedure ThtmlViewer.LoadTextFromString(const S: string);
begin
LoadString(S, '', TextType);
end;
{----------------ThtmlViewer.LoadFromString}
procedure ThtmlViewer.LoadFromString(const S: string; const Reference: string);
begin
LoadString(S, Reference, HTMLType);
if (FRefreshDelay > 0) and Assigned(FOnMetaRefresh) then
FOnMetaRefresh(Self, FRefreshDelay, FRefreshURL);
end;
{$ifdef Delphi6_Plus}
procedure ThtmlViewer.LoadFromString(const WS: WideString; const Reference: string);
begin
LoadFromString(#$EF+#$BB+#$BF+UTF8Encode(WS), Reference);
end;
{$endif}
{----------------ThtmlViewer.LoadString}
procedure ThtmlViewer.LoadString(const Source, Reference: string; ft: ThtmlFileType);
var
I: integer;
Dest, FName, OldFile: string;
begin
if FProcessing then Exit;
SetProcessing(True);
FRefreshDelay := 0;
FName := Reference;
I := Pos('#', FName);
if I > 0 then
begin
Dest := Copy(FName, I+1, Length(FName)-I); {positioning information}
FName := Copy(FName, 1, I-1);
end
else Dest := '';
DontDraw := True;
try
OldFile := FCurrentFile;
FCurrentFile := ExpandFileName(FName);
FCurrentFileType := ft;
FSectionList.ProgressStart := 75;
htProgressInit;
InitLoad;
CaretPos := 0;
Sel1 := -1;
if Assigned(FOnSoundRequest) then
FOnSoundRequest(Self, '', 0, True);
FDocumentSource := Source;
if Assigned(FOnParseBegin) then
FOnParseBegin(Self, FDocumentSource);
if Ft = HTMLType then
ParseHTMLString(FDocumentSource, FSectionList, FOnInclude, FOnSoundRequest, HandleMeta, FOnLink)
else
ParseTextString(FDocumentSource, FSectionList);
SetupAndLogic;
CheckVisitedLinks;
if (Dest <> '') and PositionTo(Dest) then {change position, if applicable}
else if (FCurrentFile = '') or (FCurrentFile <> OldFile) then
begin
ScrollTo(0);
HScrollBar.Position := 0;
end;
{else if same file leave position alone}
PaintPanel.Invalidate;
finally
htProgressEnd;
SetProcessing(False);
DontDraw := False;
end;
end;
{----------------ThtmlViewer.LoadFromStream}
procedure ThtmlViewer.LoadFromStream(const AStream: TStream; const Reference: string);
var
Stream: TMemoryStream;
S: string;
begin
Stream := TMemoryStream.Create;
try
Stream.LoadFromStream(AStream);
SetLength(S, Stream.Size);
Move(Stream.Memory^, S[1], Stream.Size);
LoadString(S, Reference, HTMLType);
if (FRefreshDelay > 0) and Assigned(FOnMetaRefresh) then
FOnMetaRefresh(Self, FRefreshDelay, FRefreshURL);
finally
Stream.Free;
end;
end;
procedure ThtmlViewer.DoImage(Sender: TObject; const SRC: string; var Stream: TMemoryStream);
begin
Stream := FImageStream;
end;
{----------------ThtmlViewer.LoadStream}
procedure ThtmlViewer.LoadStream(const URL: string; AStream: TMemoryStream; ft: ThtmlFileType);
var
SaveOnImageRequest: TGetImageEvent;
SBuffer: string;
begin
if FProcessing or not Assigned(AStream) then Exit;
SetProcessing(True);
FRefreshDelay := 0;
DontDraw := True;
try
FSectionList.ProgressStart := 75;
htProgressInit;
InitLoad;
CaretPos := 0;
Sel1 := -1;
if ft in [HTMLType, TextType] then
begin
SetLength(FDocumentSource, AStream.Size);
Move(AStream.Memory^, FDocumentSource[1], AStream.Size);
end
else FDocumentSource := '';
if Assigned(FOnParseBegin) then
FOnParseBegin(Self, FDocumentSource);
if ft = HTMLType then
begin
if Assigned(FOnSoundRequest) then
FOnSoundRequest(Self, '', 0, True);
ParseHTMLString(FDocumentSource, FSectionList, FOnInclude, FOnSoundRequest, HandleMeta, FOnLink);
SetupAndLogic;
end
else if ft = TextType then
begin
ParseTextString(FDocumentSource, FSectionList);
SetupAndLogic;
end
else
begin
SaveOnImageRequest := FOnImageRequest;
SetOnImageRequest(DoImage);
FImageStream := AStream;
SBuffer := '<img src="'+URL+'">';
try
ParseHTMLString(SBuffer, FSectionList, Nil, Nil, Nil, Nil);
SetupAndLogic;
finally
SetOnImageRequest(SaveOnImageRequest);
end;
end;
ScrollTo(0);
HScrollBar.Position := 0;
PaintPanel.Invalidate;
FCurrentFile := URL;
finally
htProgressEnd;
DontDraw := False;
SetProcessing(False);
end;
if (FRefreshDelay > 0) and Assigned(FOnMetaRefresh) then
FOnMetaRefresh(Self, FRefreshDelay, FRefreshURL);
end;
{----------------ThtmlViewer.DoScrollBars}
procedure ThtmlViewer.DoScrollBars;
var
VBar, VBar1, HBar: boolean;
Wid, HWidth, WFactor, WFactor2, VHeight: integer;
ScrollInfo :TScrollInfo;
begin
ScrollWidth := IntMin(ScrollWidth, MaxHScroll);
if FBorderStyle = htNone then
begin
WFactor := 0;
PaintPanel.Top := 0;
PaintPanel.Left := 0;
{$IFNDEF LCL}
BorderPanel.Visible := False;
{$ENDIF}
end
else
begin
WFactor := 1;
PaintPanel.Top := 1;
PaintPanel.Left := 1;
{$IFNDEF LCL}
BorderPanel.Visible := False;
BorderPanel.Visible := True;
{$ENDIF}
end;
WFactor2 := 2*WFactor;
VBar := False;
VBar1 := False;
if (not (htShowVScroll in htOptions) and (FMaxVertical <= Height-WFactor2) and (ScrollWidth <= Width-WFactor2))
or (FScrollBars = ssNone) then
{there are no scrollbars}
HBar := False
else
if FScrollBars in [ssBoth, ssVertical] then
begin {assume a vertical scrollbar}
VBar1 := (FMaxVertical >= Height-WFactor2) or
((FScrollBars in [ssBoth, ssHorizontal]) and
(FMaxVertical >= Height-WFactor2-sbWidth) and
(ScrollWidth > Width-sbWidth-WFactor2));
HBar := (FScrollBars in [ssBoth, ssHorizontal]) and
((ScrollWidth > Width-WFactor2) or
((VBar1 or (htShowVScroll in FOptions)) and
(ScrollWidth > Width-sbWidth-WFactor2)));
VBar := Vbar1 or (htShowVScroll in htOptions);
end
else
{there is no vertical scrollbar}
HBar := (FScrollBars = ssHorizontal) and (ScrollWidth > Width-WFactor2);
if VBar or ((htShowVScroll in FOptions) and (FScrollBars in [ssBoth, ssVertical])) then
Wid := Width - sbWidth
else
Wid := Width;
PaintPanel.Width := Wid - WFactor2;
if HBar then
begin
PaintPanel.Height := Height - WFactor2 - sbWidth;
VHeight := Height - sbWidth - WFactor2;
end
else
Begin
PaintPanel.Height := Height - WFactor2;
VHeight := Height - WFactor2;
end;
HWidth := IntMax(ScrollWidth, Wid-WFactor2);
HScrollBar.Visible := HBar;
HScrollBar.LargeChange := IntMax(1, Wid - 20);
HScrollBar.SetBounds(WFactor, Height-sbWidth-WFactor, Wid -WFactor, sbWidth);
VScrollBar.SetBounds(Width-sbWidth-WFactor, WFactor, sbWidth, VHeight);
VScrollBar.LargeChange := IntMax(1, PaintPanel.Height - VScrollBar.SmallChange);
// LCL port: Added IntMax per HScrollBar above to avoid range-check error.
if htShowVScroll in FOptions then
begin
VScrollBar.Visible := ( FScrollBars in [ssBoth, ssVertical] );
VScrollBar.Enabled := VBar1;
end
else VScrollBar.Visible := VBar;
{$IFNDEF LCL}
HScrollBar.Max := IntMax(0, HWidth);
VScrollBar.SetParams(VScrollBar.Position, PaintPanel.Height+1, 0, FMaxVertical);
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.fMask := SIF_PAGE;
ScrollInfo.nPage := Wid;
SetScrollInfo(HScrollBar.Handle,SB_CTL,ScrollInfo,TRUE);
{$ELSE}
VScrollBar.SetParams(VScrollBar.Position, 0, FMaxVertical, PaintPanel.Height+1);
HScrollBar.SetParams(HScrollBar.Position, 0, IntMax(0, HWidth), Wid);
{$ENDIF}
end;
{----------------ThtmlViewer.DoLogic}
procedure ThtmlViewer.DoLogic;
var
Wid, WFactor: integer;
function HasVScrollbar: boolean;
begin
Result := (FMaxVertical > Height-WFactor) or
((FScrollBars in [ssBoth, ssHorizontal]) and
(FMaxVertical >= Height-WFactor-sbWidth) and
(ScrollWidth > Width-sbWidth-WFactor));
end;
function HasVScrollbar1: boolean;
begin
Result := (FMaxVertical > Height-WFactor) or
((FScrollBars in [ssBoth, ssHorizontal]) and
(FMaxVertical >= Height-WFactor-sbWidth) and
(ScrollWidth > Width-WFactor));
end;
function FSectionListDoLogic(Width: integer): integer;
var
Curs: integer;
begin
Curs := 0;
ScrollWidth := 0;
Result := FSectionList.DoLogic(PaintPanel.Canvas, 0,
Width, ClientHeight-WFactor, 0, ScrollWidth, Curs);
end;
begin
HandleNeeded;
try
DontDraw := True;
if FBorderStyle = htNone then WFactor := 0
else WFactor := 2;
Wid := Width - WFactor;
if FScrollBars in [ssBoth, ssVertical] then
begin
if not (htShowVScroll in FOptions) and (Length(FDocumentSource) < 10000) then
begin {see if there is a vertical scrollbar with full width}
FMaxVertical := FSectionListDoLogic(Wid);
if HasVScrollBar then {yes, there is vertical scrollbar, allow for it}
begin
FMaxVertical := FSectionListDoLogic(Wid-sbWidth);
if not HasVScrollBar1 then
FMaxVertical := FSectionListDoLogic(Wid);
end;
end
else {assume a vertical scrollbar}
FMaxVertical := FSectionListDoLogic(Wid-sbWidth);
end
else {there is no vertical scrollbar}
FMaxVertical := FSectionListDoLogic(Wid);
DoScrollbars;
finally
DontDraw := False;
end;
end;
procedure ThtmlViewer.HTMLPaint(Sender: TObject);
var
ARect: TRect;
begin
if not DontDraw then
begin
ARect := Rect(0, 1, PaintPanel.Width, PaintPanel.Height);
FSectionList.Draw(PaintPanel.Canvas2, ARect, MaxHScroll,
-HScrollBar.Position, 0, 0, 0);
end;
end;
procedure ThtmlViewer.WMSize(var Message: TWMSize);
begin
inherited;
if InCreate then
Exit;
if not FProcessing then
Layout
else
DoScrollBars;
if FMaxVertical < PaintPanel.Height then
Position := 0
else ScrollTo(VScrollBar.Position); {keep aligned to limits}
with HScrollBar do
Position := IntMin(Position, Max - PaintPanel.Width);
end;
procedure ThtmlViewer.Scroll(Sender: TObject; ScrollCode: TScrollCode;
var ScrollPos: Integer);
{only the horizontal scrollbar comes here}
begin
ScrollPos := IntMin(ScrollPos, HScrollBar.Max - PaintPanel.Width);
PaintPanel.Invalidate;
end;
procedure ThtmlViewer.ScrollTo(Y: integer);
begin
Y := IntMin(Y, FMaxVertical - PaintPanel.Height);
Y := IntMax(Y, 0);
VScrollBar.Position := Y;
FSectionList.SetYOffset(Y);
Invalidate;
end;
procedure ThtmlViewer.Layout;
var
OldPos: integer;
begin
if FProcessing then Exit;
SetProcessing(True);
try
OldPos := Position;
FSectionList.ProgressStart := 0;
htProgressInit;
DoLogic;
Position := OldPos; {return to old position after width change}
finally
htProgressEnd;
SetProcessing(False);
end;
end;
function ThtmlViewer.HotSpotClickHandled: boolean;
var
Handled: boolean;
begin
Handled := False;
if Assigned(FOnHotSpotClick) then
FOnHotSpotClick(Self, URL, Handled);
Result := Handled;
end;
procedure ThtmlViewer.TriggerUrlAction;
begin
PostMessage(Handle, wm_UrlAction, 0, 0);
end;
procedure ThtmlViewer.WMUrlAction(var Message: TMessage);
begin
UrlAction;
end;
procedure ThtmlViewer.URLAction;
var
S, Dest: string;
Ext: string[5];
I: integer;
OldPos: integer;
begin
if not HotSpotClickHandled then
begin
OldPos := Position;
S := URL;
I := Pos('#', S); {# indicates a position within the document}
if I = 1 then
begin
if PositionTo(S) then {no filename with this one}
begin
BumpHistory(FCurrentFile, FTitle, OldPos, Nil, FCurrentFileType);
AddVisitedLink(FCurrentFile+S);
end;
end
else
begin
if I >= 1 then
begin
Dest := System.Copy(S, I, Length(S)-I+1); {local destination}
S := System.Copy(S, 1, I-1); {the file name}
end
else
Dest := ''; {no local destination}
S := HTMLExpandFileName(S);
Ext := Uppercase(ExtractFileExt(S));
if (Ext = '.HTM') or (Ext = '.HTML') then
begin {an html file}
if S <> FCurrentFile then
begin
LoadFromFile(S + Dest);
AddVisitedLink(S+Dest);
end
else
if PositionTo(Dest) then {file already loaded, change position}
begin
BumpHistory(FCurrentFile, FTitle, OldPos, Nil, HTMLType);
AddVisitedLink(S+Dest);
end;
end
else if (Ext = '.BMP') or (Ext = '.GIF') or (Ext = '.JPG') or (Ext = '.JPEG')
or (Ext = '.PNG') then
LoadImageFile(S);
end;
{Note: Self may not be valid here}
end;
end;
{----------------ThtmlViewer.AddVisitedLink}
procedure ThtmlViewer.AddVisitedLink(const S: string);
var
I, J: integer;
S1, UrlTmp: string;
begin
if Assigned(FrameOwner) or (FVisitedMaxCount = 0) then
Exit; {TFrameViewer will take care of visited links}
I := Visited.IndexOf(S);
if I = 0 then Exit
else if I < 0 then
begin
for J := 0 to SectionList.LinkList.Count-1 do
with TFontObj(SectionList.LinkList[J]) do
begin
UrlTmp := Url;
if Length(UrlTmp) > 0 then
begin
if Url[1] = '#' then
S1 := FCurrentFile+UrlTmp
else
S1 := HTMLExpandFilename(UrlTmp);
if CompareText(S, S1) = 0 then
Visited := True;
end;
end;
end
else Visited.Delete(I); {thus moving it to the top}
Visited.Insert(0, S);
for I := Visited.Count-1 downto FVisitedMaxCount do
Visited.Delete(I);
end;
{----------------ThtmlViewer.CheckVisitedLinks}
procedure ThtmlViewer.CheckVisitedLinks;
var
I, J: integer;
S, S1: string;
begin
if FVisitedMaxCount = 0 then
Exit;
for I := 0 to Visited.Count-1 do
begin
S := Visited[I];
for J := 0 to SectionList.LinkList.Count-1 do
with TFontObj(SectionList.LinkList[J]) do
begin
if (Url <> '') and (Url[1] = '#') then
S1 := FCurrentFile+Url
else
S1 := HTMLExpandFilename(Url);
if CompareText(S, S1) = 0 then
Visited := True;
end;
end;
end;
{----------------ThtmlViewer.HTMLMouseDown}
procedure ThtmlViewer.HTMLMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
XR, CaretHt: integer;
YR: integer;
InText: boolean;
Dummy : TUrlTarget;
DummyFC: TImageFormControlObj;
DummyTitle: string;
begin
inherited MouseDown(Button, Shift, X, Y);
SetFocus;
HotSpotAction := False;
if MiddleScrollOn then
begin
MiddleScrollOn := False;
PaintPanel.Cursor := Cursor;
MouseScrolling := False;
end
else if (Button = mbMiddle) and not (htNoWheelMouse in htOptions) then {comment this out to disable mouse middle button scrolling}
begin
MiddleScrollOn := True;
MiddleY := Y;
PaintPanel.Cursor := UpDownCursor;
end
else if (Button = mbLeft) then
begin
LeftButtonDown := True;
if not (htNoLinkHilite in FOptions)
or not (guUrl in GetURL(X, Y, Dummy, DummyFC, DummyTitle)) then
HiLiting := True;
with FSectionList do
begin
Sel1 := FindCursor(PaintPanel.Canvas, X, Y+YOff, XR, YR, CaretHt, InText);
if Sel1 > -1 then
begin
if (SelB <> SelE) or (ssShift in Shift) then
InvalidateRect(PaintPanel.Handle, Nil, True);
if (ssShift in Shift) then
if Sel1 < CaretPos then
begin
SelE := CaretPos;
SelB := Sel1;
end
else
begin
SelB := CaretPos;
SelE := Sel1;
end
else
begin
SelB := Sel1;
SelE := Sel1;
CaretPos := Sel1;
end;
end;
LButtonDown(True); {signal to TSectionList}
end;
end;
end;
procedure ThtmlViewer.HTMLTimerTimer(Sender: TObject);
var
Pt: TPoint;
begin
if GetCursorPos(Pt) and (WindowFromPoint(Pt) <> PaintPanel.Handle) then
begin
SectionList.CancelActives;
HTMLTimer.Enabled := False;
if FURL <> '' then
begin
FURL := '';
FTarget := '';
if Assigned(FOnHotSpotCovered) then FOnHotSpotCovered(Self, '');
end;
end;
end;
function ThtmlViewer.PtInObject(X, Y: integer; var Obj: TObject): boolean; {X, Y, are client coord} {css}
var
IX, IY: integer;
begin
Result := PtInRect(ClientRect, Point(X, Y)) and
FSectionList.PtInObject(X, Y+FSectionList.YOff, Obj, IX, IY);
end;
procedure ThtmlViewer.ControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
Dummy : TUrlTarget;
DummyFC: TImageFormControlObj;
begin
if Sender is TFormControlObj then
with TFormControlObj(Sender), TheControl do
begin
FTitleAttr:= Title;
if FTitleAttr = '' then
begin
Dummy := Nil;
GetURL(X+Left, Y+Top, Dummy, DummyFC, FTitleAttr);
if Assigned(Dummy) then
Dummy.Free;
end;
Inherited MouseMove(Shift,X,Y);
end;
end;
function ThtmlViewer.GetTextByIndices(AStart, ALast: integer): WideString;
var
SaveSelB: Integer;
SaveSelE: Integer;
begin
if (AStart >= 0) and (ALast >= 0) and (ALast > AStart) then
with FSectionList do
begin
SaveSelB := SelB;
SaveSelE := SelE;
SelB := Self.FindDisplayPos(AStart, False);
SelE := Self.FindDisplayPos(ALast, False);
Result := GetSelText;
DisplayPosToXY(SelB, FLinkStart.X, FLinkStart.Y);
Dec(FLinkStart.Y, VScrollBar.Position);
SelB := SaveSelB;
SelE := SaveSelE;
end
else Result := '';
end;
{----------------ThtmlViewer.HTMLMouseMove}
procedure ThtmlViewer.HTMLMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
UrlTarget : TUrlTarget;
Url, Target: string;
FormControl: TImageFormControlObj;
Obj: TObject;
IX, IY: integer;
XR, CaretHt: integer;
YR: integer;
InText: boolean;
NextCursor: TCursor;
guResult: guResultType;
begin
Inherited MouseMove(Shift,X,Y);
if MiddleScrollOn then
begin
if not MouseScrolling and (Abs(Y-MiddleY) > ScrollGap) then
begin
MouseScrolling := True;
PostMessage(Handle, wm_MouseScroll, 0, 0);
end;
Exit;
end;
UrlTarget := Nil;
URL := '';
NextCursor := crArrow;
FTitleAttr := '';
guResult := GetURL(X, Y, UrlTarget, FormControl, FTitleAttr);
if guUrl in guResult then
begin
NextCursor := HandCursor;
Url := UrlTarget.Url;
Target := UrlTarget.Target;
FLinkAttributes.Text := UrlTarget.Attr;
FLinkText := GetTextByIndices(UrlTarget.Start, UrlTarget.Last);
UrlTarget.Free;
end;
if guControl in guResult then
NextCursor := HandCursor;
if (Assigned(FOnImageClick) or Assigned(FOnImageOver)) and
FSectionList.PtInObject(X, Y+FSectionList.YOff, Obj, IX, IY) then
begin
if NextCursor <> HandCursor then {in case it's also a Link}
NextCursor := crArrow;
if Assigned(FOnImageOver) then FOnImageOver(Self, Obj, Shift, IX, IY);
end
else if (FSectionList.FindCursor(PaintPanel.Canvas, X, Y+FSectionList.YOff, XR, YR, CaretHt, InText) >= 0)
and InText and (NextCursor <> HandCursor) then
NextCursor := Cursor;
PaintPanel.Cursor := NextCursor;
if ((NextCursor = HandCursor) or (SectionList.ActiveImage <> Nil)) then
HTMLTimer.Enabled := True
else HTMLTimer.Enabled := False;
if (URL <> FURL) or (Target <> FTarget) then
begin
FURL := URL;
FTarget := Target;
if Assigned(FOnHotSpotCovered) then FOnHotSpotCovered(Self, URL);
end;
if (ssLeft in Shift) and not MouseScrolling
and ((Y <= 0) or (Y >= Self.Height)) then
begin
MouseScrolling := True;
PostMessage(Handle, wm_MouseScroll, 0, 0);
end;
if (ssLeft in Shift) and not FNoSelect then
DoHilite(X, Y);
end;
procedure ThtmlViewer.HTMLMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
UrlTarget: TUrlTarget;
FormControl: TImageFormControlObj;
Obj: TObject;
IX, IY: integer;
InImage, TmpLeft: boolean;
Parameters: TRightClickParameters;
AWord: WideString;
St, En: integer;
guResult: guResultType;
I, ThisID: integer;
ParentForm: TCustomForm;
begin
if MiddleScrollOn then
begin
{cancel unless it's middle button and has moved}
if (Button <> mbMiddle) or (Y <> MiddleY) then
begin
MiddleScrollOn := False;
PaintPanel.Cursor := Cursor;
end;
Exit;
end;
inherited MouseUp(Button, Shift, X, Y);
if Assigned(FOnImageClick) or Assigned(FOnRightClick) then
begin
InImage := FSectionList.PtInObject(X, Y+FSectionList.YOff, Obj, IX, IY);
if Assigned(FOnImageClick) and InImage then
FOnImageClick(Self, Obj, Button, Shift, IX, IY);
if (Button = mbRight) and Assigned(FOnRightClick) then
begin
Parameters := TRightClickParameters.Create;
try
if InImage then
begin
Parameters.Image := Obj as TImageObj;
Parameters.ImageX := IX;
Parameters.ImageY := IY;
end;
if guUrl in GetURL(X, Y, UrlTarget, FormControl, FTitleAttr) then
begin
Parameters.URL := UrlTarget.Url;
Parameters.Target := UrlTarget.Target;
UrlTarget.Free;
end;
if GetWordAtCursor(X, Y, St, En, AWord) then
Parameters.ClickWord := AWord;
HTMLTimer.Enabled := False;
FOnRightClick(Self, Parameters);
finally
HTMLTimer.Enabled := True;
Parameters.Free;
end;
end;
end;
if (Button = mbLeft) and not (ssShift in Shift) then
begin
MouseScrolling := False;
DoHilite(X, Y);
Hiliting := False;
FSectionList.LButtonDown(False);
TmpLeft := LeftButtonDown;
LeftButtonDown := False;
if TmpLeft and (FSectionList.SelE <= FSectionList.SelB) then
begin
guResult := GetURL(X, Y, UrlTarget, FormControl, FTitleAttr);
if guControl in guResult then
FormControl.ImageClick(Nil)
else if guUrl in guResult then
begin
FURL := UrlTarget.Url;
FTarget := UrlTarget.Target;
FLinkAttributes.Text := UrlTarget.Attr;
FLinkText := GetTextByIndices(UrlTarget.Start, UrlTarget.Last);
ThisID := UrlTarget.ID;
for I := 0 to LinkList.Count-1 do
with TFontObj(LinkList.Items[I]) do
if (ThisID = UrlTarget.ID) and Assigned(TabControl) then
begin
ParentForm := GetParentForm(TabControl);
if Assigned(ParentForm) and TabControl.CanFocus then
begin
NoJump := True; {keep doc from jumping position on mouse click}
try
ParentForm.ActiveControl := TabControl;
finally
NoJump := False;
end;
end;
break;
end;
UrlTarget.Free;
HotSpotAction := True; {prevent double click action}
URLAction;
{Note: Self pointer may not be valid after URLAction call (TFrameViewer, HistoryMaxCount=0)}
end;
end;
end;
end;
{----------------ThtmlViewer.HTMLMouseWheel}
{$ifdef ver120_plus}
procedure ThtmlViewer.HTMLMouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint);
var
Lines: integer;
begin
Lines := Mouse.WheelScrollLines;
if Lines > 0 then
if WheelDelta > 0 then
VScrollBarPosition := VScrollBarPosition - (Lines * 16)
else
VScrollBarPosition := VScrollBarPosition + (Lines * 16)
else VScrollBarPosition := VScrollBarPosition - WheelDelta div 2;
end;
function ThtmlViewer.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
MousePos: TPoint): Boolean;
begin
result:= inherited DoMouseWheel(shift, wheelDelta, mousePos);
if not result and not (htNoWheelMouse in htOptions) then
begin
HTMLMouseWheel(Self, Shift, WheelDelta, MousePos);
Result := True;
end;
end;
{$endif}
{----------------ThtmlViewer.XYToDisplayPos}
function ThtmlViewer.XYToDisplayPos(X, Y: integer): integer;
var
InText: boolean;
XR, YR, CaretHt: integer;
begin
with SectionList do
Result := FindCursor(PaintPanel.Canvas, X, Y+YOff, XR, YR, CaretHt, InText);
if not InText then
Result := -1;
end;
{----------------ThtmlViewer.GetCharAtPos}
function ThtmlViewer.GetCharAtPos(Pos: integer; var Ch: WideChar;
var Font: TFont): boolean;
var
Obj: TObject;
FO: TFontObj;
Index: integer;
begin
Result := FSectionList.GetChAtPos(Pos, Ch, Obj);
if Result and (Obj is TSection) then
with TSection(Obj) do
begin
FO := Fonts.GetFontObjAt(Pos-StartCurs, Index);
Font := FO.TheFont;
end;
end;
{----------------ThtmlViewer.GetWordAtCursor}
function ThtmlViewer.GetWordAtCursor(X, Y: integer; var St, En: integer; var AWord: WideString): boolean;
var
XR, X1, CaretHt: integer;
YR, Y1: integer;
Obj: TObject;
Ch: WideChar;
InText: boolean;
Tmp: WideString;
function AlphaNum(Ch: WideChar): boolean;
begin
Result := (Ch in [WideChar('a')..WideChar('z'), WideChar('A')..WideChar('Z'), WideChar('0')..WideChar('9')])
or (Ch >= #192);
end;
function GetCh(Pos: integer): WideChar;
var
Ch: WideChar;
Obj1: TObject;
begin
Result := ' ';
if not FSectionList.GetChAtPos(Pos, Ch, Obj1) or (Obj1 <> Obj) then Exit;
Result := Ch;
end;
begin
Result := False;
AWord := '';
with FSectionList do
begin
InText := False;
CaretPos := FindCursor(PaintPanel.Canvas, X,
Y+YOff, XR, YR, CaretHt, InText);
CursorToXy(PaintPanel.Canvas, CaretPos, X1, Y1);
if InText then {else cursor is past end of row}
begin
en := CaretPos;
st := en-1;
if GetChAtPos(en, Ch, Obj) and AlphaNum(Ch) then
begin
AWord := Ch;
Result := True;
Inc(en);
Ch := GetCh(en);
while AlphaNum(Ch) do
begin
Tmp := Ch; {Delphi 3 needs this nonsense}
AWord := AWord + Tmp;
Inc(en);
Ch := GetCh(en);
end;
if St >= 0 then
begin
Ch := GetCh(st);
while (st >= 0) and AlphaNum(Ch) do
begin
System.Insert(Ch, AWord, 1);
Dec(st);
if St >= 0 then
Ch := GetCh(St);
end;
end;
end;
end;
end;
end;
{----------------ThtmlViewer.HTMLMouseDblClk}
procedure ThtmlViewer.HTMLMouseDblClk(Message: TWMMouse);
var
st, en: integer;
AWord: WideString;
begin
FSectionList.LButtonDown(True);
if FProcessing or HotSpotAction then Exit;
if not FNoSelect and GetWordAtCursor(Message.XPos, Message.YPos, St, En, AWord) then
begin
FSectionList.SelB := st+1;
FSectionList.SelE := en;
FCaretPos := st+1;
InvalidateRect(PaintPanel.Handle, Nil, True);
end;
if Assigned(FOnMouseDouble) then
with Message do
FOnMouseDouble(Self, mbLeft, KeysToShiftState(Keys), XPos, YPos);
end;
procedure ThtmlViewer.DoHilite(X, Y: integer);
var
Curs, YR, YWin: integer;
XR, CaretHt: integer;
InText: boolean;
begin
if Hiliting and (Sel1 >= 0) then
with FSectionList do
begin
YWin := IntMin(IntMax(0, Y), Height);
Curs := FindCursor(PaintPanel.Canvas, X, YWin+YOff, XR, YR, CaretHt, InText);
if (Curs >= 0) and not FNoSelect then
begin
if Curs > Sel1 then
begin
SelE := Curs;
SelB := Sel1;
end
else
begin
SelB := Curs;
SelE := Sel1;
end;
InvalidateRect(PaintPanel.Handle, Nil, True);
end;
CaretPos := Curs;
end;
end;
{----------------ThtmlViewer.WMMouseScroll}
procedure ThtmlViewer.WMMouseScroll(var Message: TMessage);
const
Ticks: DWord = 0;
var
Pos: integer;
Pt: TPoint;
begin
GetCursorPos(Pt);
Ticks := 0;
with VScrollBar do
begin
Pt := PaintPanel.ScreenToClient(Pt);
while MouseScrolling and (LeftButtonDown and((Pt.Y <= 0) or (Pt.Y > Self.Height)))
or (MiddleScrollOn and (Abs(Pt.Y - MiddleY) > ScrollGap)) do
begin
if GetTickCount > Ticks +100 then
begin
Ticks := GetTickCount;
Pos := Position;
if LeftButtonDown then
begin
if Pt.Y < -15 then
Pos := Position - SmallChange * 8
else if Pt.Y <= 0 then
Pos := Position - SmallChange
else if Pt.Y > Self.Height+15 then
Pos := Position + SmallChange * 8
else
Pos := Position + SmallChange;
end
else
begin {MiddleScrollOn}
if Pt.Y-MiddleY < -3*ScrollGap then
Pos := Position - 32
else if Pt.Y-MiddleY < -ScrollGap then
Pos := Position - 8
else if Pt.Y-MiddleY > 3*ScrollGap then
Pos := Position + 32
else if Pt.Y-MiddleY > ScrollGap then
Pos := Position + 8;
if Pos < Position then
PaintPanel.Cursor := UpOnlyCursor
else if Pos > Position then
PaintPanel.Cursor := DownOnlyCursor;
end;
Pos := IntMax(0, IntMin(Pos, FMaxVertical - PaintPanel.Height));
FSectionList.SetYOffset(Pos);
SetPosition(Pos);
DoHilite(Pt.X, Pt.Y);
PaintPanel.Invalidate;
GetCursorPos(Pt);
Pt := PaintPanel.ScreenToClient(Pt);
end;
Application.ProcessMessages;
Application.ProcessMessages;
Application.ProcessMessages;
Application.ProcessMessages;
end;
end;
MouseScrolling := False;
if MiddleScrollOn then
PaintPanel.Cursor := UpDownCursor;
end;
function ThtmlViewer.PositionTo(Dest: string): boolean;
var
I: integer;
Obj: TObject;
begin
Result := False;
If Dest = '' then Exit;
if Dest[1] = '#' then
System.Delete(Dest, 1, 1);
I := FNameList.IndexOf(UpperCase(Dest));
if I > -1 then
begin
Obj := FNameList.Objects[I];
if (Obj is TIDObject) then
ScrollTo(TIDObject(Obj).YPosition);
HScrollBar.Position := 0;
Result := True;
AddVisitedLink(FCurrentFile+'#'+Dest);
end;
end;
function ThtmlViewer.GetURL(X, Y: integer; var UrlTarg: TUrlTarget;
var FormControl: TImageFormControlObj; var ATitle: string): guResultType;
begin
Result := FSectionList.GetURL(PaintPanel.Canvas, X, Y+FSectionList.YOff,
UrlTarg, FormControl, ATitle);
end;
procedure THTMLViewer.SetViewImages(Value: boolean);
var
OldPos: integer;
OldCursor: TCursor;
begin
if (Value <> FSectionList.ShowImages) and not FProcessing then
begin
OldCursor := Screen.Cursor;
try
Screen.Cursor := crHourGlass;
SetProcessing(True);
FSectionList.ShowImages := Value;
if FSectionList.Count > 0 then
begin
FSectionList.GetBackgroundBitmap; {load any background bitmap}
OldPos := Position;
DoLogic;
Position := OldPos;
Invalidate;
end;
finally
Screen.Cursor := OldCursor;
SetProcessing(False);
end;
end;
end;
{----------------ThtmlViewer.InsertImage}
function ThtmlViewer.InsertImage(const Src: string; Stream: TMemoryStream): boolean;
var
OldPos: integer;
ReFormat: boolean;
begin
Result := False;
if FProcessing then Exit;
try
SetProcessing(True);
FSectionList.InsertImage(Src, Stream, Reformat);
FSectionList.GetBackgroundBitmap; {in case it's the one placed}
if Reformat then
if FSectionList.Count > 0 then
begin
FSectionList.GetBackgroundBitmap; {load any background bitmap}
OldPos := Position;
DoLogic;
Position := OldPos;
end;
Invalidate;
finally
SetProcessing(False);
Result := True;
end;
end;
function THTMLViewer.GetBase: string;
begin
Result := FBase;
end;
procedure THTMLViewer.SetBase(Value: string);
begin
FBase := Value;
FBaseEx := Value;
end;
function THTMLViewer.GetBaseTarget: string;
begin
Result := FBaseTarget;
end;
function THTMLViewer.GetTitle: string;
begin
Result := FTitle;
end;
function THTMLViewer.GetCurrentFile: string;
begin
Result := FCurrentFile;
end;
function THTMLViewer.GetViewImages: boolean;
begin
Result := FSectionList.ShowImages;
end;
procedure THTMLViewer.SetColor(Value: TColor);
begin
if FProcessing then Exit;
FBackground := Value;
FSectionList.Background:= Value;
PaintPanel.Color := Value;
Invalidate;
end;
procedure THTMLViewer.SetBorderStyle(Value: THTMLBorderStyle);
begin
if Value <> FBorderStyle then
begin
FBorderStyle := Value;
DrawBorder;
end;
end;
procedure ThtmlViewer.KeyDown(var Key: Word; Shift: TShiftState);
var
Pos: integer;
OrigPos: integer;
TheChange: integer;
begin
inherited KeyDown(Key, Shift);
if Shift <> [] then
Exit;
if MiddleScrollOn then
begin
MiddleScrollOn := False;
PaintPanel.Cursor := Cursor;
Exit;
end;
with VScrollBar do
if Key in [VK_PRIOR, VK_NEXT, VK_UP, VK_DOWN, VK_HOME, VK_END] then
begin
Pos := Position;
OrigPos := Pos;
case Key of
VK_PRIOR : Dec(Pos, LargeChange);
VK_NEXT : Inc(Pos, LargeChange);
VK_UP : Dec(Pos, SmallChange);
VK_DOWN : Inc(Pos, SmallChange);
VK_Home : Pos := 0;
VK_End : Pos := FMaxVertical;
end;
if Pos < 0 then Pos := 0;
Pos := IntMax(0, IntMin(Pos, FMaxVertical - PaintPanel.Height));
Position := Pos;
FSectionList.SetYOffset(Pos);
TheChange := OrigPos-Pos;
if not BGFixed and (abs(TheChange) = SmallChange) then
begin {update only the scrolled part}
ScrollWindow(PaintPanel.Handle, 0, TheChange, NIL, NIL);
PaintPanel.Update;
end
else PaintPanel.Invalidate;
end;
with HScrollBar do
if Key in [VK_LEFT, VK_RIGHT] then
begin
Pos := Position;
case Key of
VK_LEFT : Dec(Pos, SmallChange);
VK_RIGHT : Inc(Pos, SmallChange);
end;
if Pos < 0 then Pos := 0;
Pos := IntMin(Pos, Max - PaintPanel.Width);
Position := Pos;
PaintPanel.Invalidate;
end;
end;
procedure ThtmlViewer.WMGetDlgCode(var Message: TMessage);
begin
Message.Result := DLGC_WantArrows; {else don't get the arrow keys}
end;
function ThtmlViewer.GetPosition: integer;
var
Index: integer;
TopPos, Pos: integer;
S: TSectionBase;
begin
Pos := integer(VScrollBar.Position);
S:= FSectionList.FindSectionAtPosition(Pos, TopPos, Index);
if Assigned(S) then
Result := integer(Index+1) shl 16 + ((Pos - TopPos) and $FFFF)
else Result := Pos;
{Hiword is section # plus 1, Loword is displacement from top of section
HiWord = 0 is top of display}
end;
procedure ThtmlViewer.SetPosition(Value: integer);
var
TopPos: integer;
begin
if HiWord(Value) = 0 then
ScrollTo(LoWord(Value))
else if (Hiword(Value)-1 < FSectionList.PositionList.Count) then
begin
TopPos := TSectionBase(FSectionList.PositionList[HiWord(Value)-1]).YPosition;
ScrollTo(TopPos + LoWord(Value));
end;
end;
function ThtmlViewer.GetScrollPos: integer;
begin
Result := VScrollBar.Position;
end;
procedure ThtmlViewer.SetScrollPos(Value: integer);
begin
if Value < 0 then Value := 0;
Value := IntMin(Value, FMaxVertical - PaintPanel.Height);
if Value <> GetScrollPos then
ScrollTo(Value);
end;
function ThtmlViewer.GetScrollBarRange: integer;
begin
Result := FMaxVertical - PaintPanel.Height;
end;
function ThtmlViewer.GetHScrollPos: integer;
begin
Result := HScrollBar.Position;
end;
procedure ThtmlViewer.SetHScrollPos(Value: integer);
begin
if Value < 0 then Value := 0;
Value := IntMin(Value, HScrollBar.Max-PaintPanel.Width);
HScrollbar.Position := Value;
Invalidate;
end;
function ThtmlViewer.GetHScrollBarRange: integer;
begin
Result := HScrollBar.Max - PaintPanel.Width;
end;
function ThtmlViewer.GetPalette: HPALETTE;
begin
if ThePalette <> 0 then
Result := ThePalette
else Result := inherited GetPalette;
Invalidate;
end;
function ThtmlViewer.HTMLExpandFilename(const Filename: string): string;
var
Tmp: string;
begin
{pass http: and other protocols except for file:///}
if (Pos('://', Filename) > 1) and (Pos('file://', Lowercase(Filename)) = 0) then
Result := Filename
else
begin
Result := HTMLServerToDos(Trim(Filename), FServerRoot);
{$IFDEF MSWINDOWS}
if Pos('\', Result) = 1 then
Result := ExpandFilename(Result)
else if (Pos(':', Result)<> 2) and (Pos('\\', Result) <> 1) then
{$ELSE}
if Pos('/', Result) > 1 then
Result := ExpandFilename(Result)
else if (Pos('/', Result) <> 1) then
{$ENDIF}
if CompareText(FBase, 'DosPath') = 0 then {let Dos find the path}
else if FBase <> '' then
begin
Tmp := ExtractFilePath(HTMLToDos(FBase));
Result := ExpandFilename(Tmp + Result)
end
else
Result := ExpandFilename(ExtractFilePath(FCurrentFile) + Result);
end;
end;
{----------------ThtmlViewer.BumpHistory}
procedure ThtmlViewer.BumpHistory(const FileName, Title: string;
OldPos: integer; OldFormData: TFreeList; ft: ThtmlFileType);
var
I: integer;
PO: PositionObj;
SameName: boolean;
begin
SameName := FileName = FCurrentFile;
if (FHistoryMaxCount > 0) and (FCurrentFile <> '') and
((not SameName) or (FCurrentFileType <> ft)
or (OldPos <> Position)) then
with FHistory do
begin
if (Count > 0) and (Filename <> '') then
begin
Strings[FHistoryIndex] := Filename;
with PositionObj(FPositionHistory[FHistoryIndex]) do
begin
Pos := OldPos;
FileType := ft;
if not SameName then {only stored when documents changed}
FormData := OldFormData
else OldFormData.Free;
end;
FTitleHistory[FHistoryIndex] := Title;
for I := 0 to FHistoryIndex-1 do
begin
Delete(0);
FTitleHistory.Delete(0);
PositionObj(FPositionHistory[0]).Free;
FPositionHistory.Delete(0);
end;
end;
FHistoryIndex := 0;
Insert(0, FCurrentFile);
PO := PositionObj.Create;
PO.Pos := Position;
PO.FileType := FCurrentFileType;
FPositionHistory.Insert(0, PO);
FTitleHistory.Insert(0, FTitle);
if Count > FHistoryMaxCount then
begin
Delete(FHistoryMaxCount);
FTitleHistory.Delete(FHistoryMaxCount);
PositionObj(FPositionHistory[FHistoryMaxCount]).Free;
FPositionHistory.Delete(FHistoryMaxCount);
end;
if Assigned(FOnHistoryChange) then FOnHistoryChange(Self);
end
else OldFormData.Free;
end;
procedure ThtmlViewer.SetHistoryIndex(Value: integer);
var
I: integer;
function GetLowestSameFileIndex(Start: integer): integer;
begin
Result := Start;
while (Result > 0) and (FHistory[Result-1] = FCurrentFile) do
Dec(Result);
end;
begin
with FHistory do
if (Value <> FHistoryIndex) and (Value >= 0) and (Value < Count)
and not FProcessing then
begin
if FCurrentFile <> '' then
begin {save the current information}
Strings[FHistoryIndex] := FCurrentFile;
with PositionObj(FPositionHistory[FHistoryIndex]) do
begin
Pos := Position;
FileType := FCurrentFileType;
I := GetLowestSameFileIndex(FHistoryIndex);
PositionObj(FPositionHistory[I]).FormData := GetFormData;
end;
FTitleHistory[FHistoryIndex] := FTitle;
end;
with PositionObj(FPositionHistory[Value]) do
begin {reestablish the new desired history position}
if (FCurrentFile <> Strings[Value]) or (FCurrentFileType <> FileType) then
Self.LoadFile(Strings[Value], FileType);
Position := Pos;
I := GetLowestSameFileIndex(Value);
with PositionObj(FPositionHistory[I]) do
begin
SetFormData(FormData); {reload the forms if any}
FormData.Free;
FormData := Nil;
end;
end;
FHistoryIndex := Value;
if Assigned(FOnHistoryChange) then FOnHistoryChange(Self);
end;
end;
procedure ThtmlViewer.SetHistoryMaxCount(Value: integer);
begin
if (Value = FHistoryMaxCount) or (Value < 0) then Exit;
if Value < FHistoryMaxCount then
ClearHistory;
FHistoryMaxCount := Value;
end;
procedure ThtmlViewer.ClearHistory;
var
CountWas: integer;
begin
CountWas := FHistory.Count;
FHistory.Clear;
FTitleHistory.Clear;
FPositionHistory.Clear;
FHistoryIndex := 0;
FCurrentFile := '';
if (CountWas > 0) and Assigned(FOnHistoryChange) then
FOnHistoryChange(Self);
end;
function ThtmlViewer.GetPreFontName: TFontName;
begin
Result := FPreFontName;
end;
procedure ThtmlViewer.SetPreFontName(Value: TFontName);
begin
if CompareText(Value, FSectionList.PreFontName) <> 0 then
begin
FPreFontName := Value;
FSectionList.PreFontName := Value;
end;
end;
procedure ThtmlViewer.SetFontSize(Value: integer);
begin
FFontSize := Value;
end;
procedure ThtmlViewer.SetCharset(Value: TFontCharset);
begin
FCharset := Value;
end;
function ThtmlViewer.GetFormControlList: TList;
begin
Result := FSectionList.FormControlList;
end;
function ThtmlViewer.GetNameList: TStringList;
begin
Result := FNameList;
end;
function ThtmlViewer.GetLinkList: TList;
begin
Result := FSectionList.LinkList;
end;
procedure ThtmlViewer.SetHotSpotColor(Value: TColor);
begin
FHotSpotColor := Value;
FSectionList.HotSpotColor := Value;
end;
procedure ThtmlViewer.SetVisitedColor(Value: TColor);
begin
FVisitedColor := Value;
FSectionList.LinkVisitedColor := Value;
end;
procedure ThtmlViewer.SetActiveColor(Value: TColor);
begin
FOverColor := Value;
FSectionList.LinkActiveColor := Value;
end;
procedure ThtmlViewer.SetVisitedMaxCount(Value: integer);
var
I: integer;
begin
Value := IntMax(Value, 0);
if Value <> FVisitedMaxCount then
begin
FVisitedMaxCount := Value;
if FVisitedMaxCount = 0 then
begin
Visited.Clear;
for I := 0 to SectionList.LinkList.Count-1 do
TFontObj(LinkList[I]).Visited := False;
Invalidate;
end
else
begin
FVisitedMaxCount := Value;
for I := Visited.Count-1 downto FVisitedMaxCount do
Visited.Delete(I);
end;
end;
end;
function ThtmlViewer.GetCursor: TCursor;
begin
Result := inherited Cursor;
end;
procedure ThtmlViewer.SetCursor(Value: TCursor);
begin
if Value = OldThickIBeamCursor then {no longer used}
Value := crIBeam;
inherited Cursor := Value;
end;
function ThtmlViewer.FullDisplaySize(FormatWidth: integer): TSize;
var
Curs: integer;
CopyList: TSectionList;
begin
Result.cx := 0; {error return}
Result.cy := 0;
if FormatWidth > 0 then
begin
CopyList := TSectionList.CreateCopy(FSectionList);
try
Curs := 0;
Result.cy := CopyList.DoLogic(PaintPanel.Canvas, 0, FormatWidth, 300, 0, Result.cx, Curs);
finally
CopyList.Free;
end;
end;
end;
{----------------CalcBackgroundLocationAndTiling}
procedure CalcBackgroundLocationAndTiling(const PRec: PtPositionRec; ARect: TRect;
XOff, YOff, IW, IH, BW, BH: integer; var X, Y, X2, Y2: integer);
{PRec has the CSS information on the background image, it's starting location and
whether it is tiled in x, y, neither, or both.
ARect is the cliprect, no point in drawing tiled images outside it.
XOff, YOff are offsets which allow for the fact that the viewable area may not be at 0,0.
IW, IH are the total width and height of the document if you could see it all at once.
BW, BH are bitmap dimensions used to calc tiling.
X, Y are the position (window coordinates) where the first background iamge will be drawn.
X2, Y2 are tiling limits. X2 and Y2 may be such that 0, 1, or many images will
get drawn. They're calculated so that only images within ARect are drawn.
}
var
I: integer;
P: array[1..2] of integer;
begin
{compute the location of the prime background image. Tiling can go either way
from this image}
P[1] := 0; P[2] := 0;
for I := 1 to 2 do {I = 1 is X info, I = 2 is Y info}
with PRec[I] do
begin
case PosType of
pTop:
P[I] := - YOff;
pCenter:
if I = 1 then
P[1] := IW div 2 - BW div 2 - XOff
else P[2] := IH div 2 - BH div 2 - YOff;
pBottom:
P[I] := IH - BH - YOff;
pLeft:
P[I] := -XOff;
pRight:
P[I] := IW - BW - XOff;
PPercent:
if I = 1 then
P[1] := ((IW-BW) * Value) div 100 - XOff
else P[2] := ((IH-BH) * Value div 100) - YOff;
pDim:
if I = 1 then
P[I] := Value-XOff
else P[I] := Value-YOff;
end;
end;
{Calculate the tiling keeping it within the cliprect boundaries}
X := P[1];
Y := P[2];
if PRec[2].RepeatD then
begin {y repeat}
{figure a starting point for tiling. This will be less that one image height
outside the cliprect}
if Y < ARect.Top then
Y := Y+ ((ARect.Top-Y)div BH)*BH
else if Y > ARect.Top then
Y := Y - ((Y-ARect.Top)div BH)*BH - BH;
Y2 := ARect.Bottom;
end
else
begin {a single image or row}
Y2 := Y; {assume it's not in the cliprect and won't be output}
if not((Y > ARect.Bottom) or (Y+BH < ARect.Top)) then
Inc(Y2); {it is in the clip rect, show it}
end;
if PRec[1].RepeatD then
begin {x repeat}
{figure a starting point for tiling. This will be less that one image width
outside the cliprect}
if X < ARect.Left then
X := X+ ((ARect.Left-X)div BW)*BW
else if X > ARect.Left then
X := X - ((X-ARect.Left)div BW)*BW - BW;
X2 := ARect.Right;
end
else
begin {single image or column}
X2 := X; {assume it's not in the cliprect and won't be output}
if not((X > ARect.Right) or (X+BW < ARect.Left)) then
Inc(X2); {it is in the clip rect, show it}
end;
end;
{----------------DrawBackground}
procedure DrawBackground(ACanvas: TCanvas; ARect: TRect; XStart, YStart, XLast, YLast: integer;
Image: TGpObject; Mask: TBitmap; AniGif: TGifImage; BW, BH: integer; BGColor: TColor);
{draw the background color and any tiled images on it}
{ARect, the cliprect, drawing outside this will not show but images may overhang
XStart, YStart are first image position already calculated for the cliprect and parameters.
XLast, YLast Tiling stops here.
BW, BH bitmap dimensions.
}
var
X, Y: integer;
OldBrush: HBrush;
OldPal: HPalette;
DC: HDC;
OldBack, OldFore: TColor;
Bitmap: TBitmap;
graphics: TGpGraphics;
begin
DC := ACanvas.handle;
if DC <> 0 then
begin
OldPal := SelectPalette(DC, ThePalette, False);
RealizePalette(DC);
ACanvas.Brush.Color := BGColor or PalRelative;
OldBrush := SelectObject(DC, ACanvas.Brush.Handle);
OldBack := SetBkColor(DC, clWhite);
OldFore := SetTextColor(DC, clBlack);
try
ACanvas.FillRect(ARect); {background color}
if Assigned(AniGif) then {tile the animated gif}
begin
Y := YStart;
while Y < YLast do
begin
X := XStart;
while X < XLast do
begin
AniGif.Draw(ACanvas,X, Y, BW, BH);
Inc(X, BW);
end;
Inc(Y, BH);
end;
end
else if Assigned(Image) then {tile the bitmap}
if Image is TBitmap then
begin
Bitmap := TBitmap(Image);
Y := YStart;
while Y < YLast do
begin
X := XStart;
while X < XLast do
begin
if Mask = Nil then
BitBlt(DC, X, Y, BW, BH, Bitmap.Canvas.Handle, 0, 0, SRCCOPY)
else
begin
BitBlt(dc, X, Y, BW, BH, Bitmap.Canvas.Handle, 0, 0, SrcInvert);
BitBlt(dc, X, Y, BW, BH, Mask.Canvas.Handle, 0, 0, SrcAnd);
BitBlt(dc, X, Y, BW, BH, Bitmap.Canvas.Handle, 0, 0, SrcPaint);
end;
Inc(X, BW);
end;
Inc(Y, BH);
end;
end
{$ifndef NoMetafile}
else if Image is ThtMetafile then
begin
Y := YStart;
try
while Y < YLast do
begin
X := XStart;
while X < XLast do
begin
ACanvas.Draw(X, Y, ThtMetaFile(Image));
Inc(X, BW);
end;
Inc(Y, BH);
end;
except
end;
end
{$endif}
else
begin
Y := YStart;
graphics := TGPGraphics.Create(DC);
try
while Y < YLast do
begin
X := XStart;
while X < XLast do
begin
graphics.DrawImage(TGpImage(Image), X, Y, BW, BH);
Inc(X, BW);
end;
Inc(Y, BH);
end;
except
end;
Graphics.Free;
end;
finally
SelectObject(DC, OldBrush);
SelectPalette(DC, OldPal, False);
RealizePalette(DC);
SetBkColor(DC, OldBack);
SetTextColor(DC, OldFore);
end;
end;
end;
{----------------ThtmlViewer.DrawBackground2}
procedure ThtmlViewer.DrawBackground2(ACanvas: TCanvas; ARect: TRect; XStart, YStart, XLast, YLast: integer;
Image: TGpObject; Mask: TBitmap; BW, BH: integer; BGColor: TColor);
{Called by DoBackground2 (Print and PrintPreview)}
{draw the background color and any tiled images on it}
{ARect, the cliprect, drawing outside this will not show but images may overhang
XStart, YStart are first image position already calculated for the cliprect and parameters.
XLast, YLast Tiling stops here.
BW, BH Image dimensions.
}
var
X, Y: integer;
OldBrush: HBrush;
OldPal: HPalette;
DC: HDC;
OldBack, OldFore: TColor;
Bitmap: TBitmap;
begin
DC := ACanvas.handle;
if DC <> 0 then
begin
OldPal := SelectPalette(DC, ThePalette, False);
RealizePalette(DC);
ACanvas.Brush.Color := BGColor or PalRelative;
OldBrush := SelectObject(DC, ACanvas.Brush.Handle);
OldBack := SetBkColor(DC, clWhite);
OldFore := SetTextColor(DC, clBlack);
try
ACanvas.FillRect(ARect); {background color}
if Assigned(Image) then {tile the Image}
if Image is TBitmap then
begin
Bitmap := TBitmap(Image);
Y := YStart;
while Y < YLast do
begin
X := XStart;
while X < XLast do
begin
if Mask = Nil then
PrintBitmap(ACanvas, X, Y, BW, BH, Bitmap.Handle)
else
begin
PrintTransparentBitmap3(ACanvas, X, Y, BW, BH, Bitmap, Mask, 0, Bitmap.Height);
end;
Inc(X, BW);
end;
Inc(Y, BH);
end;
end
{$ifndef NoMetafile}
else if Image is ThtMetafile then
begin
Y := YStart;
try
while Y < YLast do
begin
X := XStart;
while X < XLast do
begin
ACanvas.Draw(X, Y, ThtMetaFile(Image));
Inc(X, BW);
end;
Inc(Y, BH);
end;
except
end;
end
{$endif}
else
begin
Y := YStart;
try
while Y < YLast do
begin
X := XStart;
while X < XLast do
begin
StretchPrintGpImageOnColor(ACanvas, TGPImage(Image), X, Y, BW, BH, BGColor);
Inc(X, BW);
end;
Inc(Y, BH);
end;
except
end;
end;
finally
SelectObject(DC, OldBrush);
SelectPalette(DC, OldPal, False);
RealizePalette(DC);
SetBkColor(DC, OldBack);
SetTextColor(DC, OldFore);
end;
end;
end;
procedure ThtmlViewer.DoBackground1(ACanvas: TCanvas; ATop, AWidth, AHeight, FullHeight: integer);
var
ARect: TRect;
Image: TGpObject;
Mask: TBitmap;
PRec: PtPositionRec;
BW, BH, X, Y, X2, Y2, IW, IH, XOff, YOff: integer;
Fixed: boolean;
begin
ARect := Rect(0, 0, AWidth, AHeight);
Image := FSectionList.BackgroundBitmap;
if FSectionList.ShowImages and Assigned(Image) then
begin
Mask := FSectionList.BackgroundMask;
BW := GetImageWidth(Image);
BH := GetImageHeight(Image);
PRec := FSectionList.BackgroundPRec;
Fixed := PRec[1].Fixed;
if Fixed then
begin {fixed background}
XOff := 0;
YOff := 0;
IW := AWidth;
IH := AHeight;
end
else
begin {scrolling background}
XOff := 0;
YOff := ATop;
IW := AWidth;
IH := FullHeight;
end;
{Calculate where the tiled background images go}
CalcBackgroundLocationAndTiling(PRec, ARect, XOff, YOff, IW, IH, BW, BH, X, Y, X2, Y2);
DrawBackground(ACanvas, ARect, X, Y, X2, Y2, Image, Mask, Nil, BW, BH, PaintPanel.Color);
end
else
begin {no background image, show color only}
DrawBackground(ACanvas, ARect, 0,0,0,0, Nil, Nil, Nil, 0, 0, PaintPanel.Color);
end;
end;
procedure ThtmlViewer.DoBackground2(ACanvas: TCanvas; ALeft, ATop, AWidth, AHeight: integer; AColor: TColor);
{called by Print and PrintPreview}
var
ARect: TRect;
Image: TGpObject;
Mask: TBitmap;
PRec: PtPositionRec;
BW, BH, X, Y, X2, Y2, IW, IH, XOff, YOff: integer;
NewBitmap, NewMask: TBitmap;
begin
ARect := Rect(ALeft, ATop, ALeft+AWidth, ATop+AHeight);
Image := FSectionList.BackgroundBitmap;
if FSectionList.ShowImages and Assigned(Image) then
begin
Mask := FSectionList.BackgroundMask;
BW := GetImageWidth(Image);
BH := GetImageHeight(Image);
PRec := FSectionList.BackgroundPRec;
XOff := -ALeft;
YOff := -ATop;
IW := AWidth;
IH := AHeight;
{Calculate where the tiled background images go}
CalcBackgroundLocationAndTiling(PRec, ARect, XOff, YOff, IW, IH, BW, BH, X, Y, X2, Y2);
if (BW = 1) or (BH = 1) then
begin {this is for people who try to tile 1 pixel images}
NewBitmap := EnlargeImage(Image, X2-X, Y2-Y);
try
if Assigned(Mask) then
NewMask := TBitmap(EnlargeImage(Mask, X2-X, Y2-Y))
else NewMask := Nil;
try
DrawBackground2(ACanvas, ARect, X, Y, X2, Y2, NewBitmap, NewMask, NewBitmap.Width, NewBitmap.Height, AColor);
finally
NewMask.Free;
end;
finally
NewBitmap.Free;
end;
end
else
DrawBackground2(ACanvas, ARect, X, Y, X2, Y2, Image, Mask, BW, BH, AColor);
end
else
begin {no background image, show color only}
DrawBackground2(ACanvas, ARect, 0,0,0,0, Nil, Nil, 0, 0, AColor);
end;
end;
type
EExcessiveSizeError = Class(Exception);
{$IFNDEF LCL}
function ThtmlViewer.MakeMetaFile(YTop, FormatWidth, Width, Height: integer): TMetaFile;
var
CopyList: TSectionList;
Dummy: integer;
Curs: integer;
Canvas: TMetaFileCanvas;
DocHeight: integer;
begin
Result := Nil;
if FProcessing or (FSectionList.Count = 0) then
Exit;
if Height > 4000 then
Raise EExcessiveSizeError.Create('Vertical Height exceeds 4000');
CopyList := TSectionList.CreateCopy(FSectionList);
try
Result := TMetaFile.Create;
Result.Width := Width;
Result.Height := Height;
Canvas := TMetaFileCanvas.Create(Result, 0);
try
Curs := 0;
DocHeight := CopyList.DoLogic(Canvas, 0, FormatWidth, Height, 0, Dummy, Curs);
DoBackground1(Canvas, YTop, Width, Height, DocHeight);
CopyList.SetYOffset(IntMax(0, YTop));
CopyList.Draw(Canvas, Rect(0, 0, Width, Height), MaxHScroll, 0, 0, 0,0);
except
Result.Free;
Result := Nil;
end;
Canvas.Free;
finally
CopyList.Free;
end;
end;
function ThtmlViewer.MakePagedMetaFiles(Width, Height: integer): TList;
var
ARect, CRect: TRect;
CopyList: TSectionList;
HTop, OldTop, Dummy, Curs, I: integer;
Done: boolean;
VPixels: integer;
Canvas: TMetaFileCanvas;
MF: TMetaFile;
TablePart: TablePartType;
SavePageBottom: Integer;
hrgnClip1: hRgn;
procedure PaintBackground(Canvas: TCanvas; Top, Bot: integer);
begin
Canvas.Brush.Color := CopyList.Background;
Canvas.Brush.Style := bsSolid;
Canvas.FillRect(Rect(0, Top, Width+1, Bot));
end;
begin
Done := False;
Result := Nil;
TablePartRec := Nil;
if FProcessing or (SectionList.Count = 0) then
Exit;
CopyList := TSectionList.CreateCopy(SectionList);
try
CopyList.NoOutput := False;
CopyList.Printing := True;
CopyList.LinkDrawnEvent := FOnLinkDrawn;
Result := TList.Create;
try
HTop := 0;
OldTop := 0;
Curs := 0;
VPixels := 0;
ARect := Rect(0, 0, Width, Height);
while not Done do
begin
MF := TMetaFile.Create;
try
MF.Width := Width;
MF.Height := Height;
Canvas := TMetaFileCanvas.Create(MF, 0);
try
if HTop = 0 then {DoLogic the first time only}
VPixels := CopyList.DoLogic(Canvas, 0, Width, Height, 0, Dummy, Curs);
CopyList.SetYOffset(HTop);
PaintBackground(Canvas, 0, Height);
repeat
if Assigned(TablePartRec) then
TablePart := TablePartRec.TablePart
else TablePart := Normal;
case TablePart of
Normal:
begin
CopyList.Draw(Canvas, ARect, Width, 0, 0, 0,0);
PaintBackground(Canvas, CopyList.PageBottom-HTop, Height+1);
end;
DoHead:
begin
CopyList.SetYOffset(TablePartRec.PartStart);
CRect := ARect;
CRect.Bottom := CRect.Top+TablePartRec.PartHeight;
hrgnClip1 := CreateRectRgn(0, 0, Width+1, CRect.Bottom);
SelectClipRgn(Canvas.Handle, hrgnClip1);
DeleteObject(hrgnClip1);
CopyList.Draw(Canvas, CRect, Width, 0, 0, 0,0);
end;
DoBody1, DoBody3:
begin
CRect := ARect;
CRect.Top := CopyList.PageBottom-1-CopyList.YOff;
CopyList.SetYOffset(TablePartRec.PartStart-CRect.top);
CopyList.Draw(Canvas, CRect, Width, 0+3*Width, 0, 0,0); {off page}
TablePartRec.TablePart := DoBody2;
CRect.Bottom := CopyList.PageBottom-CopyList.YOff+1;
hrgnClip1 := CreateRectRgn(0, CRect.Top, Width+1, CRect.Bottom);
SelectClipRgn(Canvas.Handle, hrgnClip1);
DeleteObject(hrgnClip1);
CopyList.Draw(Canvas, CRect, Width, 0, 0, 0,0); {onpage}
if not Assigned(TablePartRec)
or not (TablePartRec.TablePart in [Normal]) then
PaintBackground(Canvas, CopyList.PageBottom-CopyList.YOff, Height+1);
end;
DoFoot:
begin
SavePageBottom := CopyList.PageBottom;
CRect := ARect;
CRect.Top := CopyList.PageBottom-CopyList.YOff;
CRect.Bottom := CRect.Top + TablePartRec.PartHeight;
hrgnClip1 := CreateRectRgn(0, CRect.Top, Width+1, CRect.Bottom);
SelectClipRgn(Canvas.Handle, hrgnClip1);
DeleteObject(hrgnClip1);
CopyList.SetYOffset(TablePartRec.PartStart-CRect.top);
CopyList.Draw(Canvas, CRect, Width, 0, 0, 0,0);
CopyList.PageBottom := SavePageBottom;
end;
end;
until not Assigned(TablePartRec)
or (TablePartRec.TablePart in [Normal, DoHead, DoBody3]);
finally
Canvas.Free;
end;
except
MF.Free;
Raise;
end;
Result.Add(MF);
HTop := CopyList.PageBottom;
Inc(CopyList.LinkPage);
Application.ProcessMessages;
if (HTop >= VPixels) or (HTop <= OldTop) then {see if done or endless loop}
Done := True;
OldTop := HTop;
end;
except
for I := 0 to Result.Count-1 do
TMetaFile(Result.Items[I]).Free;
FreeAndNil(Result);
Raise;
end;
finally
CopyList.Free;
end;
end;
{$ENDIF}
function ThtmlViewer.MakeBitmap(YTop, FormatWidth, Width, Height: integer): TBitmap;
var
CopyList: TSectionList;
Dummy: integer;
Curs: integer;
DocHeight: integer;
begin
Result := Nil;
if FProcessing or (FSectionList.Count = 0) then
Exit;
if Height > 4000 then
Raise EExcessiveSizeError.Create('Vertical Height exceeds 4000');
CopyList := TSectionList.CreateCopy(FSectionList);
try
Result := TBitmap.Create;
try
Result.HandleType := bmDIB;
Result.PixelFormat := pf24Bit;
Result.Width := Width;
Result.Height := Height;
Curs := 0;
DocHeight := CopyList.DoLogic(Result.Canvas, 0, FormatWidth, Height, 300, Dummy, Curs);
DoBackground1(Result.Canvas, YTop, Width, Height, DocHeight);
CopyList.SetYOffset(IntMax(0, YTop));
CopyList.Draw(Result.Canvas, Rect(0, 0, Width, Height), MaxHScroll, 0, 0, 0,0);
except
Result.Free;
Result := Nil;
end;
finally
CopyList.Free;
end;
end;
function ThtmlViewer.CreateHeaderFooter: ThtmlViewer;
begin
Result := ThtmlViewer.Create(Nil);
Result.Visible := False;
Result.Parent := Parent;
Result.DefBackground := DefBackground;
Result.DefFontName := DefFontName;
Result.DefFontSize := DefFontSize;
Result.DefFontColor := DefFontColor;
Result.CharSet := Charset;
Result.MarginHeight := 0;
with Result.FSectionList do
begin
PrintBackground := True;
PrintTableBackground := True;
end;
end;
procedure ThtmlViewer.Print(FromPage, ToPage: integer);
var
ARect, CRect: TRect;
PrintList: TSectionList;
P1, P2, P3, W, H, HTop, OldTop, Dummy: integer;
Curs: integer;
Done: boolean;
DC : HDC;
PrinterOpen: boolean;
UpperLeftPagePoint, { these will contain Top/Left and Bottom/Right unprintable area}
LowerRightPagePoint: TPoint;
MLeft: integer;
MLeftPrn: integer;
MRightPrn: integer;
MTopPrn: integer;
MBottomPrn: integer;
TopPixels, TopPixelsPrn, HPrn, WPrn: integer;
hrgnClip, hrgnClip1: THandle;
savedFont : TFont ;
savedPen : TPen ;
savedBrush : TBrush ;
Align, ScaledPgHt, ScaledPgWid, VPixels: integer;
FootViewer, HeadViewer: ThtmlViewer;
DeltaMarginTop: Double;
SavePrintMarginTop: Double;
DeltaPixelsPrn: Integer;
DeltaPixels: Integer;
OrigTopPixels: Integer;
OrigTopPixelsPrn: Integer;
OrigHprn: Integer;
OrigH: Integer;
LastPrintMarginTop: Double;
MLeftSide: Integer;
TablePart: TablePartType;
SavePageBottom: Integer;
procedure SaveCanvasItems(Canvas: TCanvas);
begin { preserve current settings of the Canvas}
SavedPen.Assign(Canvas.Pen);
SavedFont.Assign(Canvas.Font);
SavedBrush.Assign(Canvas.Brush);
end;
procedure RestoreCanvasItems(Canvas: TCanvas);
begin { restore initial Canvas settings }
Canvas.Pen.Assign(SavedPen);
Canvas.Font.Assign(SavedFont);
Canvas.Brush.Assign(SavedBrush);
end;
procedure WhiteoutArea(Canvas: TCanvas; Y: integer);
{White out excess printing. Y is top of the bottom area to be blanked.}
begin
Canvas.Brush.Color := clWhite;
Canvas.Brush.Style := bsSolid;
Canvas.Pen.Style := psSolid;
Canvas.Pen.Color := clWhite;
Canvas.Rectangle(MLeft, 0, W + MLeft+1, TopPixels-1);
Canvas.Rectangle(MLeft, Y, W + MLeft+1, TopPixels+H+1);
if (htPrintBackground in FOptions) and (Y-TopPixels < H) then
begin {need to reprint background in whited out area}
hrgnClip1 := CreateRectRgn(MLeftPrn, MulDiv(Y, P3, P2)-2,
MLeftPrn+WPrn, TopPixelsPrn+HPrn);
SelectClipRgn(Canvas.Handle, hrgnClip1);
DeleteObject(hrgnClip1);
DoBackground2(Canvas, MLeft, TopPixels, W, H, PaintPanel.Color);
end;
RestoreCanvasItems(Canvas);
end;
procedure DoHTMLHeaderFooter(Footer: boolean; Event: ThtmlPagePrinted; HFViewer: ThtmlViewer);
var
YOrigin, YOff, Ht: integer;
HFCopyList: TSectionList;
BRect: TRect;
DocHeight, XL, XR: integer;
begin
if not Assigned(Event) then
Exit;
try
XL := MLeft;
XR := MLeft + W;
Event(Self, HFViewer, FPage, PrintList.PageBottom > VPixels, XL, XR, Done); {call event handler}
HFCopyList := TSectionList.CreateCopy(HFViewer.SectionList);
try
HFCopyList.Printing := True;
HFCopyList.ScaleX := fScaleX;
HFCopyList.ScaleY := fScaleY;
Curs := 0;
DocHeight := HFCopyList.DoLogic(vwP.Canvas, 0, XR-XL, 300, 0, Dummy, Curs);
if not Footer then
begin {Header}
YOrigin := 0;
Ht := TopPixels;
YOff := DocHeight-TopPixels;
end
else
begin {Footer}
YOrigin := -(TopPixels+H);
Ht := IntMin(ScaledPgHt-(TopPixels+H), DocHeight);
YOff := 0;
end;
SetWindowOrgEx(DC, 0, YOrigin, nil);
HFViewer.DoBackground2(vwP.Canvas, XL, -YOff, XR-XL, DocHeight, HFViewer.PaintPanel.Color);
HFCopyList.SetYOffset(YOff);
BRect := Rect(XL, 0, XR, Ht);
HFCopyList.Draw(vwP.Canvas, BRect, XR-XL, XL, 0, 0,0);
finally
HFCopyList.Free;
end;
except
end;
end;
begin
Done := False;
FootViewer := Nil;
HeadViewer := Nil;
TablePartRec := Nil;
if Assigned(FOnPageEvent) then
FOnPageEvent(Self, 0, Done);
FPage := 0;
if FProcessing or (FSectionList.Count = 0) then Exit;
PrintList := TSectionList.CreateCopy(FSectionList);
PrintList.SetYOffset(0);
SavePrintMarginTop := FPrintMarginTop;
try
savedFont := TFont.Create ;
savedPen := TPen.Create ;
savedBrush := TBrush.Create ;
try
PrintList.Printing := True;
PrintList.SetBackground(clWhite);
if not assigned(vwP) then
begin
{$IFNDEF LCL}
vwP := TvwPrinter.Create;
OldPrinter := vwSetPrinter(vwP);
{$ELSE}
vwP := Printer;
{$ENDIF}
PrinterOpen := False;
end
else PrinterOpen := True;
FPage := 1;
hrgnClip := 0;
try
with vwP do
begin
if (DocumentTitle <> '') then
vwP.Title := DocumentTitle ;
if not Printing then
BeginDoc
else NewPage;
SaveCanvasItems(Canvas);
DC := Canvas.Handle;
P3 := GetDeviceCaps(DC, LOGPIXELSY);
P1 := GetDeviceCaps(DC, LOGPIXELSX);
P2 := Round(Screen.PixelsPerInch * FPrintScale);
fScaleX := 100.0/P3;
fScaleY := 100.0/P1;
PrintList.ScaleX := fScaleX;
PrintList.ScaleY := fScaleY;
SetMapMode(DC, mm_AnIsotropic);
SetWindowExtEx(DC, P2, P2, Nil);
SetViewPortExtEx(DC, P1,P3, Nil);
{ calculate the amount of space that is non-printable }
{ get PHYSICAL page width }
{$IFNDEF LCL}
LowerRightPagePoint.X := GetDeviceCaps(Printer.Handle, PhysicalWidth);
LowerRightPagePoint.Y := GetDeviceCaps(Printer.Handle, PhysicalHeight);
{$ELSE}
LowerRightPagePoint.X := Printer.PaperSize.PaperRect.PhysicalRect.Right;
LowerRightPagePoint.Y := Printer.PaperSize.PaperRect.PhysicalRect.Bottom;
{$ENDIF}
{ now compute a complete unprintable area rectangle
(composed of 2*width, 2*height) in pixels...}
with LowerRightPagePoint do
begin
Y := Y - Printer.PageHeight;
X := X - Printer.PageWidth;
end;
{ get upper left physical offset for the printer... ->
printable area <> paper size }
{$IFNDEF LCL}
UpperLeftPagePoint.X := GetDeviceCaps(Printer.Handle, PhysicalOffsetX);
UpperLeftPagePoint.Y := GetDeviceCaps(Printer.Handle, PhysicalOffsetY);
{$ELSE}
UpperLeftPagePoint.X := Printer.PaperSize.PaperRect.WorkRect.Left;
UpperLeftPagePoint.Y := Printer.PaperSize.PaperRect.WorkRect.Top;
{$ENDIF}
{ now that we know the TOP and LEFT offset we finally can
compute the BOTTOM and RIGHT offset: }
with LowerRightPagePoint do
begin
x := x - UpperLeftPagePoint.x;
{ we don't want to have negative values}
if x < 0 then
x := 0; { assume no right printing offset }
y := y - UpperLeftPagePoint.y;
{ we don't want to have negative values}
if y < 0 then
y := 0; { assume no bottom printing offset }
end;
{ which results in LowerRightPoint containing the BOTTOM
and RIGHT unprintable
area offset; using these we modify the (logical, true)
borders...}
MLeftPrn := trunc(FPrintMarginLeft/2.54 * P1);
MLeftPrn := MLeftPrn - UpperLeftPagePoint.x; { subtract physical offset }
MLeft := MulDiv(MLeftPrn, P2, P1);
MRightPrn := trunc(FPrintMarginRight/2.54 * P1);
MRightPrn := MRightPrn - LowerRightPagePoint.x; { subtract physical offset }
WPrn := PageWidth - (MLeftPrn + MRightPrn);
W := MulDiv(WPrn, P2, P1);
MTopPrn := trunc(FPrintMarginTop/2.54 * P3);
MTopPrn := MTopPrn - UpperLeftPagePoint.y; { subtract physical offset }
MBottomPrn := trunc(FPrintMarginBottom/2.54 * P3);
MBottomPrn := MBottomPrn - LowerRightPagePoint.y; { subtract physical offset }
TopPixelsPrn := MTopPrn;
TopPixels := MulDiv(TopPixelsPrn, P2, P3);
HPrn := PageHeight-(MTopPrn+MBottomPrn);
H := MulDiv(HPrn, P2, P3); {scaled pageHeight}
Curs := 0;
VPixels := PrintList.DoLogic(Canvas, 0, W, H, 0, Dummy, Curs);
Done := False;
HTop := 0;
OldTop := 0;
ScaledPgHt := MulDiv(PageHeight, P2, P3);
ScaledPgWid := MulDiv(PageWidth, P2, P3);
hrgnClip := CreateRectRgn(MLeftPrn, TopPixelsPrn-1, WPrn + MLeftPrn+2,
TopPixelsPrn + HPrn+2);
Application.ProcessMessages;
if Assigned(FOnPageEvent) then
FOnPageEvent(Self, FPage, Done);
ARect := Rect(MLeft, TopPixels, W + MLeft, TopPixels + H);
if Assigned(FOnPrintHTMLHeader) then
HeadViewer := CreateHeaderFooter;
if Assigned(FOnPrintHTMLFooter) then
FootViewer := CreateHeaderFooter;
OrigTopPixels := TopPixels;
OrigTopPixelsPrn := TopPixelsPrn;
OrigHPrn := HPrn;
OrigH := H;
LastPrintMarginTop := FPrintMarginTop;
while (FPage <= ToPage) and not Done do
begin
PrintList.SetYOffset(HTop-TopPixels);
SetMapMode(DC, mm_AnIsotropic);
SetWindowExtEx(DC, P2, P2, Nil);
SetViewPortExtEx(DC, P1,P3, Nil);
SetWindowOrgEx(DC, 0, 0, Nil);
SelectClipRgn(DC, hrgnClip);
if FPage >= FromPage then
begin
if (htPrintBackground in FOptions) then
DoBackground2(Canvas, MLeft, TopPixels, W, H, PaintPanel.Color);
MLeftSide := MLeft;
end
else MLeftSide := MLeft+3*W; {to print off page}
repeat
if Assigned(TablePartRec) then
TablePart := TablePartRec.TablePart
else TablePart := Normal;
case TablePart of
Normal:
begin
PrintList.Draw(Canvas, ARect, W, MLeftSide, 0, 0,0);
WhiteoutArea(Canvas, PrintList.PageBottom-PrintList.YOff);
end;
DoHead:
begin
PrintList.SetYOffset(TablePartRec.PartStart-TopPixels);
CRect := ARect;
CRect.Bottom := CRect.Top+TablePartRec.PartHeight;
hrgnClip1 := CreateRectRgn(MLeftPrn, TopPixelsPrn, WPrn+MLeftPrn+2,
MulDiv(CRect.Bottom, P3, P2));
SelectClipRgn(DC, hrgnClip1);
DeleteObject(hrgnClip1);
PrintList.Draw(Canvas, CRect, W, MLeftSide, 0, 0,0);
end;
DoBody1, DoBody3:
begin
CRect := ARect;
CRect.Top := PrintList.PageBottom-1-PrintList.YOff;
PrintList.SetYOffset(TablePartRec.PartStart-CRect.top);
PrintList.Draw(Canvas, CRect, W, MLeftSide+3*W, 0, 0,0); {off page}
TablePartRec.TablePart := DoBody2;
CRect.Bottom := PrintList.PageBottom-PrintList.YOff+1;
hrgnClip1 := CreateRectRgn(MLeftPrn, MulDiv(CRect.Top, P3, P2),
WPrn+MLeftPrn+2, MulDiv(CRect.Bottom, P3, P2));
SelectClipRgn(DC, hrgnClip1);
DeleteObject(hrgnClip1);
PrintList.Draw(Canvas, CRect, W, MLeftSide, 0, 0,0); {onpage}
if not Assigned(TablePartRec)
or not (TablePartRec.TablePart in [Normal]) then
WhiteoutArea(Canvas, PrintList.PageBottom-PrintList.YOff);
end;
DoFoot:
begin
SavePageBottom := PrintList.PageBottom;
CRect := ARect;
CRect.Top := PrintList.PageBottom-PrintList.YOff;
CRect.Bottom := CRect.Top + TablePartRec.PartHeight;
hrgnClip1 := CreateRectRgn(MLeftPrn, MulDiv(CRect.Top, P3, P2),
WPrn+MLeftPrn+2, MulDiv(CRect.Bottom, P3, P2));
SelectClipRgn(DC, hrgnClip1);
DeleteObject(hrgnClip1);
PrintList.SetYOffset(TablePartRec.PartStart-CRect.top);
PrintList.Draw(Canvas, CRect, W, MLeftSide, 0, 0,0);
PrintList.PageBottom := SavePageBottom;
end;
end;
until not Assigned(TablePartRec)
or (TablePartRec.TablePart in [Normal, DoHead, DoBody3]);
{.$Region 'Do HeaderFooter'}
SelectClipRgn(DC, 0);
if (FPage <= ToPage) then {print header and footer}
begin
Canvas.Pen.Assign(savedPen);
Align := SetTextAlign(DC, TA_Top or TA_Left or TA_NOUPDATECP);
if Assigned(FOnPrintHeader) then
begin
SetWindowOrgEx(DC, 0, 0, Nil);
FOnPrintHeader(Self, Canvas, FPage, ScaledPgWid, TopPixels, Done);
end;
if Assigned(FOnPrintFooter) then
begin
SetWindowOrgEx(DC, 0, -(TopPixels+H), Nil);
FOnPrintFooter(Self, Canvas, FPage, ScaledPgWid,
ScaledPgHt-(TopPixels+H), Done);
end;
DoHTMLHeaderFooter(False, FOnPrintHTMLHeader, HeadViewer);
DoHTMLHeaderFooter(True, FOnPrintHTMLFooter, FootViewer);
SetTextAlign(DC, Align);
RestoreCanvasItems(Canvas);
end;
if FPrintMarginTop <> LastPrintMarginTop then
begin
DeltaMarginTop := FPrintMarginTop - SavePrintMarginTop;
DeltaPixelsPrn:= Trunc(DeltaMarginTop/2.54 * P3);
DeltaPixels := Trunc(DeltaMarginTop/2.54 * P2);
TopPixels := OrigTopPixels + DeltaPixels;
TopPixelsPrn := OrigTopPixelsPrn +DeltaPixelsPrn;
HPrn := OrigHprn - DeltaPixelsPrn;
H := OrigH - DeltaPixels;
ARect := Rect(MLeft, TopPixels, W + MLeft, TopPixels + H);
hrgnClip := CreateRectRgn(MLeftPrn, TopPixelsPrn, WPrn + MLeftPrn+2,
TopPixelsPrn + HPrn);
LastPrintMarginTop := FPrintMarginTop;
end;
{.$EndRegion}
HTop := PrintList.PageBottom;
Application.ProcessMessages;
if Assigned(FOnPageEvent) then
FOnPageEvent(Self, FPage, Done);
if (HTop >= VPixels-MarginHeight) or (HTop <= OldTop) then {see if done or endless loop}
Done := True;
OldTop := HTop;
if not Done and (FPage >= FromPage) and (FPage < ToPage) then
NewPage;
Inc(FPage);
end;
end;
finally
FreeAndNil(HeadViewer);
FreeAndNil(FootViewer);
if hRgnClip <> 0 then DeleteObject(hrgnClip);
{$IFNDEF LCL}
if not PrinterOpen then
begin
if (FromPage > FPage) then
vwPrinter.Abort
else
vwPrinter.EndDoc;
vwSetPrinter(OldPrinter);
FreeAndNil(vwP);
end;
{$ELSE}
if (FromPage > FPage) then
Printer.Abort
else
Printer.EndDoc;
vwP := nil;
{$ENDIF}
Dec(FPage);
end;
finally
savedFont.Free ;
savedPen.Free ;
savedBrush.Free ;
end;
finally
FPrintMarginTop := SavePrintMarginTop;
PrintList.Free;
end;
end;
procedure ThtmlViewer.OpenPrint;
begin
if not assigned(vwP) then
begin
{$IFNDEF LCL}
vwP := TvwPrinter.Create;
OldPrinter := vwSetPrinter(vwP);
{$ELSE}
vwP := Printer;
{$ENDIF}
end;
end;
procedure ThtmlViewer.ClosePrint;
begin
if Assigned(vwP) then
begin
{$IFNDEF LCL}
if vwP.Printing then
vwPrinter.EndDoc;
vwSetPrinter(OldPrinter);
FreeAndNil(vwP);
{$ELSE}
if vwP.Printing then
Printer.EndDoc;
vwP := nil;
{$ENDIF}
end;
end;
procedure ThtmlViewer.AbortPrint;
begin
if Assigned(vwP) then
begin
{$IFNDEF LCL}
if vwP.Printing then
vwPrinter.Abort;
vwSetPrinter(OldPrinter);
FreeAndNil(vwP);
{$ELSE}
if vwP.Printing then
Printer.Abort;
vwP := nil;
{$ENDIF}
end;
end;
function ThtmlViewer.NumPrinterPages: integer;
var
Dummy: double;
begin
Result := NumPrinterPages(Dummy);
end;
function ThtmlViewer.NumPrinterPages(var WidthRatio: double): integer;
{$IFNDEF LCL}
var
MFPrinter: TMetaFilePrinter;
begin
MFPrinter := TMetaFilePrinter.Create(Nil);
FOnPageEvent := Nil;
try
PrintPreview(MFPrinter, True);
Result := MFPrinter.LastAvailablePage;
WidthRatio := FWidthRatio;
finally
MFPrinter.Free;
end;
{$ELSE}
begin
{$ENDIF}
end;
{$IFNDEF LCL}
function ThtmlViewer.PrintPreview(MFPrinter: TMetaFilePrinter; NoOutput: boolean = False): integer;
var
ARect, CRect : TRect;
PrintList : TSectionList;
P1, P2, P3 : integer;
W, H : integer;
HTop : integer;
OldTop : integer;
ScrollWidth : integer;
Curs : integer;
Done : boolean;
DC : HDC;
PrnDC : HDC; {metafile printer's DC}
UpperLeftPagePoint, { these will contain Top/Left and Bottom/Right unprintable area}
LowerRightPagePoint: TPoint;
MLeft : integer;
MLeftPrn : integer;
MRightPrn : integer;
MTopPrn : integer;
MBottomPrn : integer;
TopPixels : integer;
TopPixelsPrn : integer;
HPrn, WPrn : integer;
hrgnClip : THandle;
hrgnClip1 : THandle;
hrgnClip2 : THandle;
SavedFont : TFont;
SavedPen : TPen;
SavedBrush : TBrush;
Align : integer;
ScaledPgHt : integer;
ScaledPgWid : integer;
VPixels : integer;
FootViewer, HeadViewer: ThtmlViewer;
DeltaMarginTop: Double;
SavePrintMarginTop: Double;
DeltaPixelsPrn: Integer;
DeltaPixels: Integer;
OrigTopPixels: Integer;
OrigTopPixelsPrn: Integer;
OrigHprn: Integer;
OrigH: Integer;
LastPrintMarginTop: Double;
SavePageBottom: Integer;
TablePart: TablePartType;
procedure Fill(Canvas: TCanvas);
var
BrushColor: TColor;
begin
BrushColor := Canvas.Brush.Color;
Canvas.Brush.Color := $eeeeff;
Canvas.Rectangle(MLeft, 0, W + MLeft+200, 4000);
Canvas.Brush.Color := BrushColor;
end;
procedure SaveCanvasItems(Canvas: TCanvas);
begin { preserve current settings of the Canvas}
SavedPen.Assign(Canvas.Pen);
SavedFont.Assign(Canvas.Font);
SavedBrush.Assign(Canvas.Brush);
end;
procedure RestoreCanvasItems(Canvas: TCanvas);
begin { restore initial Canvas settings }
Canvas.Pen.Assign(SavedPen);
Canvas.Font.Assign(SavedFont);
Canvas.Brush.Assign(SavedBrush);
end;
procedure WhiteoutArea(Canvas: TCanvas; Y: integer);
{White out excess printing. Y is top of the bottom area to be blanked.}
begin
Canvas.Brush.Color := clWhite;
Canvas.Brush.Style := bsSolid;
Canvas.Pen.Style := psSolid;
Canvas.Pen.Color := clWhite;
Canvas.Rectangle(MLeft, 0, W + MLeft+1, TopPixels-1);
Canvas.Rectangle(MLeft, Y, W + MLeft+1, TopPixels+H+1);
if (htPrintBackground in FOptions) and (Y-TopPixels < H) then
begin {need to reprint background in whited out area}
hrgnClip1 := CreateRectRgn(MLeftPrn, MulDiv(Y, P3, P2)+2,
MLeftPrn+WPrn, TopPixelsPrn+HPrn);
SelectClipRgn(Canvas.Handle, hrgnClip1);
DeleteObject(hrgnClip1);
DoBackground2(Canvas, MLeft, TopPixels, W, H, PaintPanel.Color);
end;
RestoreCanvasItems(Canvas);
end;
procedure DoHTMLHeaderFooter(Footer: boolean; Event: ThtmlPagePrinted; HFViewer: ThtmlViewer);
var
YOrigin, YOff, Ht: integer;
HFCopyList: TSectionList;
BRect: TRect;
DocHeight, XL, XR: integer;
begin
if not Assigned(Event) then
Exit;
try
XL := MLeft;
XR := MLeft + W;
Event(Self, HFViewer, FPage, PrintList.PageBottom > VPixels, XL, XR, Done); {call event handler}
HFCopyList := TSectionList.CreateCopy(HFViewer.SectionList);
try
HFCopyList.Printing := True;
HFCopyList.NoOutput := NoOutput;
HFCopyList.ScaleX := fScaleX;
HFCopyList.ScaleY := fScaleY;
Curs := 0;
DocHeight := HFCopyList.DoLogic(MFPrinter.Canvas, 0, XR-XL, 300, 0, ScrollWidth, Curs);
if not Footer then
begin {Header}
YOrigin := 0;
Ht := TopPixels;
YOff := DocHeight-TopPixels;
end
else
begin {Footer}
YOrigin := -(TopPixels+H);
Ht := IntMin(ScaledPgHt-(TopPixels+H), DocHeight);
YOff := 0;
end;
SetWindowOrgEx(DC, 0, YOrigin, nil);
HFViewer.DoBackground2(MFPrinter.Canvas, XL, -YOff, XR-XL, DocHeight, HFViewer.PaintPanel.Color);
HFCopyList.SetYOffset(YOff);
BRect := Rect(XL, 0, XR, Ht);
HFCopyList.Draw(MFPrinter.Canvas, BRect, XR-XL, XL, 0, 0, 0);
finally
HFCopyList.Free;
end;
except
end;
end;
begin
Done := False;
FootViewer := Nil;
HeadViewer := Nil;
TablePartRec := Nil;
if Assigned(FOnPageEvent) then
FOnPageEvent(Self, 0, Done);
FPage := 0;
Result := 0;
if FProcessing or (SectionList.Count = 0) then Exit;
PrintList := TSectionList.CreateCopy(SectionList);
PrintList.SetYOffset(0);
SavePrintMarginTop := FPrintMarginTop;
try
SavedPen := TPen.Create;
SavedFont := TFont.Create;
SavedBrush := TBrush.Create;
try
PrintList.Printing := True;
PrintList.NoOutput := NoOutput;
PrintList.SetBackground(clWhite);
FPage := 1;
hrgnClip := 0;
hrgnClip2 := 0;
try
with MFPrinter do
begin
if DocumentTitle <> '' then
Title := DocumentTitle;
BeginDoc;
DC := Canvas.Handle;
PrnDC := PrinterDC;
P3 := GetDeviceCaps(PrnDC, LOGPIXELSY);
P1 := GetDeviceCaps(PrnDC, LOGPIXELSX);
P2 := Round(Screen.PixelsPerInch * FPrintScale);
fScaleX := 100.0/P3;
fScaleY := 100.0/P1;
PrintList.ScaleX := fScaleX;
PrintList.ScaleY := fScaleY;
SetMapMode(DC, mm_AnIsotropic);
//P1 := GetDeviceCaps(PrnDC, LOGPIXELSX);
SetWindowExtEx(DC, P2, P2, nil);
SetViewPortExtEx(DC, P1, P3, nil);
{ calculate the amount of space that is non-printable }
{ get PHYSICAL page width }
LowerRightPagePoint.X := GetDeviceCaps(PrnDC, PhysicalWidth);
LowerRightPagePoint.Y := GetDeviceCaps(PrnDC, PhysicalHeight);
{ now compute a complete unprintable area rectangle
(composed of 2*width, 2*height) in pixels...}
with LowerRightPagePoint do
begin
Y := Y - MFPrinter.PageHeight;
X := X - MFPrinter.PageWidth;
end;
{ get upper left physical offset for the printer... ->
printable area <> paper size }
UpperLeftPagePoint.X := GetDeviceCaps(PrnDC, PhysicalOffsetX);
UpperLeftPagePoint.Y := GetDeviceCaps(PrnDC, PhysicalOffsetY);
{ now that we know the TOP and LEFT offset we finally can
compute the BOTTOM and RIGHT offset: }
with LowerRightPagePoint do
begin
X := X - UpperLeftPagePoint.X;
{ we don't want to have negative values}
if X < 0 then
X := 0; { assume no right printing offset }
Y := Y - UpperLeftPagePoint.Y;
{ we don't want to have negative values}
if Y < 0 then
Y := 0; { assume no bottom printing offset }
end;
{ which results in LowerRightPoint containing the BOTTOM
and RIGHT unprintable area offset; using these we modify
the (logical, true) borders...}
MLeftPrn := Trunc(FPrintMarginLeft/2.54 * P1);
MLeftPrn := MLeftPrn - UpperLeftPagePoint.X; { subtract physical offset }
MLeft := MulDiv(MLeftPrn, P2, P1);
MRightPrn := Trunc(FPrintMarginRight/2.54 * P1);
MRightPrn := MRightPrn - LowerRightPagePoint.X; { subtract physical offset }
WPrn := PageWidth - (MLeftPrn + MRightPrn);
W := MulDiv(WPrn, P2, P1);
MTopPrn := Trunc(FPrintMarginTop/2.54 * P3);
MTopPrn := MTopPrn - UpperLeftPagePoint.Y; { subtract physical offset }
MBottomPrn := Trunc(FPrintMarginBottom/2.54 * P3);
MBottomPrn := MBottomPrn - LowerRightPagePoint.Y; { subtract physical offset }
TopPixelsPrn := MTopPrn;
TopPixels := MulDiv(TopPixelsPrn, P2, P3);
HPrn := PageHeight-(MTopPrn+MBottomPrn);
H := MulDiv(HPrn, P2, P3); {scaled pageHeight}
HTop := 0;
OldTop := 0;
Curs := 0;
VPixels := PrintList.DoLogic(Canvas, 0, W, H, 0, ScrollWidth, Curs);
FWidthRatio := ScrollWidth/W;
if FWidthRatio > 1.0 then
FWidthRatio := Round(P2*FWidthRatio +0.5)/P2;
ScaledPgHt := MulDiv(PageHeight, P2, P3);
ScaledPgWid := MulDiv(PageWidth, P2, P3);
{This one clips to the allowable print region so that the preview is
limited to that region also}
hrgnClip2 := CreateRectRgn(0, 0, MFPrinter.PageWidth, MFPrinter.PageHeight);
{This one is primarily used to clip the top and bottom margins to insure
nothing is output there. It's also constrained to the print region
in case the margins are misadjusted.}
hrgnClip := CreateRectRgn(MLeftPrn, IntMax(0, TopPixelsPrn),
IntMin(MFPrinter.PageWidth, WPrn+MLeftPrn+2),
IntMin(MFPrinter.PageHeight, TopPixelsPrn+HPrn));
Application.ProcessMessages;
if Assigned(FOnPageEvent) then
FOnPageEvent(Self, FPage, Done);
ARect := Rect(MLeft, TopPixels, W + MLeft, TopPixels + H);
if Assigned(FOnPrintHTMLHeader) then
HeadViewer := CreateHeaderFooter;
if Assigned(FOnPrintHTMLFooter) then
FootViewer := CreateHeaderFooter;
OrigTopPixels := TopPixels;
OrigTopPixelsPrn := TopPixelsPrn;
OrigHPrn := HPrn;
OrigH := H;
LastPrintMarginTop := FPrintMarginTop;
while not Done do
begin
PrintList.SetYOffset(HTop-TopPixels);
{next line is necessary because the canvas changes with each new page }
DC := Canvas.Handle;
SaveCanvasItems(Canvas);
SetMapMode(DC, mm_AnIsotropic);
SetWindowExtEx(DC, P2, P2, nil);
SetViewPortExtEx(DC, P1, P3, nil);
SetWindowOrgEx(DC, 0, 0, nil);
SelectClipRgn(DC, hrgnClip);
if (htPrintBackground in FOptions) then
DoBackground2(Canvas, MLeft, TopPixels, W, H, PaintPanel.Color);
repeat
if Assigned(TablePartRec) then
TablePart := TablePartRec.TablePart
else TablePart := Normal;
case TablePart of
Normal:
begin
PrintList.Draw(Canvas, ARect, W, MLeft, 0, 0,0);
WhiteoutArea(Canvas, PrintList.PageBottom-PrintList.YOff);
end;
DoHead:
begin
PrintList.SetYOffset(TablePartRec.PartStart-TopPixels);
CRect := ARect;
CRect.Bottom := CRect.Top+TablePartRec.PartHeight;
hrgnClip1 := CreateRectRgn(MLeftPrn, TopPixelsPrn, WPrn+MLeftPrn+2,
MulDiv(CRect.Bottom, P3, P2));
SelectClipRgn(DC, hrgnClip1);
DeleteObject(hrgnClip1);
PrintList.Draw(Canvas, CRect, W, MLeft, 0, 0,0);
end;
DoBody1, DoBody3:
begin
CRect := ARect;
CRect.Top := PrintList.PageBottom-1-PrintList.YOff;
PrintList.SetYOffset(TablePartRec.PartStart-CRect.top);
PrintList.Draw(Canvas, CRect, W, MLeft+3*W, 0, 0,0); {off page}
TablePartRec.TablePart := DoBody2;
CRect.Bottom := PrintList.PageBottom-PrintList.YOff+1;
hrgnClip1 := CreateRectRgn(MLeftPrn, MulDiv(CRect.Top, P3, P2),
WPrn+MLeftPrn+2, MulDiv(CRect.Bottom, P3, P2));
SelectClipRgn(DC, hrgnClip1);
DeleteObject(hrgnClip1);
PrintList.Draw(Canvas, CRect, W, MLeft, 0, 0,0); {onpage}
if not Assigned(TablePartRec)
or not (TablePartRec.TablePart in [Normal]) then
WhiteoutArea(Canvas, PrintList.PageBottom-PrintList.YOff);
end;
DoFoot:
begin
SavePageBottom := PrintList.PageBottom;
CRect := ARect;
CRect.Top := PrintList.PageBottom-PrintList.YOff;
CRect.Bottom := CRect.Top + TablePartRec.PartHeight;
hrgnClip1 := CreateRectRgn(MLeftPrn, MulDiv(CRect.Top, P3, P2),
WPrn+MLeftPrn+2, MulDiv(CRect.Bottom, P3, P2));
SelectClipRgn(DC, hrgnClip1);
DeleteObject(hrgnClip1);
PrintList.SetYOffset(TablePartRec.PartStart-CRect.top);
PrintList.Draw(Canvas, CRect, W, MLeft, 0, 0,0);
PrintList.PageBottom := SavePageBottom;
end;
end;
until not Assigned(TablePartRec)
or (TablePartRec.TablePart in [Normal, DoHead, DoBody3]);
{.$Region 'HeaderFooter'}
SelectClipRgn(DC, 0);
Align := SetTextAlign(DC, TA_Top or TA_Left or TA_NOUPDATECP);
SelectClipRgn(DC, hrgnClip2);
if Assigned(FOnPrintHeader) then
begin
SetWindowOrgEx(DC, 0, 0, Nil);
FOnPrintHeader(Self, Canvas, FPage, ScaledPgWid, TopPixels, Done);
end;
if Assigned(FOnPrintFooter) then
begin
SetWindowOrgEx(DC, 0, -(TopPixels+H), nil);
FOnPrintFooter(Self, Canvas, FPage, ScaledPgWid,
ScaledPgHt-(TopPixels+H), Done);
end;
DoHTMLHeaderFooter(False, FOnPrintHTMLHeader, HeadViewer);
DoHTMLHeaderFooter(True, FOnPrintHTMLFooter, FootViewer);
SetTextAlign(DC, Align);
SelectClipRgn(DC, 0);
if FPrintMarginTop <> LastPrintMarginTop then
begin
DeltaMarginTop := FPrintMarginTop - SavePrintMarginTop;
DeltaPixelsPrn:= Trunc(DeltaMarginTop/2.54 * P3);
DeltaPixels := Trunc(DeltaMarginTop/2.54 * P2);
TopPixels := OrigTopPixels + DeltaPixels;
TopPixelsPrn := OrigTopPixelsPrn +DeltaPixelsPrn;
HPrn := OrigHprn - DeltaPixelsPrn;
H := OrigH - DeltaPixels;
ARect := Rect(MLeft, TopPixels, W + MLeft, TopPixels + H);
hrgnClip := CreateRectRgn(MLeftPrn, IntMax(0, TopPixelsPrn),
IntMin(MFPrinter.PageWidth, WPrn+MLeftPrn+2),
IntMin(MFPrinter.PageHeight, TopPixelsPrn+HPrn));
LastPrintMarginTop := FPrintMarginTop;
end;
{.$EndRegion}
HTop := PrintList.PageBottom;
Application.ProcessMessages;
if Assigned(FOnPageEvent) then
FOnPageEvent(Self, FPage, Done);
if (HTop >= VPixels-MarginHeight) or (HTop <= OldTop) then {see if done or endless loop}
Done := True;
OldTop := HTop;
if not Done then
NewPage;
Inc(FPage);
end;
EndDoc;
end;
finally
FreeAndNil(HeadViewer);
FreeAndNil(FootViewer);
if hRgnClip <> 0 then
DeleteObject(hrgnClip);
if hRgnClip2 <> 0 then
DeleteObject(hrgnClip2);
Dec(FPage);
end;
finally
SavedPen.Free;
SavedFont.Free;
SavedBrush.Free;
end;
finally
FPrintMarginTop := SavePrintMarginTop;
PrintList.Free;
Result := FPage;
end;
end;
{$ENDIF}
procedure ThtmlViewer.BackgroundChange(Sender: TObject);
begin
PaintPanel.Color := (Sender as TSectionList).Background or PalRelative;
end;
procedure ThtmlViewer.SetOnBitmapRequest(Handler: TGetBitmapEvent);
begin
FOnBitmapRequest := Handler;
FSectionList.GetBitmap := Handler;
end;
procedure ThtmlViewer.SetOnImageRequest(Handler: TGetImageEvent);
begin
FOnImageRequest := Handler;
FSectionList.GetImage := Handler;
end;
procedure ThtmlViewer.SetOnExpandName(Handler: TExpandNameEvent);
begin
FOnExpandName := Handler;
FSectionList.ExpandName := Handler;
end;
procedure ThtmlViewer.SetOnScript(Handler: TScriptEvent);
begin
FOnScript := Handler;
FSectionList.ScriptEvent := Handler;
end;
procedure ThtmlViewer.SetOnFileBrowse(Handler: TFileBrowseEvent);
begin
FOnFileBrowse := Handler;
FSectionList.FileBrowse := Handler;
end;
procedure ThtmlViewer.SetOnObjectClick(Handler: TObjectClickEvent);
begin
FOnObjectClick := Handler;
FSectionList.ObjectClick := Handler;
end;
procedure ThtmlViewer.SetOnObjectFocus(Handler: ThtObjectEvent);
begin
FOnObjectFocus := Handler;
FSectionList.ObjectFocus := Handler;
end;
procedure ThtmlViewer.SetOnObjectBlur(Handler: ThtObjectEvent);
begin
FOnObjectBlur := Handler;
FSectionList.ObjectBlur := Handler;
end;
procedure ThtmlViewer.SetOnObjectChange(Handler: ThtObjectEvent);
begin
FOnObjectChange := Handler;
FSectionList.ObjectChange := Handler;
end;
procedure ThtmlViewer.SetOnPanelCreate(Handler: TPanelCreateEvent);
begin
FOnPanelCreate := Handler;
FSectionList.PanelCreateEvent := Handler;
end;
procedure ThtmlViewer.SetOnPanelDestroy(Handler: TPanelDestroyEvent);
begin
FOnPanelDestroy := Handler;
FSectionList.PanelDestroyEvent := Handler;
end;
procedure ThtmlViewer.SetOnPanelPrint(Handler: TPanelPrintEvent);
begin
FOnPanelPrint := Handler;
FSectionList.PanelPrintEvent := Handler;
end;
procedure ThtmlViewer.SetOnFormSubmit(Handler: TFormSubmitEvent);
begin
FOnFormSubmit := Handler;
if Assigned(Handler) then
FSectionList.SubmitForm := SubmitForm
else FSectionList.SubmitForm := Nil;
end;
procedure ThtmlViewer.SubmitForm(Sender: TObject; const Action, Target, EncType, Method: string;
Results: TStringList);
begin
if Assigned(FOnFormSubmit) then
begin
FAction := Action;
FMethod := Method;
FFormTarget := Target;
FEncType:= EncType;
FStringList := Results;
PostMessage(Handle, wm_FormSubmit, 0, 0);
end;
end;
procedure ThtmlViewer.WMFormSubmit(var Message: TMessage);
begin
FOnFormSubmit(Self, FAction, FFormTarget, FEncType, FMethod, FStringList);
end; {user disposes of the TStringList}
function ThtmlViewer.Find(const S: WideString; MatchCase: boolean): boolean;
begin
Result := FindEx(S, MatchCase, False);
end;
function ThtmlViewer.FindEx(const S: WideString; MatchCase, Reverse: boolean): boolean;
var
Curs: integer;
X: integer;
Y, Pos: integer;
S1: WideString;
begin
Result := False;
if S = '' then Exit;
with FSectionList do
begin
if MatchCase then
S1 := S
else S1 := WideLowerCase1(S);
if Reverse then
Curs := FindStringR(CaretPos, S1, MatchCase)
else
Curs := FindString(CaretPos, S1, MatchCase);
if Curs >= 0 then
begin
Result := True;
SelB := Curs;
SelE := Curs+Length(S);
if Reverse then
CaretPos := SelB
else
CaretPos := SelE;
if CursorToXY(PaintPanel.Canvas, Curs, X, Y) then
begin
Pos := VScrollBarPosition;
if (Y < Pos) or
(Y > Pos +ClientHeight-20) then
VScrollBarPosition := (Y - ClientHeight div 2);
Pos := HScrollBarPosition;
if (X < Pos) or
(X > Pos +ClientWidth-50) then
HScrollBarPosition := (X - ClientWidth div 2);
Invalidate;
end;
end;
end;
end;
procedure ThtmlViewer.FormControlEnterEvent(Sender: TObject);
var
Y, Pos: integer;
begin
if Sender is TFormControlObj then
begin
Y := TFormControlObj(Sender).YValue;
Pos := VScrollBarPosition;
if (Y < Pos) or (Y > Pos +ClientHeight-20) then
begin
VScrollBarPosition := (Y - ClientHeight div 2);
Invalidate;
end;
end
else if Sender is TFontObj and not NoJump then
begin
Y := TFontObj(Sender).YValue;
Pos := VScrollBarPosition;
if (Y < Pos) then
VScrollBarPosition := Y
else if (Y > Pos +ClientHeight-30) then
VScrollBarPosition := (Y - ClientHeight div 2);
Invalidate;
end
end;
procedure ThtmlViewer.SelectAll;
begin
with FSectionList do
if (Count > 0) and not FNoSelect then
begin
SelB := 0;
with TSectionBase(Items[Count-1]) do
SelE := StartCurs + Len;
Invalidate;
end;
end;
{----------------ThtmlViewer.InitLoad}
procedure ThtmlViewer.InitLoad;
begin
if not Assigned(FSectionList.BitmapList) then
begin
FSectionList.BitmapList := TStringBitmapList.Create;
FSectionList.BitmapList.Sorted := True;
FSectionList.BitmapList.SetCacheCount(FImageCacheCount);
LocalBitmapList := True;
end;
FSectionList.Clear;
UpdateImageCache;
FSectionList.SetFonts(FFontName, FPreFontName, FFontSize, FFontColor,
FHotSpotColor, FVisitedColor, FOverColor, FBackground,
htOverLinksActive in FOptions, not (htNoLinkUnderline in FOptions),
FCharSet, FMarginHeight, FMarginWidth);
end;
{----------------ThtmlViewer.Clear}
procedure ThtmlViewer.Clear;
{Note: because of Frames do not clear history list here}
begin
if FProcessing then Exit;
HTMLTimer.Enabled := False;
FSectionList.Clear;
if LocalBitmapList then
FSectionList.BitmapList.Clear;
FSectionList.SetFonts(FFontName, FPreFontName, FFontSize, FFontColor,
FHotSpotColor, FVisitedColor, FOverColor, FBackground,
htOverLinksActive in FOptions, not (htNoLinkUnderline in FOptions),
FCharSet, FMarginHeight, FMarginWidth);
FBase := '';
FBaseEx := '';
FBaseTarget := '';
FTitle := '';
VScrollBar.Max := 0;
VScrollBar.Visible := False;
VScrollBar.Height := PaintPanel.Height;
HScrollBar.Visible := False;
CaretPos := 0;
Sel1 := -1;
if Assigned(FOnSoundRequest) then
FOnSoundRequest(Self, '', 0, True);
Invalidate;
end;
procedure ThtmlViewer.PaintWindow(DC: HDC);
begin
PaintPanel.RePaint;
{$IFNDEF LCL}
BorderPanel.RePaint;
VScrollbar.RePaint; //Don't need this anymore (and causes
HScrollbar.RePaint; // endless loop with GTK2).
{$ENDIF}
end;
procedure ThtmlViewer.CopyToClipboard;
const
StartFrag = '<!--StartFragment-->';
EndFrag = '<!--EndFragment-->';
DocType = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'#13#10;
var
Leng: integer;
StSrc, EnSrc: integer;
HTML: string;
format : UINT;
{$IFNDEF LCL}
procedure copyFormatToClipBoard(const source: string; format : UINT);
{$ELSE} //changed to var to use with AddFormat below
procedure copyFormatToClipBoard(var source: string; format : UINT);
{$ENDIF}
// Put SOURCE on the clipboard, using FORMAT as the clipboard format
// Based on http://www.lorriman.com/programming/cf_html.html
var
gMem: HGLOBAL;
lp: pchar;
begin
clipboard.Open;
try
{$IFNDEF LCL}
//an extra "1" for the null terminator
gMem := globalalloc(GMEM_DDESHARE + GMEM_MOVEABLE, length(source)+1);
lp := globallock(gMem);
copymemory(lp, pchar(source), length(source)+1);
globalunlock(gMem);
setClipboarddata(format, gMem);
{$ELSE}
clipboard.AddFormat(format, source[1], Length(source));
{$ENDIF}
finally
clipboard.Close;
end
end;
function GetHeader(const HTML: string): string;
const
Version = 'Version:1.0'#13#10;
StartHTML = 'StartHTML:';
EndHTML = 'EndHTML:';
StartFragment = 'StartFragment:';
EndFragment = 'EndFragment:';
SourceURL = 'SourceURL:';
NumberLengthAndCR = 10;
// Let the compiler determine the description length.
PreliminaryLength = Length(Version) + Length(StartHTML) +
Length(EndHTML) + Length(StartFragment) +
Length(EndFragment) + 4 * NumberLengthAndCR +
2; {2 for last CRLF}
var
URLString: string;
StartHTMLIndex,
EndHTMLIndex,
StartFragmentIndex,
EndFragmentIndex: integer;
begin
if CurrentFile = '' then
UrlString := SourceURL+'unsaved:///ThtmlViewer.htm'
else if Pos('://', CurrentFile) > 0 then
URLString := SourceURL+CurrentFile {already has protocol}
else
URLString := SourceURL+'file://'+CurrentFile;
StartHTMLIndex := PreliminaryLength + Length(URLString);
EndHTMLIndex := StartHTMLIndex + Length(HTML);
StartFragmentIndex := StartHTMLIndex + Pos(StartFrag, HTML) + Length(StartFrag)-1;
EndFragmentIndex := StartHTMLIndex + Pos(EndFrag, HTML)-1;
Result := Version +
SysUtils.Format('%s%.8d', [StartHTML, StartHTMLIndex]) + #13#10 +
SysUtils.Format('%s%.8d', [EndHTML, EndHTMLIndex]) + #13#10 +
SysUtils.Format('%s%.8d', [StartFragment, StartFragmentIndex]) + #13#10 +
SysUtils.Format('%s%.8d', [EndFragment, EndFragmentIndex]) + #13#10 +
URLString + #13#10;
end;
function Truncate(const S: string): string;
var
I: integer;
begin
I := Pos(EndFrag, S);
Result := S;
if I > 0 then
Result := Copy(Result, 1, I+Length(EndFrag)-1);
end;
procedure RemoveTag(const Tag: string);
{remove all the tags that look like "<tag .....>" }
var
I: integer;
L: string;
C: char;
begin
L := Lowercase(HTML);
I := Pos(Tag, L);
while (I > 0) do
begin
Delete(HTML, I, Length(Tag));
repeat
if I <= Length(HTML) then
C := HTML[I]
else C := #0;
Delete(HTML, I, 1);
until C in ['>', #0];
L := Lowercase(HTML);
I := Pos(Tag, L);
end;
end;
procedure MessUp(const S: string);
var
I: integer;
L: string;
begin
L := Lowercase(HTML);
I := Pos(S, L);
while (I > 0) do
begin
Delete(HTML, I, 1);
L := Lowercase(HTML);
I := Pos(S, L);
end;
end;
function ConvertToUTF8(const S: string): string;
var
Len, Len1: integer;
WS: WideString;
begin
{$IFNDEF LCL}
if CodePage = CP_UTF8 then
begin
Result := S;
Exit;
End;
Len := Length(S);
SetLength(WS, Len);
Len := MultibyteToWideChar(CodePage, 0, PChar(S), Len, PWideChar(WS), Len);
Len1 := 4*Len;
SetLength(Result, Len1);
Len1 := WideCharToMultibyte(CP_UTF8, 0, PWideChar(WS), Len, PChar(Result), Len1, Nil, Nil);
SetLength(Result, Len1);
{$ELSE}
Result := AnsiToUtf8(S);
{$ENDIF}
end;
procedure InsertDefaultFontInfo;
var
I: integer;
S, L: string;
HeadFound: boolean;
begin
L := LowerCase(HTML);
I := Pos('<head>', L);
HeadFound := I > 0;
if not HeadFound then
I := Pos('<html>', L);
if I <= 0 then
I := 1;
S := '<style> body {font-size: '+IntToStr(DefFontSize)+'pt; font-family: "'+
DefFontName+'"; }</style>';
if not HeadFound then
S := '<head>'+S+'</head>';
Insert(S, HTML, I);
end;
procedure BackupToContent;
var
C: char;
I: integer;
procedure GetC; {reads characters backwards}
begin
if I-1 > StSrc then
begin
Dec(I);
C := HTML[I];
end
else C := #0;
end;
begin
I := EnSrc;
repeat
repeat {skip past white space}
GetC;
until C in [#0, '!'..#255];
if C = '>' then
repeat {read thru a tag}
repeat
GetC;
until C in [#0, '<'];
GetC;
until C <> '>';
until C in [#0, '!'..#255]; {until found some content}
if C = #0 then Dec(I);
HTML := Copy(HTML, 1, I); {truncate the tags}
end;
begin
Leng := FSectionList.GetSelLength;
if Leng = 0 then
Exit;
FSectionList.CopyToClipboardA(Leng+1);
HTML := DocumentSource;
StSrc := FindSourcePos(FSectionList.SelB)+1;
EnSrc := FindSourcePos(FSectionList.SelE);
if EnSrc < 0 then {check to see if end selection is at end of document}
begin
EnSrc := Length(HTML);
if HTML[EnSrc] = '>' then
begin
HTML := HTML + ' ';
Inc(EnSrc);
end;
end
else EnSrc := EnSrc + 1;
{Truncate beyond EnSrc}
HTML := Copy(HTML, 1, EnSrc-1);
{Also remove any tags on the end}
BackupToContent;
{insert the StartFrag string}
Insert(StartFrag, HTML, StSrc);
{Remove all Meta tags, in particular the ones that specify language, but others
seem to cause problems also}
RemoveTag('<meta');
{Remove <!doctype> in preparation to having one added}
RemoveTag('<!doctype');
{page-break-... stylesheet properties cause a hang in Word -- mess them up}
MessUp('page-break-');
{Add in default font information which wouldn't be in the HTML}
InsertDefaultFontInfo;
{Convert character set to UTF-8}
HTML := ConvertToUTF8(HTML);
{Add Doctype tag at start}
HTML := DocType+HTML;
{Append the EndFrag string}
HTML := HTML+EndFrag;
{Add the header to start}
HTML := GetHeader(HTML)+HTML;
{$IFNDEF LCL}
format := RegisterClipboardFormat('HTML Format'); {not sure this is necessary}
{$ELSE}
format := RegisterClipboardFormat('text/html');
{$ENDIF}
CopyFormatToClipBoard(HTML, format);
end;
function ThtmlViewer.GetSelTextBuf(Buffer: PWideChar; BufSize: integer): integer;
begin
if BufSize <= 0 then Result := 0
else Result := FSectionList.GetSelTextBuf(Buffer, BufSize);
end;
function ThtmlViewer.GetSelText: WideString;
var
Len: integer;
begin
Len := FSectionList.GetSelLength;
if Len > 0 then
begin
SetString(Result, Nil, Len);
FSectionList.GetSelTextBuf(Pointer(Result), Len+1);
end
else Result := '';
end;
function ThtmlViewer.GetSelLength: integer;
begin
with FSectionList do
if FCaretPos = SelB then
Result := SelE - SelB
else
Result := SelB - SelE;
end;
procedure ThtmlViewer.SetSelLength(Value: integer);
begin
with FSectionList do
begin
if Value >= 0 then
begin
SelB := FCaretPos;
SelE := FCaretPos + Value;
end
else
begin
SelE := FCaretPos;
SelB := FCaretPos + Value;
end;
Invalidate;
end;
end;
procedure ThtmlViewer.SetSelStart(Value: integer);
begin
with FSectionList do
begin
FCaretPos := Value;
SelB := Value;
SelE := Value;
Invalidate;
end;
end;
procedure ThtmlViewer.SetNoSelect(Value: boolean);
begin
if Value <> FNoSelect then
begin
FNoSelect := Value;
if Value = True then
begin
FSectionList.SelB := -1;
FSectionList.SelE := -1;
RePaint;
end;
end;
end;
procedure ThtmlViewer.UpdateImageCache;
begin
FSectionList.BitmapList.BumpAndCheck;
end;
procedure ThtmlViewer.SetImageCacheCount(Value: integer);
begin
Value := IntMax(0, Value);
Value := IntMin(20, Value);
if Value <> FImageCacheCount then
begin
FImageCacheCount := Value;
if Assigned(FSectionList.BitmapList) then
FSectionList.BitmapList.SetCacheCount(FImageCacheCount);
end;
end;
procedure ThtmlViewer.SetStringBitmapList(BitmapList: TStringBitmapList);
begin
FSectionList.BitmapList := BitmapList;
LocalBitmapList := False;
end;
procedure ThtmlViewer.DrawBorder;
begin //Focused may not work with control on all widgetsets.
if (Focused and (FBorderStyle = htFocused)) or (FBorderStyle = htSingle)
or (csDesigning in ComponentState) then
{$IFNDEF LCL}
BorderPanel.BorderStyle := bsSingle
else
BorderPanel.BorderStyle := bsNone;
{$ELSE} //Setting viewer's BorderStyle currently does not work.
// inherited BorderStyle := bsSingle
//else
// inherited BorderStyle := bsNone;
{$ENDIF}
end;
procedure ThtmlViewer.DoEnter;
begin
inherited DoEnter;
DrawBorder;
end;
procedure ThtmlViewer.DoExit;
begin
inherited DoExit;
DrawBorder;
end;
procedure ThtmlViewer.SetScrollBars(Value: TScrollStyle);
begin
if (Value <> FScrollBars) then
begin
FScrollBars := Value;
if not (csLoading in ComponentState) and HandleAllocated then
begin
SetProcessing(True);
try
DoLogic;
finally
SetProcessing(False);
end;
Invalidate;
end;
end;
end;
{----------------ThtmlViewer.Reload}
procedure ThtmlViewer.Reload; {reload the last file}
var
Pos: integer;
begin
if FCurrentFile <> '' then
begin
Pos := Position;
if FCurrentFileType = HTMLType then
LoadFromFile(FCurrentFile)
else if FCurrentFileType = TextType then
LoadTextFile(FCurrentFile)
else LoadImageFile(FCurrentFile);
Position := Pos;
end;
end;
{----------------ThtmlViewer.GetOurPalette:}
function ThtmlViewer.GetOurPalette: HPalette;
begin
if ColorBits = 8 then
Result := CopyPalette(ThePalette)
else Result := 0;
end;
{----------------ThtmlViewer.SetOurPalette}
procedure ThtmlViewer.SetOurPalette(Value: HPalette);
var
NewPalette: HPalette;
begin
if (Value <> 0) and (ColorBits = 8) then
begin
NewPalette := CopyPalette(Value);
if NewPalette <> 0 then
begin
if ThePalette <> 0 then
DeleteObject(ThePalette);
ThePalette := NewPalette;
if FDither then SetGlobalPalette(ThePalette);
end;
end;
end;
{----------------ThtmlViewer.SetDither}
procedure ThtmlViewer.SetDither(Value: boolean);
begin
if (Value <> FDither) and (ColorBits = 8) then
begin
FDither := Value;
if Value then SetGlobalPalette(ThePalette)
else SetGLobalPalette(0);
end;
end;
procedure ThtmlViewer.SetCaretPos(Value: integer);
begin
if Value >= 0 then
begin
FCaretPos := Value;
end;
end;
function ThtmlViewer.FindSourcePos(DisplayPos: integer): integer;
begin
Result := FSectionList.FindSourcePos(DisplayPos);
end;
function ThtmlViewer.FindDisplayPos(SourcePos: integer; Prev: boolean): integer;
begin
Result := FSectionList.FindDocPos(SourcePos, Prev);
end;
function ThtmlViewer.DisplayPosToXy(DisplayPos: integer; var X, Y: integer): boolean;
begin
Result := FSectionList.CursorToXY(PaintPanel.Canvas, DisplayPos, X, integer(Y)); {integer() req'd for delphi 2}
end;
{----------------ThtmlViewer.SetProcessing}
procedure ThtmlViewer.SetProcessing(Value: boolean);
begin
if FProcessing <> Value then
begin
FProcessing := Value;
if Assigned(FOnProcessing) and not (csLoading in ComponentState) then
FOnProcessing(Self, FProcessing);
end;
end;
procedure THTMLViewer.SetServerRoot(Value: string);
begin
Value := Trim(Value);
if (Length(Value) >= 1) and (Value[Length(Value)] = '\') then
SetLength(Value, Length(Value)-1);
FServerRoot := Value;
end;
procedure THTMLViewer.HandleMeta(Sender: TObject; const HttpEq, Name, Content: string);
var
DelTime, I: integer;
begin
if Assigned(FOnMeta) then FOnMeta(Self, HttpEq, Name, Content);
if Assigned(FOnMetaRefresh) then
if CompareText(Lowercase(HttpEq), 'refresh') = 0 then
begin
I := Pos(';', Content);
if I > 0 then
DelTime := StrToIntDef(copy(Content, 1, I-1), -1)
else DelTime := StrToIntDef(Content, -1);
if DelTime < 0 then Exit
else if DelTime = 0 then DelTime := 1;
I := Pos('url=', Lowercase(Content));
if I > 0 then
FRefreshURL := Copy(Content, I+4, Length(Content)-I-3)
else FRefreshURL := '';
FRefreshDelay := DelTime;
end;
end;
procedure THTMLViewer.SetOptions(Value: ThtmlViewerOptions);
begin
if Value <> FOptions then
begin
FOptions := Value;
if Assigned(FSectionList) then
with FSectionList do
begin
LinksActive := htOverLinksActive in FOptions;
PrintTableBackground := (htPrintTableBackground in FOptions) or
(htPrintBackground in FOptions);
PrintBackground := htPrintBackground in FOptions;
PrintMonoBlack := htPrintMonochromeBlack in FOptions;
ShowDummyCaret := htShowDummyCaret in FOptions;
end;
end;
end;
procedure ThtmlViewer.Repaint;
var
I: integer;
begin
for I := 0 to FormControlList.count-1 do
with TFormControlObj(FormControlList.Items[I]) do
if Assigned(TheControl) then
TheControl.Hide;
{$IFNDEF LCL}
BorderPanel.BorderStyle := bsNone;
{$ELSE}
//inherited BorderStyle := bsNone;
{$ENDIF}
inherited Repaint;
end;
function THTMLViewer.GetDragDrop: TDragDropEvent;
begin
Result := FOnDragDrop;
end;
procedure THTMLViewer.SetDragDrop(const Value: TDragDropEvent);
begin
FOnDragDrop := Value;
if Assigned(Value) then
PaintPanel.OnDragDrop := HTMLDragDrop
else PaintPanel.OnDragDrop := Nil;
end;
procedure THTMLViewer.HTMLDragDrop(Sender, Source: TObject; X, Y: Integer);
begin
if Assigned(FOnDragDrop) then
FOnDragDrop(Self, Source, X, Y);
end;
function THTMLViewer.GetDragOver: TDragOverEvent;
begin
Result := FOnDragOver;
end;
procedure THTMLViewer.SetDragOver(const Value: TDragOverEvent);
begin
FOnDragOver := Value;
if Assigned(Value) then
PaintPanel.OnDragOver := HTMLDragOver
else PaintPanel.OnDragOver := Nil;
end;
procedure THTMLViewer.HTMLDragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
if Assigned(FOnDragOver) then
FOnDragOver(Self, Source, X, Y, State, Accept);
end;
function THTMLViewer.GetFormData: TFreeList;
begin
if Assigned(SectionList) then
Result := SectionList.GetFormControlData
else Result := Nil;
end;
procedure THTMLViewer.SetFormData(T: TFreeList);
begin
if Assigned(SectionList) and Assigned(T) then
with SectionList do
begin
ObjectClick := Nil;
SetFormControlData(T);
ObjectClick := FOnObjectClick;
end;
end;
procedure THTMLViewer.ReplaceImage(const NameID: string; NewImage: TStream);
var
I: integer;
OldPos: integer;
begin
if FNameList.Find(NameID, I) then
if FNameList.Objects[I] is TImageObj then
begin
TImageObj(FNameList.Objects[I]).ReplaceImage(NewImage);
if not TImageObj(FNameList.Objects[I]).ImageKnown then
if FSectionList.Count > 0 then
begin
FSectionList.GetBackgroundBitmap; {load any background bitmap}
OldPos := Position;
DoLogic;
Position := OldPos;
end;
end;
end;
function THTMLViewer.GetIDControl(const ID: string): TObject;
var
I: integer;
Obj: TObject;
begin
Result := Nil;
with FSectionList.IDNameList do
if Find(ID, I) then
begin
Obj := Objects[I];
if (Obj is TFormControlObj) then
begin
if (Obj is THiddenFormControlObj) then
Result := Obj
else Result := TFormControlObj(Obj).TheControl;
end
else if (Obj is TImageObj) then
Result := Obj;
end;
end;
function THTMLViewer.GetIDDisplay(const ID: string): boolean;
var
I: integer;
Obj: TObject;
begin
Result := False;
with FSectionList.IDNameList do
if Find(ID, I) then
begin
Obj := Objects[I];
if (Obj is TBlock) then
Result := not TBlock(Obj).DisplayNone;
end;
end;
procedure THTMLViewer.SetIDDisplay(const ID: string; Value: boolean);
var
I: integer;
Obj: TObject;
begin
with FSectionList.IDNameList do
if Find(ID, I) then
begin
Obj := Objects[I];
if (Obj is TBlock) and (TBlock(Obj).DisplayNone = Value) then
begin
FSectionList.HideControls;
TBlock(Obj).DisplayNone := not Value;
end;
end;
end;
procedure THTMLViewer.SetPrintScale(Value: double);
begin
If Value > 4.0 then
FPrintScale := 4.0
else if Value < 0.25 then
FPrintScale := 0.25
else FPrintScale := Value;
end;
procedure THTMLViewer.Reformat;
var
Pt: TPoint;
begin
Layout;
Update;
GetCursorPos(Pt);
SetCursorPos(Pt.X, Pt.Y); {trigger a mousemove to keep cursor correct}
end;
procedure THTMLViewer.htProgressInit;
begin
if Assigned(FOnProgress) then
FOnProgress(Self, psStarting, 0);
end;
procedure THTMLViewer.htProgress(Percent: Integer);
begin
if Assigned(FOnProgress) then
FOnProgress(Self, psRunning, Percent);
end;
procedure THTMLViewer.htProgressEnd;
begin
if Assigned(FOnProgress) then
FOnProgress(Self, psEnding, 100);
end;
{----------------TPaintPanel.CreateIt}
constructor TPaintPanel.CreateIt(AOwner: TComponent; Viewer: ThtmlViewer);
begin
inherited Create(AOwner);
FViewer := Viewer;
end;
{----------------TPaintPanel.Paint}
procedure TPaintPanel.Paint;
var
MemDC: HDC;
ABitmap: HBitmap;
ARect: TRect;
OldPal: HPalette;
begin
if FViewer.DontDraw or (Canvas2 <> Nil) then
Exit;
FViewer.DrawBorder;
OldPal := 0;
Canvas.Font := Font;
Canvas.Brush.Color := Color;
ARect := Canvas.ClipRect;
Canvas2 := TCanvas.Create; {paint on a memory DC}
try
MemDC := CreateCompatibleDC(Canvas.Handle);
ABitmap := 0;
try
with ARect do
begin
ABitmap := CreateCompatibleBitmap(Canvas.Handle, Right-Left, Bottom-Top);
if (ABitmap = 0) and (Right-Left + Bottom-Top <> 0) then
raise EOutOfResources.Create('Out of Resources');
try
SelectObject(MemDC, ABitmap);
SetWindowOrgEx(memDC, Left, Top, Nil);
Canvas2.Handle := MemDC;
DoBackground(Canvas2);
if Assigned(FOnPaint) then FOnPaint(Self);
OldPal := SelectPalette(Canvas.Handle, ThePalette, False);
RealizePalette(Canvas.Handle);
BitBlt(Canvas.Handle, Left, Top, Right-Left, Bottom-Top,
MemDC, Left, Top, SrcCopy);
finally
if OldPal <> 0 then SelectPalette(MemDC, OldPal, False);
Canvas2.Handle := 0;
end;
end;
finally
DeleteDC(MemDC);
DeleteObject(ABitmap);
end;
finally
FreeAndNil(Canvas2);
end;
end;
procedure TPaintPanel.DoBackground(ACanvas: TCanvas);
var
ARect: TRect;
Image: TGpObject;
Mask, NewBitmap, NewMask: TBitmap;
PRec: PtPositionRec;
BW, BH, X, Y, X2, Y2, IW, IH, XOff, YOff: integer;
AniGif: TGifImage;
begin
with FViewer do
begin
if FSectionList.Printing then
Exit; {no background}
// ARect := Canvas.ClipRect; //bug? get invalid DC with Carbon
ARect := ACanvas.ClipRect;
Image := FSectionList.BackgroundBitmap;
if FSectionList.ShowImages and Assigned(Image) then
begin
Mask := FSectionList.BackgroundMask;
BW := GetImageWidth(Image);
BH := GetImageHeight(Image);
PRec := FSectionList.BackgroundPRec;
BGFixed := PRec[1].Fixed;
if BGFixed then
begin {fixed background}
XOff := 0;
YOff := 0;
IW := Self.ClientRect.Right;
IH := Self.ClientRect.Bottom;
end
else
begin {scrolling background}
XOff := HScrollbar.Position;
YOff := FSectionList.YOff;
IW := HScrollbar.Max;
IH := IntMax(MaxVertical, Self.ClientRect.Bottom);
end;
{Calculate where the tiled background images go}
CalcBackgroundLocationAndTiling(PRec, ARect, XOff, YOff, IW, IH, BW, BH, X, Y, X2, Y2);
if (BW = 1) or (BH = 1) then
begin {this is for people who try to tile 1 pixel images}
NewBitmap := EnlargeImage(Image, X2-X, Y2-Y);// as TBitmap;
try
if Assigned(Mask) then
NewMask := TBitmap(EnlargeImage(Mask, X2-X, Y2-Y))
else NewMask := Nil;
try
DrawBackground(ACanvas, ARect, X, Y, X2, Y2, NewBitmap, NewMask, Nil, NewBitmap.Width, NewBitmap.Height, Self.Color);
finally
NewMask.Free;
end;
finally
NewBitmap.Free;
end;
end
else {normal situation}
begin
AniGif := FSectionList.BackgroundAniGif;
DrawBackground(ACanvas, ARect, X, Y, X2, Y2, Image, Mask, AniGif, BW, BH, Self.Color);
end;
end
else
begin {no background image, show color only}
BGFixed := False;
DrawBackground(ACanvas, ARect, 0,0,0,0, Nil, Nil, Nil, 0, 0, Self.Color);
end;
end;
end;
procedure TPaintPanel.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
Message.Result := 1; {it's erased}
end;
{----------------TPaintPanel.WMLButtonDblClk}
procedure TPaintPanel.WMLButtonDblClk(var Message: TWMMouse);
begin
if Message.Keys and MK_LButton <> 0 then
ThtmlViewer(FViewer).HTMLMouseDblClk(Message);
end;
{$IFNDEF LCL}
{----------------T32ScrollBar.SetParams}
procedure T32ScrollBar.SetParams(APosition, APage, AMin, AMax: Integer);
var
ScrollInfo: TScrollInfo;
begin
if (APosition <> FPosition) or (APage <> FPage) or (AMin <> FMin)
or (AMax <> FMax) then
with ScrollInfo do
begin
cbSize := SizeOf(ScrollInfo);
fMask := SIF_ALL;
if htShowVScroll in (Owner as ThtmlViewer).FOptions then
fMask := fMask or SIF_DISABLENOSCROLL;
nPos := APosition;
nPage := APage;
nMin := AMin;
nMax := AMax;
SetScrollInfo(Handle, SB_CTL, ScrollInfo, True);
FPosition := APosition;
FPage := APage;
FMin := AMin;
FMax := AMax;
end;
end;
procedure T32ScrollBar.SetPosition(Value: integer);
var
SavePos: integer;
begin
SavePos := FPosition;
SetParams(Value, FPage, FMin, FMax);
if FPosition <> SavePos then
Change;
end;
procedure T32ScrollBar.SetMin(Value: Integer);
begin
SetParams(FPosition, FPage, Value, FMax);
end;
procedure T32ScrollBar.SetMax(Value: Integer);
begin
SetParams(FPosition, FPage, FMin, Value);
end;
procedure T32ScrollBar.CNVScroll(var Message: TWMVScroll);
var
SPos: integer;
ScrollInfo: TScrollInfo;
OrigPos: integer;
TheChange: integer;
begin
with ThtmlViewer(Parent) do
begin
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.fMask := SIF_ALL;
GetScrollInfo(Self.Handle, SB_CTL, ScrollInfo);
if TScrollCode(Message.ScrollCode) = scTrack then
begin
OrigPos := ScrollInfo.nPos;
SPos := ScrollInfo.nTrackPos;
end
else
begin
SPos := ScrollInfo.nPos;
OrigPos := SPos;
case TScrollCode(Message.ScrollCode) of
scLineUp:
Dec(SPos, SmallChange);
scLineDown:
Inc(SPos, SmallChange);
scPageUp:
Dec(SPos, LargeChange);
scPageDown:
Inc(SPos, LargeChange);
scTop:
SPos := 0;
scBottom:
SPos := (FMaxVertical - PaintPanel.Height);
end;
end;
SPos := IntMax(0, IntMin(SPos, (FMaxVertical - PaintPanel.Height)));
Self.SetPosition(SPos);
FSectionList.SetYOffset(SPos);
if BGFixed then
PaintPanel.Invalidate
else
begin {scroll background}
TheChange := OrigPos-SPos;
ScrollWindow(PaintPanel.Handle,0,TheChange,NIL,NIL);
PaintPanel.Update;
end;
end;
end;
{$ELSE}
procedure T32ScrollBar.DoOnScroll(sender : TObject; ScrollCode: TScrollCode;
var ScrollPos: Integer);
var
OrigPos : Integer;
TheChange : Integer;
begin
with THTMLViewer(Parent) do
begin
OrigPos := Position; //THTMLViewer.Position
ScrollPos := IntMax(0, IntMin(ScrollPos, (FMaxVertical - PaintPanel.Height)));
Position := ScrollPos; //THTMLViewer.Position
FSectionList.SetYOffset(ScrollPos);
if BGFixed then
PaintPanel.Invalidate
else
begin {scroll background}
TheChange := OrigPos-ScrollPos;
ScrollWindow(PaintPanel.Handle,0,TheChange,NIL,NIL);
PaintPanel.Update;
end;
end;
end;
{$ENDIF}
{ PositionObj }
destructor PositionObj.Destroy;
begin
FormData.Free;
inherited;
end;
end.