lazarus/lcl/interfaces/customdrawn/customdrawnproc.pas

267 lines
7.6 KiB
ObjectPascal

unit customdrawnproc;
{$mode objfpc}{$H+}
interface
uses
// rtl+ftl
Types, Classes, SysUtils,
fpimage, fpcanvas,
// Custom Drawn Canvas
IntfGraphics, lazcanvas, lazregions,
//
GraphType, Controls, LCLMessageGlue, WSControls, LCLType, LCLProc,
Forms;
type
TUpdateLazImageFormat = (
clfRGB16_R5G6B5,
clfRGB24, clfRGB24UpsideDown, clfBGR24, clfBGRA32);
TCDWinControl = class
public
Region: TLazRegionWithChilds;
WinControl: TWinControl;
//CDControl: TCDControl;
end;
TCDNonNativeForm = class
public
LCLForm: TCustomForm;
Children: TFPList; // of TCDWinControl;
// painting objects
Image: TLazIntfImage;
Canvas: TLazCanvas;
end;
// Routines for non-native form
procedure InitNonNativeForms();
function GetCurrentForm(): TCDNonNativeForm;
function AddNewForm(AForm: TCustomForm): TCDNonNativeForm;
procedure ShowForm(ACDForm: TCDNonNativeForm);
procedure HideForm(ACDForm: TCDNonNativeForm);
// Routines for non-native wincontrol
procedure UpdateControlLazImageAndCanvas(var AImage: TLazIntfImage;
var ACanvas: TLazCanvas; AWidth, AHeight: Integer; AFormat: TUpdateLazImageFormat;
AData: Pointer = nil);
procedure RenderChildWinControls(var AImage: TLazIntfImage;
var ACanvas: TLazCanvas; ACDControlsList: TFPList);
//procedure RenderWinControl(var AImage: TLazIntfImage;
// var ACanvas: TLazCanvas; ACDControlsList: TFPList);
function FindControlWhichReceivedEvent(AForm: TCustomForm;
AControlsList: TFPList; AX, AY: Integer): TWinControl;
// Other routines
function DateTimeToMilliseconds(aDateTime: TDateTime): Int64;
function IsValidDC(ADC: HDC): Boolean;
function IsValidGDIObject(AGDIObj: HGDIOBJ): Boolean;
implementation
// List with the Z-order of non-native forms, index=0 is the bottom-most form
var
NonNativeForms: TFPList = nil;
procedure InitNonNativeForms();
begin
if NonNativeForms <> nil then Exit;
NonNativeForms := TFPList.Create;
end;
function GetCurrentForm(): TCDNonNativeForm;
var
lCount: Integer;
begin
{$IFDEF VerboseWinAPI}
DebugLn('GetCurrentForm');
{$ENDIF}
InitNonNativeForms();
lCount := NonNativeForms.Count;
if lCount = 0 then Result := nil
else Result := TCDNonNativeForm(NonNativeForms.Items[lCount-1]);
end;
function AddNewForm(AForm: TCustomForm): TCDNonNativeForm;
var
lFormInfo: TCDNonNativeForm;
begin
{$IFDEF VerboseWinAPI}
DebugLn('AddNewForm');
{$ENDIF}
InitNonNativeForms();
lFormInfo := TCDNonNativeForm.Create;
lFormInfo.LCLForm := AForm;
lFormInfo.Children := TFPList.Create;
NonNativeForms.Insert(0, lFormInfo);
end;
procedure ShowForm(ACDForm: TCDNonNativeForm);
var
lCount, lCurIndex: Integer;
begin
{$IFDEF VerboseWinAPI}
DebugLn('ShowForm');
{$ENDIF}
InitNonNativeForms();
lCount := NonNativeForms.Count;
lCurIndex := NonNativeForms.IndexOf(ACDForm);
NonNativeForms.Move(lCurIndex, lCount-1);
end;
procedure HideForm(ACDForm: TCDNonNativeForm);
var
lCount, lCurIndex: Integer;
begin
InitNonNativeForms();
lCount := NonNativeForms.Count;
lCurIndex := NonNativeForms.IndexOf(ACDForm);
NonNativeForms.Move(lCurIndex, 0);
end;
procedure UpdateControlLazImageAndCanvas(var AImage: TLazIntfImage;
var ACanvas: TLazCanvas; AWidth, AHeight: Integer; AFormat: TUpdateLazImageFormat;
AData: Pointer = nil);
var
lRawImage: TRawImage;
lPixelSize: Byte;
begin
{$IFDEF VerboseWinAPI}
DebugLn(Format(':>[UpdateControlLazImageAndCanvas] Input Image: %x Canvas: %x',
[PtrInt(AImage), PtrInt(ACanvas)]));
{$ENDIF}
// Check if the image needs update
if (AImage = nil) or (AWidth <> AImage.Width) or (AHeight <> AImage.Height) then
begin
if (AImage <> nil) then AImage.Free;
lRawImage.Init;
case AFormat of
clfRGB16_R5G6B5: lRawImage.Description.Init_BPP16_R5G6B5(AWidth, AHeight);
clfRGB24: lRawImage.Description.Init_BPP24_R8G8B8_BIO_TTB(AWidth, AHeight);
clfRGB24UpsideDown: lRawImage.Description.Init_BPP24_R8G8B8_BIO_TTB_UpsideDown(AWidth, AHeight);
clfBGR24: lRawImage.Description.Init_BPP24_B8G8R8_BIO_TTB(AWidth, AHeight);
clfBGRA32: lRawImage.Description.Init_BPP32_B8G8R8A8_BIO_TTB(AWidth, AHeight);
end;
// Now connect the pixel buffer or create one
if AData = nil then lRawImage.CreateData(True)
else
begin
case AFormat of
clfRGB16_R5G6B5: lPixelSize := 2;
clfRGB24: lPixelSize := 3;
clfRGB24UpsideDown: lPixelSize := 3;
clfBGR24: lPixelSize := 3;
clfBGRA32: lPixelSize := 4;
end;
lRawImage.Data := AData;
lRawImage.DataSize := AWidth * lPixelSize * AHeight;
end;
AImage := TLazIntfImage.Create(AWidth, AHeight);
AImage.SetRawImage(lRawImage);
if (ACanvas <> nil) then ACanvas.Free;
ACanvas := TLazCanvas.Create(AImage);
end;
{$IFDEF VerboseWinAPI}
DebugLn(Format(':<[UpdateControlLazImageAndCanvas] Output Image: %x Canvas: %x',
[PtrInt(AImage), PtrInt(ACanvas)]));
{$ENDIF}
end;
procedure RenderChildWinControls(var AImage: TLazIntfImage;
var ACanvas: TLazCanvas; ACDControlsList: TFPList);
var
i: Integer;
lCDWinControl: TCDWinControl;
lWinControl: TWinControl;
struct : TPaintStruct;
begin
{$ifdef VerboseCDWinControl}
DebugLn(Format('[RenderChildWinControls] ACanvas=%x ACDControlsList=%x',
[PtrInt(ACanvas), PtrInt(ACDControlsList)]));
{$endif}
FillChar(struct, SizeOf(TPaintStruct), 0);
struct.hdc := HDC(ACanvas);
for i := 0 to ACDControlsList.Count-1 do
begin
lCDWinControl := TCDWinControl(ACDControlsList.Items[i]);
lWinControl := lCDWinControl.WinControl;
{$ifdef VerboseCDWinControl}
DebugLn(Format('[RenderChildWinControls] i=%d lWinControl=%x Left=%d'
+ ' Top=%d Width=%d Height=%d', [i, PtrInt(lWinControl),
lWinControl.Left, lWinControl.Top, lWinControl.Width, lWinControl.Height]));
{$endif}
if lWinControl.Visible = False then Continue;
// Prepare the clippping
ACanvas.Clipping := True;
lCDWinControl.Region.Rect := Bounds(lWinControl.Left, lWinControl.Top, lWinControl.Width, lWinControl.Height);
ACanvas.ClipRegion := lCDWinControl.Region;
ACanvas.UseRegionClipping := True;
ACanvas.WindowOrg := Point(lWinControl.Left, lWinControl.Top);
{$ifdef VerboseCDWinControl}
DebugLn(Format('[RenderChildWinControls] i=%d before LCLSendPaintMsg', [i]));
{$endif}
LCLSendPaintMsg(lCDWinControl.WinControl, struct.hdc, @struct);
end;
ACanvas.Clipping := False;
ACanvas.WindowOrg := Point(0, 0);
end;
function FindControlWhichReceivedEvent(AForm: TCustomForm;
AControlsList: TFPList; AX, AY: Integer): TWinControl;
var
i: Integer;
lRegionOfEvent: TLazRegionWithChilds;
lCurCDControl: TCDWinControl;
begin
Result := AForm;
for i := 0 to AControlsList.Count-1 do
begin
lCurCDControl := TCDWinControl(AControlsList.Items[i]);
if lCurCDControl.Region = nil then Continue;
lRegionOfEvent := lCurCDControl.Region.IsPointInRegion(AX, AY);
if lRegionOfEvent <> nil then
begin
if lRegionOfEvent.UserData = nil then
raise Exception.Create('[FindControlWhichReceivedEvent] Malformed tree of regions');
Result := TWinControl(lRegionOfEvent.UserData);
Exit;
end;
end;
end;
function DateTimeToMilliseconds(aDateTime: TDateTime): Int64;
var
TimeStamp: TTimeStamp;
begin
{Call DateTimeToTimeStamp to convert DateTime to TimeStamp:}
TimeStamp:= DateTimeToTimeStamp (aDateTime);
{Multiply and add to complete the conversion:}
Result:= TimeStamp.Time;
end;
function IsValidDC(ADC: HDC): Boolean;
begin
Result := ADC <> 0;
end;
function IsValidGDIObject(AGDIObj: HGDIOBJ): Boolean;
begin
Result := AGDIObj <> 0;
end;
end.