LCL-CustomDrawn: Starts implementing the new drawing model with buffered control images

git-svn-id: trunk@35917 -
This commit is contained in:
sekelsenmat 2012-03-13 07:26:07 +00:00
parent fb7f52ecb8
commit 221327700f
3 changed files with 72 additions and 29 deletions

View File

@ -40,3 +40,8 @@
//{$define CD_UseNativeText} //{$define CD_UseNativeText}
{$endif} {$endif}
// Other options
// This option makes the drawing faster by buffering previous drawing operations
{$define CD_BufferControlImages}

View File

@ -1,6 +1,7 @@
unit customdrawnproc; unit customdrawnproc;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
{$include customdrawndefines.inc}
interface interface
@ -42,8 +43,16 @@ type
ScrollX, ScrollY: Integer; ScrollX, ScrollY: Integer;
LastMousePos: TPoint; LastMousePos: TPoint;
IsScrolling: Boolean; IsScrolling: Boolean;
// Counter to keep track of when we requested Invalidate
// Some systems like X11 and Win32 will keep sending unnecessary paint messages
// so for them we just throw the previously painted image
InvalidateCount: Integer;
// painting objects
ControlImage: TLazIntfImage;
ControlCanvas: TLazCanvas;
constructor Create; virtual; constructor Create; virtual;
destructor Destroy; override; destructor Destroy; override;
procedure IncInvalidateCount;
function AdjustCoordinatesForScrolling(AX, AY: Integer): TPoint; function AdjustCoordinatesForScrolling(AX, AY: Integer): TPoint;
property Props[AnIndex:String]:pointer read GetProps write SetProps; property Props[AnIndex:String]:pointer read GetProps write SetProps;
end; end;
@ -56,6 +65,7 @@ type
WinControl: TWinControl; WinControl: TWinControl;
CDControl: TCDControl; CDControl: TCDControl;
CDControlInjected: Boolean; CDControlInjected: Boolean;
procedure UpdateImageAndCanvas;
end; end;
{ TCDForm } { TCDForm }
@ -69,15 +79,10 @@ type
FocusedControl: TWinControl; // The control focused in the form FocusedControl: TWinControl; // The control focused in the form
FocusedIntfControl: TWinControl; // The intf control focused in the form FocusedIntfControl: TWinControl; // The intf control focused in the form
LayoutAutoAdjusted: Boolean; // Indicates if the form layout was already auto-adjusted once LayoutAutoAdjusted: Boolean; // Indicates if the form layout was already auto-adjusted once
// Counter to keep track of when we requested Invalidate // painting objects which represent the composed form image, don't confuse with ControlImage/ControlCanvas
// Some systems like X11 and Win32 will keep sending unnecessary paint messages
// so for them we just throw the previously painted image
InvalidateCount: Integer;
// painting objects
Image: TLazIntfImage; Image: TLazIntfImage;
Canvas: TLazCanvas; Canvas: TLazCanvas;
constructor Create; virtual; constructor Create; virtual;
procedure IncInvalidateCount;
function GetFocusedControl: TWinControl; function GetFocusedControl: TWinControl;
function GetFormVirtualHeight(AScreenHeight: Integer): Integer; function GetFormVirtualHeight(AScreenHeight: Integer): Integer;
procedure SanityCheckScrollPos(); procedure SanityCheckScrollPos();
@ -447,13 +452,11 @@ var
lWinControl, lParentControl: TWinControl; lWinControl, lParentControl: TWinControl;
struct : TPaintStruct; struct : TPaintStruct;
lCanvas: TCanvas; lCanvas: TCanvas;
lControlCanvas: TLazCanvas;
lBaseWindowOrg: TPoint; lBaseWindowOrg: TPoint;
begin begin
Result := False; Result := False;
FillChar(struct, SizeOf(TPaintStruct), 0);
struct.hdc := HDC(ACanvas);
lWinControl := ACDWinControl.WinControl; lWinControl := ACDWinControl.WinControl;
{$ifdef VerboseCDWinControl} {$ifdef VerboseCDWinControl}
@ -480,24 +483,42 @@ begin
lWinControl.Width, lWinControl.Height); lWinControl.Width, lWinControl.Height);
ACanvas.ClipRegion := ACDWinControl.Region; ACanvas.ClipRegion := ACDWinControl.Region;
// Special drawing for some native controls lControlCanvas := ACanvas;
if lWinControl is TCustomPanel then {$ifdef CD_BufferControlImages}
if ACDWinControl.InvalidateCount > 0 then
begin begin
// Erase the background of TPanel controls, since it can draw it's own border, but fails to draw it's own background ACDWinControl.UpdateImageAndCanvas();
ACanvas.SaveState; lControlCanvas := ACDWinControl.ControlCanvas;
ACanvas.Brush.FPColor := TColorToFPColor((lWinControl as TCustomPanel).GetRGBColorResolvingParent()); ACDWinControl.InvalidateCount := 0;
ACanvas.Pen.FPColor := ACanvas.Brush.FPColor; {$endif}
ACanvas.Rectangle(Bounds(0, 0, lWinControl.Width, lWinControl.Height));
ACanvas.RestoreState(-1); // 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
lControlCanvas.SaveState;
lControlCanvas.Brush.FPColor := TColorToFPColor((lWinControl as TCustomPanel).GetRGBColorResolvingParent());
lControlCanvas.Pen.FPColor := lControlCanvas.Brush.FPColor;
lControlCanvas.Rectangle(Bounds(0, 0, lWinControl.Width, lWinControl.Height));
lControlCanvas.RestoreState(-1);
end;
// Send the drawing message
{$ifdef VerboseCDWinControl}
DebugLn('[RenderWinControl] before LCLSendPaintMsg');
{$endif}
FillChar(struct, SizeOf(TPaintStruct), 0);
struct.hdc := HDC(lControlCanvas);
LCLSendPaintMsg(lWinControl, struct.hdc, @struct);
{$ifdef VerboseCDWinControl}
DebugLn('[RenderWinControl] after LCLSendPaintMsg');
{$endif}
{$ifdef CD_BufferControlImages}
end; end;
// Send the drawing message // Here we actually blit the control to the form canvas
{$ifdef VerboseCDWinControl} ACanvas.CanvasCopyRect(ACDWinControl.ControlCanvas, 0, 0, 0, 0,
DebugLn('[RenderWinControl] before LCLSendPaintMsg'); lWinControl.Width, lWinControl.Height);
{$endif}
LCLSendPaintMsg(lWinControl, struct.hdc, @struct);
{$ifdef VerboseCDWinControl}
DebugLn('[RenderWinControl] after LCLSendPaintMsg');
{$endif} {$endif}
// Now restore it // Now restore it
@ -865,6 +886,15 @@ begin
if (not DirFound) and (not DirEmpty) then if (not DirFound) and (not DirEmpty) then
AFontPaths.Add(APath); AFontPaths.Add(APath);
end; end;
{ TCDWinControl }
procedure TCDWinControl.UpdateImageAndCanvas;
begin
UpdateControlLazImageAndCanvas(ControlImage, ControlCanvas,
WinControl.Width, WinControl.Height, clfARGB32);
end;
{$endif} {$endif}
{ TCDBitmap } { TCDBitmap }
@ -906,14 +936,26 @@ begin
FProps := TStringList.Create; FProps := TStringList.Create;
//FProps.CaseSensitive:=false; commented as in the qt widgetset //FProps.CaseSensitive:=false; commented as in the qt widgetset
FProps.Sorted:=true; FProps.Sorted:=true;
IncInvalidateCount(); // Always starts needing an invalidate
end; end;
destructor TCDBaseControl.Destroy; destructor TCDBaseControl.Destroy;
begin begin
FProps.Free; FProps.Free;
// Free the Canvas and Image if required
// Dont free for the Form because elsewhere this is taken care of
if ControlCanvas <> nil then ControlCanvas.Free;
if ControlImage <> nil then ControlImage.Free;
inherited Destroy; inherited Destroy;
end; end;
procedure TCDBaseControl.IncInvalidateCount;
begin
Inc(InvalidateCount);
end;
function TCDBaseControl.AdjustCoordinatesForScrolling(AX, AY: Integer): TPoint; function TCDBaseControl.AdjustCoordinatesForScrolling(AX, AY: Integer): TPoint;
begin begin
DebugLn(Format('AX=%d AY=%d ScrollX=%d ScrollY=%d', [AX, AY, ScrollX, ScrollY])); DebugLn(Format('AX=%d AY=%d ScrollX=%d ScrollY=%d', [AX, AY, ScrollX, ScrollY]));
@ -928,11 +970,6 @@ begin
InvalidateCount := 1; InvalidateCount := 1;
end; end;
procedure TCDForm.IncInvalidateCount;
begin
Inc(InvalidateCount);
end;
function TCDForm.GetFocusedControl: TWinControl; function TCDForm.GetFocusedControl: TWinControl;
begin begin
if FocusedIntfControl <> nil then Result := FocusedIntfControl if FocusedIntfControl <> nil then Result := FocusedIntfControl

View File

@ -4681,6 +4681,7 @@ begin
if lHandle is TCDWinControl then if lHandle is TCDWinControl then
begin begin
lControlHandle := TCDWinControl(lHandle); lControlHandle := TCDWinControl(lHandle);
lControlHandle.IncInvalidateCount();
lControl := lControlHandle.WinControl; lControl := lControlHandle.WinControl;
lControl := Forms.GetParentForm(lControl); lControl := Forms.GetParentForm(lControl);
Result := BackendInvalidateRect(lControl.Handle, Rect, BErase); Result := BackendInvalidateRect(lControl.Handle, Rect, BErase);