mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-28 21:00:43 +02:00
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:
parent
c10575f191
commit
e495c78e4d
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 }
|
||||
|
Loading…
Reference in New Issue
Block a user