1 {
2     This file is part of the Free Component Library.
3     Copyright (c) 2016 Michael Van Canneyt, member of the Free Pascal development team
4 
5     FPReport generic LCL Export filter. Can also be used in design mode.
6 
7     See the file COPYING.FPC, included in this distribution,
8     for details about the copyright.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14  **********************************************************************}
15 unit fpreportlclexport;
16 
17 {$mode objfpc}{$H+}
18 { $DEFINE DEBUGRD}
19 
20 interface
21 
22 uses
23   Classes,
24   SysUtils,
25   fpImage,
26   fpReport,
27   contnrs,
28   types,
29   graphics,
30   forms;
31 
32 Const
33   // Design mode constants
34   BandTitleMargin = 2;             // Margin used in band title displaying name of band, in pixels.
35   BandTitleOffset = 12;            // Space between band title and previous band, in pixels
36   ElementHCornerLength = 4;        // Length of horitonzal corner handle
37   ElementVCornerLength = 6;        // Length of horitonzal corner handle
38   clSelectionRect = clDkGray;    // Color for selected elements rectangle
39   clEmementCorner = clBlack;       // Color for element corner indicators.
40   ReSizeHandleHalfWidth = 3;       // Half width of selection resize handle
41   ReSizeHandleWidth = 2 * ReSizeHandleHalfWidth; // Full width of selection resize handle;
42 
43 {  btUnknown,btPageHeader,btReportTitle,btColumnHeader,btDataHeader,btGroupHeader,btDataband,btGroupFooter,
44                                btDataFooter,btColumnFooter,btReportSummary,btPageFooter,btChild);}
45 
46 type
47   {
48     The LCL renderer does not support hyperlinks by itself.
49     It collects a series of URLs and Rects when rendering.
50     The user of the LCL renderer can use this collection to implement
51     onClick and MouseMove handlers that query the List using the IndexOfPoint or FindLinkAtPoint methods.
52     If links overlap, the last added link will be used.
53   }
54 
55   { THyperLinkItem }
56 
57   THyperLinkItem = Class(TCollectionItem)
58   private
59     FRect: TRect;
60     FURL: String;
61   Public
62     Property Rect : TRect Read FRect Write FRect;
63     Property URL : String Read FURL Write FURL;
64   end;
65 
66   { THyperLinkList }
67 
68   THyperLinkList = Class(TCollection)
69   private
GetLnull70     function GetL(AIndex : Integer): THyperLinkItem;
71   Public
IndexOfPointnull72     Function IndexOfPoint(APoint : TPoint) : Integer;
IndexOfPointnull73     Function IndexOfPoint(AX,AY : Integer) : Integer;
FindLinkAtPointnull74     Function FindLinkAtPoint(APoint : TPoint) : THyperlinkItem;
FindLinkAtPointnull75     Function FindLinkAtPoint(AX,AY : Integer) : THyperlinkItem;
AddLinknull76     Function AddLink(Const ARect : TRect; Const AURL : String) : THyperlinkItem;
77     Property Links[AIndex : Integer] : THyperLinkItem Read GetL; default;
78   end;
79 
80   { TFPReportExportCanvas }
81   TReportDrawMode = (dmRender,dmDesign);
82 
83   TFPReportExportCanvas = class(TFPReportExporter)
84   private
85     FCanvas : TCanvas;
86     FDrawMode: TReportDrawMode;
87     FHDPI: integer;
88     FHorzOffset: Integer;
89     FImageWidth: integer;
90     FImageHeight: integer;
91     FFonts : TFPObjectHashTable;
92     FPageIndex : Integer;
93     FPages : TFPList;
94     FShowBandTypeNames: Boolean;
95     FVDPI: integer;
96     FVertOffset: Integer;
97     FZoom: Double;
98     FHyperLinks : THyperLinkList;
99     FBandHandleHeight : Integer;
GetCurrentPagenull100     function GetCurrentPage: TFPReportPage;
GetHyperLinksEnablednull101     function GetHyperLinksEnabled: Boolean;
GetLayoutnull102     function GetLayout(AElement: TFPReportElement): TFPReportLayout;
GetPageCountnull103     function GetPageCount: Integer;
104     procedure PrepareCanvas;
105     procedure SetHyperlinksEnabled(AValue: Boolean);
106     procedure SetPageIndex(AValue: Integer);
107   protected
108     procedure RenderFrame(const AFrame: TFPReportFrame; const ARect: Trect;  const ABackgroundColor: TColor);
109     Procedure RenderImage(aRect : TFPReportRect; var AImage: TFPCustomImage) ; override;
BandColorCodenull110     function BandColorCode(ABand: TFPReportCustomBandClass; Edge : Boolean): TColor; virtual;
111     procedure DrawBandLabel(Aband: TFPReportCustomBand; l: TFPReportLayout); virtual;
112     procedure DrawBandRect(Aband: TFPReportCustomBand; l: TFPReportLayout); virtual;
CreateHyperlinksnull113     Function CreateHyperlinks : THyperLinkList; virtual;
114     procedure DrawElementCorners(E: TFPReportElement; R: TRect); virtual;
GetFontnull115     function GetFont(const AFontName: String): TFont;
116     procedure SetupPageRender(const APage: TFPReportPage);
117     procedure DoExecute(const ARTObjects: TFPList); override;
118     procedure RenderBand(Aband: TFPReportCustomBand); virtual;
119     procedure RenderFrame(const ABand: TFPReportCustomBand; const AFrame: TFPReportFrame; const APos: TFPReportPoint; const AWidth, AHeight: TFPReportUnits); virtual;
120     procedure RenderMemo(const ABand: TFPReportCustomBand; const AMemo: TFPReportCustomMemo); virtual;
121     procedure RenderShape(const ABand: TFPReportCustomBand; const AShape: TFPReportCustomShape); virtual;
122     procedure RenderImage(const ABand: TFPReportCustomBand; const AImage: TFPReportCustomImage); virtual;
123     procedure RenderCheckbox(const ABand: TFPReportCustomBand; const ACheckbox: TFPReportCustomCheckbox); virtual;
GetBandHandleHeightnull124     Function GetBandHandleHeight : Integer;
125   public
126     constructor Create(AOwner: TComponent); override;
127     destructor  Destroy; override;
128     // Rendering options
129     procedure   RenderElement(ABand: TFPReportCustomBand;  Element: TFPReportElement); virtual;
130     procedure   RenderCurrentPage; virtual;
131     procedure   DrawSelectionHandle(ACenter: TPoint; AColor: TColor); virtual;
132     Procedure   DrawSelectionRect(ARect : Trect); virtual;
133     // Moved here to be usable externally
134     procedure RenderShapeCircle(const lpt1: TFPReportPoint; const ALayout: TFPReportLayout);
135     procedure RenderShapeEllipse(const lpt1: TFPReportPoint; const ALayout: TFPReportLayout);
136     procedure RenderShapeLine(lpt1: TFPReportPoint;  const AOrientation: TFPReportOrientation; const ALayout: TFPReportLayout);
137     procedure RenderShapeRect(const lpt1: TFPReportPoint; const ALayout: TFPReportLayout);
138     procedure RenderShapeTriangle(Alpt: TFPReportPoint; const AOrientation: TFPReportOrientation; const ALayout: TFPReportLayout);
139     // Some size/position routines
140     Procedure   GetCurrentPageRenderSize(Out AWidth,AHeight : Integer);
141     Procedure   GetPageRenderSize(APage : TFPReportCustomPage; Out AWidth,AHeight : Integer);
CoordToPointnull142     function    CoordToPoint(const APos: TFPReportPoint;  const AWidth: TFPReportUnits=0; const AHeight: TFPReportUnits=0): TPoint;
CoordToRectnull143     function    CoordToRect(const APos: TFPReportPoint; const AWidth: TFPReportUnits=0; const AHeight: TFPReportUnits=0): TRect;
HmmToPixelsnull144     function    HmmToPixels(const AValue: TFPReportUnits): Integer;
VmmToPixelsnull145     function    VmmToPixels(const AValue: TFPReportUnits): Integer;
PtToPixelsnull146     function    PtToPixels(const AValue: Integer): Integer;
GetPageRectnull147     Function    GetPageRect(APage : TFPReportCustomPage; WithoutMargin : Boolean = False)  : TRect;
GetBandRectnull148     Function    GetBandRect(L : TFPReportLayout;IncludeHandle: Boolean) : TRect;
GetBandRectnull149     Function    GetBandRect(ABand : TFPReportCustomBand; IncludeHandle : Boolean) : TRect;
GetElementRectnull150     Function    GetElementRect(BandLayout,ElementLayout : TFPReportLayout) : TRect;
GetElementRectnull151     Function    GetElementRect(ABand : TFPReportCustomBand; AElement : TFPReportElement) : TRect;
RGBtoBGRnull152     Class function RGBtoBGR(const AColor: UInt32): TColor;
BGRToRGBnull153     Class function BGRToRGB(const AColor: TColor): TFPReportColor;
154     // Properties
155     property    HDPI: integer read FHDPI write FHDPI;
156     property    VDPI: integer read FVDPI write FVDPI;
157     property    Zoom : Double read FZoom write FZoom;
158     Property    Canvas : TCanvas Read FCanvas Write FCanvas;
159     Property    PageIndex : Integer Read FPageIndex Write SetPageIndex;
160     Property    PageCount : Integer Read GetPageCount;
161     Property    CurrentPage : TFPReportPage Read GetCurrentPage;
162     Property    HorzOffset : Integer Read FHorzOffset Write FHorzOffset;
163     Property    VertOffset : Integer Read FVertOffset Write FVertOffset;
164     // collect links ?
165     Property    HyperLinksEnabled : Boolean Read GetHyperLinksEnabled Write SetHyperlinksEnabled;
166     // List of collected hyperlinks. Only valid when HyperLinksEnabled = True.
167     Property    HyperLinks : THyperLinkList Read FHyperLinks;
168     // Design mode or not
169     Property    DrawMode : TReportDrawMode Read FDrawMode Write FDrawMode;
170     // ShowBandTypeNames
171     Property ShowBandTypeNames : Boolean Read FShowBandTypeNames Write FShowBandTypeNames;
172   end;
173 
174 const
175   cInchToMM = 25.4;
176   cPtToDPI = 72;
177   RGBA_Width = 4;
178 
179 implementation
180 
181 uses
182   fpTTF,
183   fpwritepng,
184   math;
185 
186 Resourcestring
187   SErrPageOutOfRange = 'Page index %d out of allowed range [0..%d]';
188 
189 type
190 
191   { for access to Protected methods }
192   TReportImageFriend = class(TFPReportCustomImage);
193   TReportCheckboxFriend = class(TFPReportCustomCheckbox);
194 
195 { TFPImageFriend }
196 
197 
GetColorComponentnull198 function GetColorComponent(Var AColor: UInt32): Word;
199 begin
200   Result:=AColor and $FF;
201   Result:=Result or (Result shl 8);
202   AColor:=AColor shr 8;
203 end;
204 
TFPReportExportCanvas.RGBtoBGRnull205 Class function TFPReportExportCanvas.RGBtoBGR(const AColor: UInt32): TColor;
206 var
207   C : UInt32;
208   R,G,B : Byte;
209 begin
210   C:=AColor;
211   B:= GetColorComponent(C);
212   G:= GetColorComponent(C);
213   R:= GetColorComponent(C);
214 //    Alpha := GetColorComponent(C);
215   Result:=RGBToColor(R,G,B);
216 end;
217 
TFPReportExportCanvas.BGRToRGBnull218 class function TFPReportExportCanvas.BGRToRGB(const AColor: TColor): TFPReportColor;
219 
220 var
221   R,G,B : Byte;
222 
223 begin
224   RedGreenBlue(ColorToRGB(AColor),R,G,B);
225   Result:=RGBToReportColor(R,G,B);
226 end;
227 
228 { THyperLinkList }
229 
GetLnull230 function THyperLinkList.GetL(AIndex : Integer): THyperLinkItem;
231 begin
232   Result:=Items[AIndex] as THyperLinkItem;
233 end;
234 
THyperLinkList.IndexOfPointnull235 function THyperLinkList.IndexOfPoint(APoint: TPoint): Integer;
236 begin
237   Result:=Count-1;
238   While (Result>=0) and (Not ptInRect(GetL(Result).Rect,APoint)) do
239     Dec(Result);
240 end;
241 
THyperLinkList.IndexOfPointnull242 function THyperLinkList.IndexOfPoint(AX, AY: Integer): Integer;
243 begin
244   Result:=IndexOfPoint(Point(AX,AY));
245 end;
246 
THyperLinkList.FindLinkAtPointnull247 function THyperLinkList.FindLinkAtPoint(APoint: TPoint): THyperlinkItem;
248 
249 Var
250   I : Integer;
251 
252 begin
253   I:=IndexOfPoint(APoint);
254   If I=-1 then
255     Result:=Nil
256   else
257     Result:=GetL(I);
258 end;
259 
THyperLinkList.FindLinkAtPointnull260 function THyperLinkList.FindLinkAtPoint(AX, AY: Integer): THyperlinkItem;
261 begin
262   Result:=FindLinkAtPoint(Point(AX,AY));
263 end;
264 
THyperLinkList.AddLinknull265 function THyperLinkList.AddLink(const ARect: TRect; const AURL: String): THyperlinkItem;
266 begin
267   Result:=Add as THyperLinkItem;
268   Result.FRect:=ARect;
269   Result.FURL:=AURL;
270 end;
271 
272 
273 { TFPReportExportCanvas }
274 
275 
HmmToPixelsnull276 function TFPReportExportCanvas.HmmToPixels(const AValue: TFPReportUnits): Integer;
277 begin
278   Result := Round(AValue * (HDPI * Zoom/ cInchToMM));
279 end;
280 
TFPReportExportCanvas.VmmToPixelsnull281 function TFPReportExportCanvas.VmmToPixels(const AValue: TFPReportUnits): Integer;
282 begin
283   Result := Round(AValue * (VDPI * Zoom/ cInchToMM));
284 end;
285 
PtToPixelsnull286 function TFPReportExportCanvas.PtToPixels(const AValue: Integer): Integer;
287 begin
288   // This is used for line widths and ideally should be individually
289   // calculated for every line angle as HDPI and VDPI differ on some
290   // printers. They do not differ greatly though (usually factor 2)
291   // so we get away with an average to keep things simple.
292   Result := Round(AValue * (((HDPI + VDPI) / 2) * Zoom / cPtToDPI));
293 end;
294 
295 procedure TFPReportExportCanvas.SetupPageRender(const APage: TFPReportPage);
296 
297 begin
298   if APage.Orientation = poPortrait then
299     begin
300     FImageWidth := HmmToPixels(APage.PageSize.Width);
301     FImageHeight := VmmToPixels(APage.PageSize.Height);
302     end
303   else
304     begin
305     FImageWidth := HmmToPixels(APage.PageSize.Height);
306     FImageHeight := VmmToPixels(APage.PageSize.Width);
307     end;
308   PrepareCanvas;
309 end;
310 
311 
312 procedure TFPReportExportCanvas.PrepareCanvas;
313 
314 begin
315   Canvas.Pen.Style:=psSolid;
316   Canvas.Pen.Color:=clBlack;
317   Canvas.Brush.Style:=bsSolid;
318   Canvas.Brush.Color:=clWhite;
319   Canvas.FillRect(FHorzOffset,FVertOffset,FHorzOffset+FImageWidth-1,FVertOffset+FImageHeight-1);
320   if Assigned(FHyperLinks) then
321     FHyperLinks.Clear;
322 end;
323 
GetCurrentPagenull324 function TFPReportExportCanvas.GetCurrentPage: TFPReportPage;
325 begin
326   if Assigned(FPages) and (PageIndex<FPages.Count) then
327     Result:=TFPReportPage(FPages[PageIndex])
328   else
329     Result:=Nil;
330 end;
331 
GetHyperLinksEnablednull332 function TFPReportExportCanvas.GetHyperLinksEnabled: Boolean;
333 begin
334   Result:=Assigned(FHyperlinks);
335 end;
336 
TFPReportExportCanvas.GetPageCountnull337 function TFPReportExportCanvas.GetPageCount: Integer;
338 begin
339   if Assigned(FPages) then
340     Result:=FPages.Count
341   else
342     Result:=0;
343 end;
344 
CoordToPointnull345 function TFPReportExportCanvas.CoordToPoint(const APos: TFPReportPoint;
346   const AWidth: TFPReportUnits; const AHeight: TFPReportUnits): TPoint;
347 
348 begin
349   Result.X:=HmmToPixels(APos.Left+AWidth)+FHorzOffset;
350   Result.Y:=VmmToPixels(APos.Top+AHeight)+FVertOffset;
351 end;
352 
TFPReportExportCanvas.CoordToRectnull353 function TFPReportExportCanvas.CoordToRect(const APos: TFPReportPoint;
354   const AWidth: TFPReportUnits; const AHeight: TFPReportUnits): TRect;
355 
356 begin
357   Result.Left:=HmmToPixels(APos.Left)+FHorzOffset;
358   Result.Top:=VmmToPixels(APos.Top)+FVertOffset;
359   Result.Right:=HmmToPixels(APos.Left+AWidth)+FHorzOffset;
360   Result.Bottom:=VmmToPixels(APos.Top+AHeight)+FVertOffset;
361 end;
362 
GetPageRectnull363 function TFPReportExportCanvas.GetPageRect(APage: TFPReportCustomPage;
364   WithoutMargin: Boolean): TRect;
365 
366 Var
367   W,H : Integer;
368 
369 begin
370   GetPageRenderSize(APage,W,H);
371   Result:=Rect(FHorzOffset,FVertOffset,FHorzOffset+W,FVertOffset+H);
372   if WithoutMargin then
373     begin
374     Result.Left:=Result.Left-hMMToPixels(APage.Margins.Left);
375     Result.Top:=Result.Top-VMMToPixels(APage.Margins.Top);
376     Result.Right:=Result.Right+hMMToPixels(APage.Margins.Right);
377     Result.Bottom:=Result.Bottom+VMMToPixels(APage.Margins.Bottom);
378     end;
379 end;
380 
381 procedure TFPReportExportCanvas.RenderFrame(const AFrame: TFPReportFrame;
382   const ARect: Trect; const ABackgroundColor: TColor);
383 
384 var
385   bStroke, bFill: boolean;
386   C : TFPReportColor;
387 
388 begin
389   bStroke := AFrame.Color <> clNone;
390   bFill := AFrame.BackgroundColor <> clNone;
391   if not (bStroke or bFill) then
392     exit;
393   if AFrame.Color = fpReport.clNone then
394     Canvas.Pen.Style := psClear
395   else
396   begin
397     Canvas.Pen.Style:=AFrame.Pen;
398     Canvas.Pen.Color:= RGBtoBGR(AFrame.Color);
399     Canvas.Pen.Width:=PtToPixels(AFrame.Width);
400   end;
401   {$IFDEF DEBUGRD}
402   Writeln('Rendering frame [',AFrame.Shape,'] (',ARect.Left,',',ARect.Top,',',ARect.right,',',ARect.Bottom,') : ',(bStroke or bFill));
403   {$ENDIF}
404   if (AFrame.Shape=fsRectangle) and (bStroke or bFill) then
405     begin
406     if bFill then
407       begin
408       Canvas.Brush.Style:=bsSolid;
409       C:=AFrame.BackgroundColor;
410       if c=fpReport.clNone then
411         C:=ABackgroundColor;
412       if c=fpReport.clNone then
413         C:=fpReport.clWhite;
414       Canvas.Brush.Color := RGBtoBGR(C);
415       FCanvas.FillRect(ARect);
416       end;
417     if bStroke then
418       begin
419       Canvas.Brush.Style:=bsClear;
420       FCanvas.Rectangle(ARect);
421       end;
422     end;
423   if (AFrame.Shape=fsNone) and bStroke then
424     begin
425     if (flTop in AFrame.Lines) then
426       FCanvas.line(ARect.Left, ARect.Top,ARect.Right,ARect.Top);
427     if (flbottom in AFrame.Lines) then
428       FCanvas.line(ARect.Left, ARect.Bottom,ARect.Right,ARect.Bottom);
429     if (flLeft in AFrame.Lines) then
430       FCanvas.line(ARect.Left, ARect.Top,ARect.Left,ARect.Bottom);
431     if (flRight in AFrame.Lines) then
432       FCanvas.line(ARect.Right, ARect.Top,ARect.Right,ARect.Bottom);
433     end;  { Frame.Shape = fsNone }
434 end;
435 
436 procedure TFPReportExportCanvas.RenderImage(aRect: TFPReportRect; var AImage: TFPCustomImage);
437 Var
438   lpt : TFPReportPoint;
439   pt : TPoint;
440   G : TBitmap;
441 
442 begin
443   lPt.Left := aRect.Left;
444   lPt.Top := aRect.Top;
445   PT:=CoordToPoint(Lpt,0,0);
446 //  Canvas.StretchDraw(pt.X,pT.Y,mmToPixels(arect.Width), mmToPixels(arect.Height),AImage);
447   G:=CreateBitmapFromFPImage(aImage);
448   try
449     Canvas.Draw(pt.X,pT.Y,G);
450   Finally
451     G.Free;
452   end;
453 end;
454 
455 procedure TFPReportExportCanvas.RenderFrame(const ABand: TFPReportCustomBand; const AFrame: TFPReportFrame;
456   const APos: TFPReportPoint; const AWidth, AHeight: TFPReportUnits);
457 
458 begin
459   RenderFrame(AFrame,CoordToRect(APos,AWidth,AHeight), ABand.Frame.BackgroundColor);
460 end;
461 
462 Type
463   THackReportMemo = class(TFPReportCustomMemo)
464   published
465     property  Font;
466   end;
467 
TFPReportExportCanvas.GetFontnull468 function TFPReportExportCanvas.GetFont(const AFontName: String): TFont;
469 
470 Var
471   fontCached : TFPFontCacheItem;
472   fontStyles : TFontStyles;
473   ftFont : TFont;
474 
475 begin
476   Result:=Nil;
477   Result:=TFont(FFonts.Items[AFontName]);
478   If (Result=Nil) then
479     begin
480     ftFont:=TFont.create;
481     ftFont.Name:=AFontName;
482     fontCached := gTTFontCache.Find(AFontName);
483     if Assigned(fontCached) then
484       begin
485       // This still requires that the Font is available to the lcl back-end,
486       // custom fpTTF fonts are not implicitly available. E.g. on Windows a
487       // custom font would require the use of AddFontMemResourceEx() to
488       // make it available to GDI (and thus lcl Canvas).
489       ftFont.Name := fontCached.FamilyName;
490       fontStyles := [];
491       if fontCached.IsBold then Include(fontStyles, TFontStyle.fsBold);
492       if fontCached.IsItalic then Include(fontStyles, TFontStyle.fsItalic);
493       ftFont.Style := fontStyles;
494       end;
495     Result:=ftFont;
496     FFonts.Add(AFontName,Result);
497     end;
498 end;
499 
500 procedure TFPReportExportCanvas.RenderMemo(const ABand: TFPReportCustomBand; const AMemo: TFPReportCustomMemo);
501 var
502   lPt1: TFPReportPoint;  // original Report point
503   lMemo: THackReportMemo;
504   i: integer;
505   lXPos: TFPReportUnits;
506   lYPos: TFPReportUnits;
507   txtblk: TFPTextBlock;
508   R,MR : TRect;
509   BL,ML : TFPReportLayout;
510 begin
511   lMemo := THackReportMemo(AMemo);
512 
513   { Store the Top-Left coordinate of the Memo. We will be reusing this info. }
514   BL:=GetLayout(Aband);
515   ML:=GetLayout(AMemo);
516   lPt1.Left := BL.Left + ML.Left;
517   lPt1.Top := BL.Top + ML.Top ;
518   MR:=CoordToRect(LPT1,ML.Width,ML.Height);
519 
520   { Frame must be drawn before the text as it could have a fill color. }
521   RenderFrame(AMemo.Frame, MR, ABand.Frame.BackgroundColor);
522   if DrawMode=dmDesign then
523     begin
524     DrawElementCorners(AMemo,MR);
525     lMemo.RecalcLayout;
526     end;
527   { render the TextBlocks as-is. }
528   for i := 0 to lMemo.TextBlockList.Count-1 do
529   begin
530     txtblk := lMemo.TextBlockList[i];
531     Canvas.Font := GetFont(txtblk.FontName);
532     Canvas.Font.Size:=Round(lMemo.Font.Size * Zoom);
533 
534     lXPos := lPt1.Left + txtblk.Pos.Left;
535     lYPos := lPt1.Top + txtblk.Pos.Top;
536     R:=Rect(HmmToPixels(lXPos) + FHorzOffset,
537             VmmToPixels(lYPos) + FVertOffset,
538             HmmToPixels(lXPos + txtblk.Width) + FHorzOffset,
539             VmmToPixels(lYPos + txtblk.Height + (txtblk.Descender*3)) + FVertOffset);
540     if txtblk.BGColor <> fpReport.clNone then // DON'T remove "fpReport." prefix.
541     begin
542       Canvas.Pen.Style := psClear;
543       Canvas.Brush.Style := bsSolid;
544       Canvas.Brush.Color := RGBtoBGR(txtblk.BGColor);
545       Canvas.Rectangle(R);
546 {      Canvas.Rectangle(
547           mmToPixels(lXPos) + FHorzOffset,
548           mmToPixels(lYPos) + FVertOffset,
549           mmToPixels(lXPos + txtblk.Width) + FHorzOffset,
550           mmToPixels(lYPos + txtblk.Height + (txtblk.Descender*3)) + FVertOffset
551       );}
552     end;
553 
554     Canvas.Pen.Style := psSolid;
555     Canvas.Brush.Style := bsClear;
556     Canvas.Font.Color := RGBtoBGR(txtblk.FGColor);
557     { LCL's Canvas.TextOut origin coordinate is Top-Left }
558     if DrawMode=dmRender then
559       begin
560       Canvas.TextOut(
561           HmmToPixels(lXPos) + FHorzOffset,
562           VmmToPixels(lYPos) + FVertOffset,
563           txtblk.Text
564       );
565       if Assigned(FHyperLinks) and (txtblk is TFPHTTPTextBlock) then
566         FHyperLinks.AddLink(R,(txtblk as TFPHTTPTextBlock).URL);
567       end
568     else
569       begin
570       Canvas.TextRect(
571           MR,
572           HmmToPixels(lXPos) + FHorzOffset,
573           VmmToPixels(lYPos) + FVertOffset,
574           txtblk.Text
575       )
576       end;
577 
578   end;
579 end;
580 
581 procedure TFPReportExportCanvas.RenderShapeCircle(const lpt1: TFPReportPoint;
582   const ALayout: TFPReportLayout);
583 
584 var
585   lPt2: TFPReportPoint;  // original Report point
586   R : TRect;
587   LW : TFPReportUnits;
588 
589 begin
590   // Keep center of circle at center of rectangle
591   lw := Min(ALayout.Width, ALayout.Height);
592   lpt2.Left:=lPt1.Left+(ALayout.Width / 2)-lW/2;
593   lpt2.Top:=lPt1.top+(ALayout.Height / 2)-lW/2;
594   R:=CoordToRect(lpt2,LW,LW);
595   Canvas.ellipse(R);
596 end;
597 
598 procedure TFPReportExportCanvas.RenderShapeEllipse(const lpt1: TFPReportPoint;
599   const ALayout: TFPReportLayout);
600 
601 Var
602   R : TRect;
603 begin
604   R:=CoordToRect(lpt1,ALayout.Width,ALayout.Height);
605   Canvas.ellipse(R);
606 end;
607 
608 procedure TFPReportExportCanvas.RenderShapeLine(lpt1: TFPReportPoint;
609   const AOrientation: TFPReportOrientation; const ALayout: TFPReportLayout);
610 
611 var
612   lPt2: TFPReportPoint;  // original Report point
613   R1,R2 : TPoint;
614 
615 begin
616   case AOrientation of
617   orNorth, orSouth:
618      begin                                         //   |
619      lPt1.Left := lPt1.Left + (ALayout.Width / 2); //   |
620      lPt2.Left := lPt1.Left ;                      //   |
621      lPt2.Top := LPT1.Top + ALayout.Height;        //   |
622      end;
623   orNorthEast, orSouthWest:
624      begin                                         //    /
625      lPt2.Left := lPt1.Left;                       //   /
626      lPt1.Left := lPt1.Left + ALayout.Width;       //  /
627      lPt2.Top := lPt1.Top + ALayout.Height;        // /
628      end;
629   orEast, orWest:
630      begin                                         //
631      lPt2.Left := lPt1.Left + ALayout.Width;       // ----
632      lPt1.Top := lPt1.Top + (ALayout.Height / 2);  //
633      lPt2.Top := lPt1.Top;                         //
634      end;
635   orSouthEast, orNorthWest:
636      begin                                         // \
637      lPt2.Left := lPt1.Left + ALayout.Width;       //  \
638      lPt2.Top := lPt1.Top + ALayout.Height;        //   \
639      end;                                          //    \
640   end;
641   R1:=CoordToPoint(lpt1);
642   R2:=CoordToPoint(lpt2);
643   Canvas.line(R1,R2);
644 end;
645 
646 procedure TFPReportExportCanvas.RenderShapeRect(const lpt1: TFPReportPoint;
647   const ALayout: TFPReportLayout);
648 
649 Var
650   ldx, ldy, lw: TFPReportUnits;
651   P : TFPReportPoint;
652 begin
653   lw := Min(ALayout.Width, ALayout.Height);
654   if ALayout.Width = ALayout.Height then
655   begin
656     ldx := 0;
657     ldy := 0;
658   end
659   else if ALayout.Width > ALayout.Height then
660   begin
661     ldx := (ALayout.Width - ALayout.Height) / 2;
662     ldy := 0;
663   end
664   else if ALayout.Width < ALayout.Height then
665   begin
666     ldx := 0;
667     ldy := (ALayout.Height - ALayout.Width) / 2;
668   end;
669   P.Left := lPt1.Left + ldx;
670   { PDF origin coordinate is Bottom-Left, and Report Layout is Top-Left }
671   P.Top := lPt1.Top + ldy;
672   Canvas.rectangle(CoordToRect(P,lw,Lw));
673 end;
674 
675 procedure TFPReportExportCanvas.RenderShapeTriangle(Alpt: TFPReportPoint;
676   const AOrientation: TFPReportOrientation; const ALayout: TFPReportLayout);
677 
678 
679   Procedure DrawLine(Const A,B : TFPReportPoint);
680 
681   begin
682     Canvas.Line(CoordToPoint(A),CoordToPoint(B));
683   end;
684 
685 var
686   lpt1,lPt2,lpt3: TFPReportPoint;  // original Report points for 3 corners of triangle.
687 
688 begin
689   case AOrientation of
690   orNorth:
691     begin
692     lPt1.Left := ALPT.Left + (ALayout.Width / 2); //      1
693     lPt1.Top  := ALPT.Top;                        //      /\
694     lPt2.Left := ALPT.Left;                       //     /  \
695     lPt2.Top  := ALPT.Top + ALayout.Height;       //    /____\
696     lPt3.Left := ALPT.Left + ALayout.Width;       //  2       3
697     lPt3.Top  := lPt2.Top;
698     end;
699   orNorthEast:
700     begin
701     lPt1.Left := ALPT.Left + (ALayout.Width );    //   +-------1
702     lPt1.Top  := ALPT.Top;                        //   |       |
703     lPt2.Left := ALPT.Left;                       //   2       |
704     lPt2.Top  := ALPT.Top + ALayout.Height/2;     //   |       |
705     lPt3.Left := ALPT.Left + ALayout.Width/2;     //   +---3---+
706     lPt3.Top  := lPt1.Top + aLayout.height;
707     end;
708   orSouth:
709     begin
710     lPt1.Left := ALPT.Left;                        //  1 ------ 2
711     lPt1.Top  := ALPT.Top;                         //    \    /
712     lPt2.Left := ALPT.Left+ ALayout.Width;         //     \  /
713     lPt2.Top  := ALPT.Top;                         //      \/
714     lPt3.Left := ALPT.Left + (ALayout.Width / 2);  //      3
715     lPt3.Top  := ALPT.Top+ALayout.Height;
716     end;
717   orSouthEast:
718     begin
719     lPt1.Left := ALPT.Left + (ALayout.Width/2);   //   +---1---+
720     lPt1.Top  := ALPT.Top;                        //   |       |
721     lPt2.Left := ALPT.Left;                       //   2       |
722     lPt2.Top  := ALPT.Top + ALayout.Height/2;     //   |       |
723     lPt3.Left := ALPT.Left + ALayout.Width;       //   +-------3
724     lPt3.Top  := lPt1.Top + aLayout.height;
725     end;
726   orEast:
727     begin
728     lPt1.Left := ALPT.Left;                       //   1
729     lPt1.Top  := Alpt.Top ;                       //   |\
730     lPt2.Left := ALPT.Left + ALayout.Width;       //   | \ 2
731     lPt2.Top  := ALPT.Top + (ALayout.Height / 2); //   | /
732     lPt3.Left := ALPT.Left;                       //   |/
733     lPt3.Top  := Alpt.Top + ALayout.Height;       //   3
734     end;
735   orNorthWest:
736     begin
737     lPt1.Left := ALPT.Left;                       //   1-------+
738     lPt1.Top  := ALPT.Top;                        //   |       |
739     lPt2.Left := ALPT.Left+ALayout.width;         //   |       2
740     lPt2.Top  := ALPT.Top + ALayout.Height/2;     //   |       |
741     lPt3.Left := ALPT.Left + ALayout.Width/2;     //   +---3---+
742     lPt3.Top  := lPt1.Top + aLayout.height;
743     end;
744   orWest:
745     begin
746     lPt1.Left := ALPT.Left + ALayout.Width;      //       1
747     lPt1.Top  := ALPT.Top;                       //      /|
748     lPt2.Left := ALPT.Left;                      //   2 / |
749     lPt2.Top  := ALPT.Top + ALayout.Height / 2;  //     \ |
750     lPt3.Left := ALPT.Left + ALayout.Width;      //      \|
751     lPt3.Top  := ALPT.Top+ ALayout.Height;       //       3
752     end;
753   orSouthWest:
754     begin
755     lPt1.Left := ALPT.Left+ ALayout.Height/2;     //   +---1---+
756     lPt1.Top  := ALPT.Top;                        //   |       |
757     lPt2.Left := ALPT.Left+ALayout.width;         //   |       2
758     lPt2.Top  := ALPT.Top + ALayout.Height/2;     //   |       |
759     lPt3.Left := ALPT.Left ;                      //   3-------+
760     lPt3.Top  := lPt1.Top + aLayout.height;
761     end;
762   end;
763   DrawLine(lpt1,lpt2);
764   DrawLine(lpt2,lpt3);
765   DrawLine(lpt3,lpt1);
766 end;
767 
GetBandHandleHeightnull768 function TFPReportExportCanvas.GetBandHandleHeight: Integer;
769 begin
770   if (FBandHandleHeight=0) and (Canvas<>Nil) then
771     FBandHandleHeight:=Canvas.TextHeight('W');
772   Result:=FBandHandleHeight;
773 end;
774 
775 procedure TFPReportExportCanvas.RenderShape(const ABand: TFPReportCustomBand; const AShape: TFPReportCustomShape);
776 
777 var
778   lPt1: TFPReportPoint;  // original Report point
779   BL,SL : TFPReportLayout;
780   SR : Trect;
781 
782 begin
783   BL:=GetLayout(ABand);
784   SL:=GetLayout(AShape);
785   SR:=GetElementRect(BL,SL);
786   { Frame must be drawn before the shape as it could have a fill color. }
787   RenderFrame(AShape.Frame, SR, ABand.Frame.BackgroundColor);
788   { exit if Shape will not be visible. }
789   if (TFPReportShape(AShape).Color = fpreport.clNone)
790   or (TFPReportShape(AShape).Color = AShape.Frame.BackgroundColor) then
791     exit;
792   Canvas.Pen.Color:=TFPReportShape(AShape).Color;
793   Canvas.Pen.Style:=psSolid;
794   Canvas.Pen.Width:=PtToPixels(1);
795   lPt1.Left := BL.Left + SL.Left;
796   lPt1.Top := BL.Top + SL.Top;
797   case TFPReportShape(AShape).ShapeType of
798     stEllipse: RenderShapeEllipse(lpt1,SL);
799     stCircle: RenderShapeCircle(lpt1,SL);
800     stLine: RenderShapeLine(lpt1,TFPReportShape(AShape).Orientation, SL);
801     stSquare: RenderShapeRect(lpt1,SL);
802     stTriangle: RenderShapeTriangle(lpt1,TFPReportShape(AShape).Orientation, SL);
803   end;
804   if DrawMode=dmDesign then
805     begin
806     SR:=CoordToRect(LPT1,SL.Width,SL.Height);
807     DrawElementCorners(AShape,SR);
808     end;
809 end;
810 
811 procedure TFPReportExportCanvas.RenderImage(const ABand: TFPReportCustomBand; const AImage: TFPReportCustomImage);
812 var
813   lPt: TFPReportPoint;
814   img: TReportImageFriend;
815   PT : TPoint;
816   R : TRect;
817   G : TBitmap;
818   BL,IL : TFPReportLayout;
819 
820 begin
821   img := TReportImageFriend(AImage);  { for access to Protected methods }
822   BL:=GetLayout(ABand);
823   IL:=GetLayout(AImage);
824   lPt.Left := BL.Left + IL.Left;
825   lPt.Top := BL.Top + IL.Top;
826   PT:=CoordToPoint(Lpt,0,0);
827 
828   { Frame must be drawn before the Image as it could have a fill color. }
829   RenderFrame(ABand, AImage.Frame, lPt, IL.Width, IL.Height);
830   if not Assigned(img.Image) then
831     Exit; { nothing further to do }
832   G:=CreateBitmapFromFPImage(img.Image);
833   try
834     if img.Stretched then
835       begin
836       R:=Rect(pt.X,pT.Y,pt.X+HmmToPixels(IL.Width), pt.Y+VmmToPixels(IL.Height));
837       Canvas.StretchDraw(R,G)
838       end
839     else
840       Canvas.Draw(pt.X,pT.Y,G);
841   finally
842     G.Free;
843   end;
844   if DrawMode=dmDesign then
845     DrawElementCorners(AImage,R);
846 end;
847 
848 procedure TFPReportExportCanvas.RenderCheckbox(const ABand: TFPReportCustomBand; const ACheckbox: TFPReportCustomCheckbox);
849 var
850   lPt: TFPReportPoint;
851   pt : TPoint;
852   cb: TReportCheckboxFriend;
853   lImage: TFPCustomImage;
854   G : TBitmap;
855   R : TRect;
856   BL,CL : TFPReportLayout;
857 
858 begin
859   cb := TReportCheckboxFriend(ACheckbox);  { for access to Protected methods }
860   BL:=GetLayout(ABand);
861   CL:=GetLayout(ACheckbox);
862   lPt.Left := BL.Left + CL.Left;
863   lPt.Top := BL.Top + CL.Top;
864   Pt:=CoordToPoint(lpt);
865   lImage:=cb.GetRTImage;
866   G:=CreateBitmapFromFPImage(lImage);
867   try
868     R:=Rect(pt.X,Pt.Y,pt.X+HmmToPixels(CL.Width), pt.Y+VmmToPixels(CL.Height));
869     Canvas.StretchDraw(R,g);
870   finally
871     G.Free;
872   end;
873   if DrawMode=dmDesign then
874     DrawElementCorners(ACheckBox,R);
875 end;
876 
877 constructor TFPReportExportCanvas.Create(AOwner: TComponent);
878 begin
879   inherited Create(AOwner);
880   FHDPI := Screen.PixelsPerInch;
881   FVDPI := FHDPI;
882   Zoom:=1;
883   FImageWidth := 0;
884   FImageHeight := 0;
885   // store the original DPI, we will restore it later
886   FFonts:=TFPObjectHashTable.Create(True);
887   FShowBandTypeNames:=True;
888 end;
889 
890 destructor TFPReportExportCanvas.Destroy;
891 begin
892   FreeAndNil(FHyperLinks);
893   FreeAndNil(FFonts);
894   inherited Destroy;
895 end;
896 
897 procedure TFPReportExportCanvas.GetCurrentPageRenderSize(out AWidth,
898   AHeight: Integer);
899 begin
900   GetPageRenderSize(CurrentPage,AWidth,AHeight);
901 end;
902 
903 procedure TFPReportExportCanvas.GetPageRenderSize(APage: TFPReportCustomPage;
904   out AWidth, AHeight: Integer);
905 begin
906   if (APage.Orientation=poPortrait) then
907     begin
908     AWidth := HmmToPixels(APage.PageSize.Width);
909     AHeight := VmmToPixels(APage.PageSize.Height);
910     end
911   else
912     begin
913     AWidth := VmmToPixels(APage.PageSize.Height);
914     AHeight := HmmToPixels(APage.PageSize.Width);
915     end;
916 end;
917 
918 procedure TFPReportExportCanvas.RenderElement(ABand : TFPReportCustomBand; Element : TFPReportElement);
919 
920 Var
921   C : TFPReportPoint;
922   LB,LE : TFPReportLayout;
923 
924 begin
925   {$IFDEF DEBUGRD}
926   Writeln('Rendering element ',Element.ClassName,' (',Element.Name,')');
927   {$ENDIF}
928   if (Element is TFPReportCustomBand)  then
929     RenderBand(Element as TFPReportCustomBand);
930   if Element is TFPReportCustomMemo then
931     RenderMemo(Aband,TFPReportCustomMemo(Element))
932   else if Element is TFPReportCustomShape then
933     RenderShape(ABand,TFPReportCustomShape(Element))
934   else if Element is TFPReportCustomImage then
935     RenderImage(Aband,TFPReportCustomImage(Element))
936   else if Element is TFPReportCustomCheckbox then
937     RenderCheckbox(ABand,TFPReportCustomCheckbox(Element))
938   else if not (Element is TFPReportCustomBand) then
939     begin
940     LB:=GetLayout(ABand);
941     LE:=GetLayout(Element);
942     C.Left := LB.Left + LE.Left;
943     C.Top := LB.Top + LE.Top ; // + Element.RTLayout.Height;
944     RenderFrame(ABand, Element.Frame, C, LE.Width, LE.Height);
945     C.Left:=LB.Left;
946     C.Top:=LB.Top;
947     RenderUnknownElement(C,Element,Self.VDPI);
948     end;
949 end;
950 
951 procedure TFPReportExportCanvas.SetHyperlinksEnabled(AValue: Boolean);
952 begin
953   {$IFDEF DEBUGRD}Writeln('TFPReportExportCanvas.SetHyperlinksEnabled(',AValue,')');{$ENDIF}
954   if (AValue=GetHyperLinksEnabled) then exit;
955   If AValue then
956     FHyperLinks:=CreateHyperlinks
957   else
958     FreeAndNil(FHyperLinks);
959 end;
960 
961 procedure TFPReportExportCanvas.SetPageIndex(AValue: Integer);
962 begin
963   if FPageIndex=AValue then Exit;
964   FPageIndex:=AValue;
965   if Assigned(Report) and (FPageIndex<0) or (FPageIndex>=PageCount) then
966     Raise EReportError.CreateFmt(SErrPageOutOfRange,[FPageIndex,PageCount-1]);
967   RenderCurrentPage;
968 end;
969 
CreateHyperlinksnull970 function TFPReportExportCanvas.CreateHyperlinks: THyperLinkList;
971 begin
972   {$IFDEF DEBUGRD}Writeln('TFPReportExportCanvas.CreateHyperlinks');{$ENDIF}
973   Result:=THyperLinkList.Create(THyperLinkItem);
974 end;
975 
TFPReportExportCanvas.GetLayoutnull976 function TFPReportExportCanvas.GetLayout(AElement: TFPReportElement
977   ): TFPReportLayout;
978 
979 begin
980   if DrawMode=dmRender then
981     Result:=AElement.RTLayout
982   else
983     Result:=AElement.Layout;
984 end;
985 
BandColorCodenull986 function TFPReportExportCanvas.BandColorCode(ABand: TFPReportCustomBandClass;
987   Edge: Boolean): TColor;
988 
989 begin
990   if Edge then
991     Result := RGBtoBGR(DefaultBandRectangleColors[ABand.ReportBandType])
992   else
993     Result := RGBtoBGR(DefaultBandColors[ABand.ReportBandType]);
994 end;
995 
996 procedure TFPReportExportCanvas.DrawBandLabel(Aband: TFPReportCustomBand; l : TFPReportLayout);
997 Var
998   N : String;
999   TH,X,Y : Integer;
1000   TopLeft : TFPReportPoint;
1001 begin
1002   TopLeft.Left:=L.Left;
1003   TopLeft.Top:=L.Top;
1004   N:=ABand.Name;
1005   if N='' then
1006     N:='Unnamed '+DefaultBandNames[ABand.ReportBandType]+' band'
1007   else if ShowBandTypeNames then
1008     N:=N+' ('+DefaultBandNames[ABand.ReportBandType]+')';
1009   Canvas.Font.Name:='default';
1010   Canvas.Font.Size:=10;
1011   Canvas.Font.Style:=[];
1012   Canvas.Font.Color:=clBlack;
1013   TH:=GetBandHandleHeight;
1014   X:=FHorzOffset+HmmToPixels(TopLeft.Left);
1015   Y:=FVertOffset+VmmToPixels(TopLeft.Top)-TH-2*BandTitleMargin;
1016   Canvas.Brush.Color:=BandColorCode(TFPReportCustomBandClass(ABand.ClassType),False);
1017   Canvas.Pen.Style:=psSolid;
1018   Canvas.Pen.Color:=BandColorCode(TFPReportCustomBandClass(ABand.ClassType),True);
1019   Canvas.Rectangle(X,Y,X+HmmToPixels(L.Width),Y+TH+2*BandTitleMargin);
1020   Y:=Y+BandTitleMargin;
1021   X:=X+BandTitleMargin;
1022  {$IFDEF DEBUGRD}Writeln('Writing name : Canvas.TextOut(',X,',',Y,',',N,')');{$ENDIF}
1023   Canvas.TextOut(X,Y,N);
1024 end;
1025 
1026 procedure TFPReportExportCanvas.DrawElementCorners(E : TFPReportElement; R : TRect);
1027 
1028 
1029 begin
1030   Canvas.Pen.Style:=psSolid;
1031   Canvas.Pen.Color:=clEmementCorner;
1032   // Horizontal, top
1033   Canvas.Line(R.Left,R.Top,R.Left+ElementHCornerLength,R.Top);
1034   Canvas.Line(R.Right-ElementHCornerLength,R.Top,R.Right,R.Top);
1035   // Horizontal, bottom
1036   Canvas.Line(R.Left,R.Bottom,R.Left+ElementHCornerLength,R.Bottom);
1037   Canvas.Line(R.Right-ElementHCornerLength,R.Bottom,R.Right,R.Bottom);
1038   // Vertical, Top
1039   Canvas.Line(R.Left,R.Top,R.Left,R.Top+ElementVCornerLength);
1040   Canvas.Line(R.Right,R.Top,R.Right,R.Top+ElementVCornerLength);
1041   // Vertical, bottom
1042   Canvas.Line(R.Left,R.Bottom,R.Left,R.Bottom-ElementVCornerLength);
1043   Canvas.Line(R.Right,R.Bottom,R.Right,R.Bottom-ElementVCornerLength);
1044 end;
1045 
1046 procedure TFPReportExportCanvas.DrawBandRect(Aband: TFPReportCustomBand; l : TFPReportLayout);
1047 
1048 Var
1049   DR : TRect;
1050 
1051 begin
1052   DR:=GetBandRect(L,False);
1053   Canvas.Brush.Style:=bsClear;
1054   Canvas.Pen.Style:=psSolid;
1055   Canvas.Pen.Color:=BandColorCode(TFPReportCustomBandClass(ABand.ClassType),true);
1056   Canvas.Rectangle(DR);
1057   DrawElementCorners(ABand,DR);
1058 end;
1059 
1060 procedure TFPReportExportCanvas.RenderBand(Aband: TFPReportCustomBand);
1061 
1062 Var
1063   lPt1: TFPReportPoint;  // original Report point
1064   I : integer;
1065   L : TFPReportLayout;
1066 
1067 begin
1068   L:=GetLayout(ABand);
1069   {$IFDEF DEBUGRD}
1070   Writeln('Renderband ',ABand.ClassName,' : ',ABand.Name,' (',L.Width,' x ',L.Height,')');
1071   {$ENDIF}
1072   if DrawMode=dmDesign then
1073     begin
1074     DrawBandLabel(ABand,L);
1075     DrawBandRect(Aband,L);
1076     end;
1077   lpt1.Left:=L.Left;
1078   lpt1.Top:=L.Top;
1079   RenderFrame(Aband, Aband.Frame, lPt1, L.Width, L.Height);
1080   if DrawMode=dmRender then
1081     for I:=0 to Aband.ChildCount-1 do
1082       RenderElement(ABand,Aband.Child[i]);
1083 end;
1084 
1085 procedure TFPReportExportCanvas.RenderCurrentPage;
1086 
1087 var
1088   b: integer;
1089   rpage: TFPReportPage;
1090 
1091 begin
1092   If Not Assigned(Canvas) then exit;
1093   rpage := CurrentPage;
1094   If Not Assigned(rpage) then exit;
1095   SetupPageRender(rpage);
1096   for b := 0 to (rpage.BandCount - 1) do
1097     RenderBand(rpage.Bands[b]);
1098 end;
1099 
TFPReportExportCanvas.GetBandRectnull1100 function TFPReportExportCanvas.GetBandRect(L: TFPReportLayout;IncludeHandle: Boolean): TRect;
1101 
1102 Var
1103   LPT1 : TFPReportPoint;
1104 
1105 begin
1106   lpt1.Left:=L.Left;
1107   lpt1.Top:=L.Top;
1108   Result:=CoordToRect(LPT1,L.Width, L.Height);
1109   if IncludeHandle then
1110     Result.Top:=Result.Top-GetBandHandleHeight;
1111 end;
1112 
TFPReportExportCanvas.GetBandRectnull1113 function TFPReportExportCanvas.GetBandRect(ABand: TFPReportCustomBand;
1114   IncludeHandle: Boolean): TRect;
1115 begin
1116   Result:=GetBandRect(GetLayout(ABand),IncludeHandle);
1117 end;
1118 
TFPReportExportCanvas.GetElementRectnull1119 function TFPReportExportCanvas.GetElementRect(BandLayout,
1120   ElementLayout: TFPReportLayout): TRect;
1121 
1122 Var
1123   LPT1 : TFPReportPoint;
1124 
1125 begin
1126   lpt1.Left:=BandLayout.Left+ElementLayout.Left;
1127   lpt1.Top:=BandLayout.Top+ElementLayout.Top;
1128   Result:=CoordToRect(LPT1,ElementLayout.Width,ElementLayout.Height);
1129 end;
1130 
TFPReportExportCanvas.GetElementRectnull1131 function TFPReportExportCanvas.GetElementRect(ABand: TFPReportCustomBand;
1132   AElement: TFPReportElement): TRect;
1133 begin
1134   Result:=GetElementRect(GetLayout(ABand),GetLayout(AElement));
1135 end;
1136 
1137 procedure TFPReportExportCanvas.DrawSelectionHandle(ACenter: TPoint;
1138   AColor: TColor);
1139 
1140 begin
1141   With Canvas do
1142     begin
1143     Brush.Color:=AColor;
1144     Brush.Style:=bsSolid;
1145     Pen.Color:=AColor;
1146     Pen.Style:=psSolid;
1147     {$IFDEF DEBUGRD}Writeln('Drawing selection handle at (',ACenter.X,',',ACenter.Y,')');{$ENDIF}
1148     with ACenter do
1149       Rectangle(X-ReSizeHandleHalfWidth,Y-ReSizeHandleHalfWidth,X+ReSizeHandleHalfWidth,Y+ReSizeHandleHalfWidth);
1150     end;
1151 end;
1152 
1153 procedure TFPReportExportCanvas.DrawSelectionRect(ARect: Trect);
1154 begin
1155   Canvas.Brush.Style:=bsClear;
1156   Canvas.Pen.Color:=clSelectionRect;
1157   Canvas.Pen.Style:=psDash;
1158   Canvas.Rectangle(ARect);
1159 end;
1160 
1161 procedure TFPReportExportCanvas.DoExecute(const ARTObjects: TFPList);
1162 
1163 begin
1164   FPages:=ARTObjects;
1165   RenderCurrentPage;
1166 end;
1167 
1168 end.
1169 
1170