Reworks the drawing code in LCL-CustomDrawn to support drawing only 1 control or it and its children, adds more elements to the lazcanvas save state and makes lazregions more similar for fpc 2.7 and old versions by adding a copy of TFPCustomRegion

git-svn-id: trunk@34038 -
This commit is contained in:
sekelsenmat 2011-12-08 09:48:14 +00:00
parent c10575f191
commit e495c78e4d
3 changed files with 110 additions and 70 deletions

View File

@ -70,8 +70,10 @@ procedure UpdateControlLazImageAndCanvas(var AImage: TLazIntfImage;
procedure DrawFormBackground(var AImage: TLazIntfImage; var ACanvas: TLazCanvas);
procedure RenderChildWinControls(var AImage: TLazIntfImage;
var ACanvas: TLazCanvas; ACDControlsList: TFPList);
//procedure RenderWinControl(var AImage: TLazIntfImage;
// var ACanvas: TLazCanvas; ACDControlsList: TFPList);
function RenderWinControl(var AImage: TLazIntfImage;
var ACanvas: TLazCanvas; ACDWinControl: TCDWinControl): Boolean;
procedure RenderWinControlAndChildren(var AImage: TLazIntfImage;
var ACanvas: TLazCanvas; ACDWinControl: TCDWinControl);
function FindControlWhichReceivedEvent(AForm: TCustomForm;
AControlsList: TFPList; AX, AY: Integer): TWinControl;
function FindControlPositionRelativeToTheForm(ALCLControl: TWinControl): TPoint;
@ -265,82 +267,108 @@ begin
ACanvas.RestoreState;
end;
// This does not render the win control itself, only it's children
// The WinControls themselves will render child TControls not descending from TWinControl
procedure RenderChildWinControls(var AImage: TLazIntfImage;
var ACanvas: TLazCanvas; ACDControlsList: TFPList);
var
i, lChildrenCount: Integer;
lCDWinControl: TCDWinControl;
lWinControl, lParentControl: TWinControl;
struct : TPaintStruct;
lCanvas: TCanvas;
lBaseWindowOrg: TPoint;
begin
lChildrenCount := ACDControlsList.Count;
{$ifdef VerboseCDWinControl}
DebugLn(Format('[RenderChildWinControls] ACanvas=%x ACDControlsList=%x lChildrenCount=%d',
[PtrInt(ACanvas), PtrInt(ACDControlsList), lChildrenCount]));
{$endif}
FillChar(struct, SizeOf(TPaintStruct), 0);
struct.hdc := HDC(ACanvas);
for i := 0 to lChildrenCount-1 do
begin
{$ifdef VerboseCDWinControl}
DebugLn(Format('[RenderChildWinControls] i=%d', [i]));
{$endif}
lCDWinControl := TCDWinControl(ACDControlsList.Items[i]);
lWinControl := lCDWinControl.WinControl;
{$ifdef VerboseCDWinControl}
DebugLn(Format('[RenderChildWinControls] i=%d lWinControl=%x Name=%s:%s Left=%d'
+ ' Top=%d Width=%d Height=%d', [i, PtrInt(lWinControl), lWinControl.Name, lWinControl.ClassName,
lWinControl.Left, lWinControl.Top, lWinControl.Width, lWinControl.Height]));
{$endif}
if lWinControl.Visible = False then Continue;
// lBaseWindowOrg makes debugging easier
// Iterate to find the appropriate BaseWindowOrg relative to the parent control
lBaseWindowOrg := FindControlPositionRelativeToTheForm(lWinControl);
ACanvas.BaseWindowOrg := lBaseWindowOrg;
ACanvas.WindowOrg := Point(0, 0);
RenderWinControlAndChildren(AImage, ACanvas, lCDWinControl);
end;
end;
// Prepare the clippping relative to the form
ACanvas.Clipping := True;
lCDWinControl.Region.Rect := Bounds(lBaseWindowOrg.X, lBaseWindowOrg.Y, lWinControl.Width, lWinControl.Height);
ACanvas.ClipRegion := lCDWinControl.Region;
// Renders a WinControl, but not it's children
// Returns if the control is visible and therefore if its children should be rendered
function RenderWinControl(var AImage: TLazIntfImage; var ACanvas: TLazCanvas;
ACDWinControl: TCDWinControl): Boolean;
var
lWinControl, lParentControl: TWinControl;
struct : TPaintStruct;
lCanvas: TCanvas;
lBaseWindowOrg: TPoint;
begin
Result := False;
// Save the Canvas state
FillChar(struct, SizeOf(TPaintStruct), 0);
struct.hdc := HDC(ACanvas);
lWinControl := ACDWinControl.WinControl;
{$ifdef VerboseCDWinControl}
DebugLn(Format('[RenderWinControl] lWinControl=%x Name=%s:%s Left=%d'
+ ' Top=%d Width=%d Height=%d', [PtrInt(lWinControl), lWinControl.Name, lWinControl.ClassName,
lWinControl.Left, lWinControl.Top, lWinControl.Width, lWinControl.Height]));
{$endif}
if lWinControl.Visible = False then Exit;
// Save the Canvas state
ACanvas.SaveState;
ACanvas.ResetCanvasState;
// lBaseWindowOrg makes debugging easier
// Iterate to find the appropriate BaseWindowOrg relative to the parent control
lBaseWindowOrg := FindControlPositionRelativeToTheForm(lWinControl);
ACanvas.BaseWindowOrg := lBaseWindowOrg;
ACanvas.WindowOrg := Point(0, 0);
// Prepare the clippping relative to the form
ACanvas.Clipping := True;
ACDWinControl.Region.Rect := Bounds(lBaseWindowOrg.X, lBaseWindowOrg.Y, lWinControl.Width, lWinControl.Height);
ACanvas.ClipRegion := ACDWinControl.Region;
// Special drawing for some native controls
if lWinControl is TCustomPanel then
begin
// Erase the background of TPanel controls, since it can draw it's own border, but fails to draw it's own background
ACanvas.SaveState;
ACanvas.ResetCanvasState;
// Special drawing for some native controls
if lWinControl is TCustomPanel then
begin
// Erase the background of TPanel controls, since it can draw it's own border, but fails to draw it's own background
ACanvas.Brush.FPColor := TColorToFPColor((lWinControl as TCustomPanel).GetRGBColorResolvingParent());
ACanvas.Pen.FPColor := ACanvas.Brush.FPColor;
ACanvas.Rectangle(Bounds(0, 0, lWinControl.Width, lWinControl.Height));
ACanvas.ResetCanvasState;
end;
// Send the drawing message
{$ifdef VerboseCDWinControl}
DebugLn(Format('[RenderChildWinControls] i=%d before LCLSendPaintMsg', [i]));
{$endif}
LCLSendPaintMsg(lWinControl, struct.hdc, @struct);
// Now Draw all sub-controls
if lCDWinControl.Children <> nil then
RenderChildWinControls(AImage, ACanvas, lCDWinControl.Children);
{$ifdef VerboseCDWinControl}
DebugLn(Format('[RenderChildWinControls] i=%d Finished child controls', [i]));
{$endif}
// Now restore it
ACanvas.Brush.FPColor := TColorToFPColor((lWinControl as TCustomPanel).GetRGBColorResolvingParent());
ACanvas.Pen.FPColor := ACanvas.Brush.FPColor;
ACanvas.Rectangle(Bounds(0, 0, lWinControl.Width, lWinControl.Height));
ACanvas.RestoreState;
end;
ACanvas.Clipping := False;
ACanvas.BaseWindowOrg := Point(0, 0);
ACanvas.WindowOrg := Point(0, 0);
// Send the drawing message
{$ifdef VerboseCDWinControl}
DebugLn('[RenderWinControl] before LCLSendPaintMsg');
{$endif}
LCLSendPaintMsg(lWinControl, struct.hdc, @struct);
{$ifdef VerboseCDWinControl}
DebugLn('[RenderWinControl] after LCLSendPaintMsg');
{$endif}
// Now restore it
ACanvas.RestoreState;
Result := True;
end;
// Render a WinControl and all it's children
procedure RenderWinControlAndChildren(var AImage: TLazIntfImage;
var ACanvas: TLazCanvas; ACDWinControl: TCDWinControl);
begin
// Draw the control
if not RenderWinControl(AImage, ACanvas, ACDWinControl) then Exit;
// Now Draw all sub-controls
if ACDWinControl.Children <> nil then
RenderChildWinControls(AImage, ACanvas, ACDWinControl.Children);
end;
function FindControlWhichReceivedEvent(AForm: TCustomForm;

View File

@ -57,6 +57,8 @@ type
Pen: TFPCustomPen;
BaseWindowOrg: TPoint;
WindowOrg: TPoint;
Clipping: Boolean;
ClipRegion: TFPCustomRegion;
destructor Destroy; override;
end;
@ -68,7 +70,7 @@ type
FAssignedPen: TFPCustomPen;
FBaseWindowOrg: TPoint;
{$if defined(ver2_4) or defined(ver2_5) or defined(ver2_6)}
FLazClipRegion: TLazRegion;
FLazClipRegion: TFPCustomRegion;
{$endif}
FWindowOrg: TPoint; // already in absolute coords with BaseWindowOrg summed up
GraphicStateStack: TObjectStack; // TLazCanvasState
@ -120,7 +122,7 @@ type
// based upon the BaseWindowOrg which is set relative to the Form canvas
property BaseWindowOrg: TPoint read FBaseWindowOrg write FBaseWindowOrg;
{$if defined(ver2_4) or defined(ver2_5) or defined(ver2_6)}
property ClipRegion: TLazRegion read FLazClipRegion write FLazClipRegion;
property ClipRegion: TFPCustomRegion read FLazClipRegion write FLazClipRegion;
{$endif}
property WindowOrg: TPoint read GetWindowOrg write SetWindowOrg;
end;
@ -338,16 +340,13 @@ end;
procedure TLazCanvas.SetLazClipRegion(ARegion: TLazRegion);
begin
if ARegion.IsSimpleRectRegion then
begin
Clipping := True;
{$if defined(ver2_4) or defined(ver2_5) or defined(ver2_6)}
ClipRect := TLazRegionRect(ARegion.Parts.Items[0]).Rect;
FLazClipRegion := ARegion;
{$else}
ClipRegion := ARegion;
{$endif}
end;
Clipping := True;
{$if defined(ver2_4) or defined(ver2_5) or defined(ver2_6)}
ClipRect := TLazRegionRect(ARegion.Parts.Items[0]).Rect;
FLazClipRegion := ARegion;
{$else}
ClipRegion := ARegion;
{$endif}
end;
procedure TLazCanvas.SaveState;
@ -358,6 +357,9 @@ begin
lState.Brush := Brush.CopyBrush;
lState.Pen := Pen.CopyPen;
lState.BaseWindowOrg := BaseWindowOrg;
lState.WindowOrg := WindowOrg;
lState.Clipping := Clipping;
GraphicStateStack.Push(lState);
end;
@ -371,6 +373,9 @@ begin
AssignPenData(lState.Pen);
AssignBrushData(lState.Brush);
BaseWindowOrg := lState.BaseWindowOrg;
WindowOrg := lState.WindowOrg;
Clipping := lState.Clipping;
lState.Free;
end;

View File

@ -29,7 +29,14 @@ type
function IsPointInPart(AX, AY: Integer): Boolean; override;
end;
TLazRegion = class{$if defined(ver2_7) or defined(ver2_8) or defined(ver2_9)}(TFPCustomRegion){$endif}
{$if defined(ver2_4) or defined(ver2_5) or defined(ver2_6)}
TFPCustomRegion = class
function GetBoundingRect: TRect; virtual; abstract;
function IsPointInRegion(AX, AY: Integer): Boolean; virtual; abstract;
end;
{$endif}
TLazRegion = class(TFPCustomRegion)
public
// The parts of a region should all be inside valid areas of the region
// so if a combination operation removes some areas of the region, then
@ -42,8 +49,8 @@ type
destructor Destroy; override;
procedure AddRectangle(ARect: TRect);
procedure SetAsSimpleRectRegion(ARect: TRect);
function GetBoundingRect: TRect; {$if defined(ver2_4) or defined(ver2_5) or defined(ver2_6)}virtual;{$else}override;{$endif}
function IsPointInRegion(AX, AY: Integer): Boolean; {$if defined(ver2_4) or defined(ver2_5) or defined(ver2_6)}virtual;{$else}override;{$endif}
function GetBoundingRect: TRect; override;
function IsPointInRegion(AX, AY: Integer): Boolean; override;
end;
{ This is a region which can hold other region holders inside it }