diff --git a/lcl/interfaces/customdrawn/customdrawnproc.pas b/lcl/interfaces/customdrawn/customdrawnproc.pas index 14862323b1..32184ab315 100644 --- a/lcl/interfaces/customdrawn/customdrawnproc.pas +++ b/lcl/interfaces/customdrawn/customdrawnproc.pas @@ -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; diff --git a/lcl/lazcanvas.pas b/lcl/lazcanvas.pas index b3a0f31b5e..0250967486 100644 --- a/lcl/lazcanvas.pas +++ b/lcl/lazcanvas.pas @@ -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; diff --git a/lcl/lazregions.pas b/lcl/lazregions.pas index 0049d72bd9..3d57644cff 100644 --- a/lcl/lazregions.pas +++ b/lcl/lazregions.pas @@ -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 }