LazRegions and LCL-CustomDrawn: Expands the support of region creation and combination, now supports the OR operator and more properly handles the simple region to complex region change

git-svn-id: trunk@36604 -
This commit is contained in:
sekelsenmat 2012-04-06 12:23:53 +00:00
parent 53c2240d9f
commit f6b773ed90
3 changed files with 188 additions and 113 deletions

View File

@ -194,7 +194,7 @@ end;
function TQtWidgetSet.ClipboardRegisterFormat(const AMimeType: string): TClipboardFormat;
begin
Result := Clipboard.RegisterFormat(AMimeType);
end;
end;*)
{------------------------------------------------------------------------------
@ -225,106 +225,35 @@ end;
NullRegion
SimpleRegion
ComplexRegion
------------------------------------------------------------------------------}
function TQtWidgetSet.CombineRgn(Dest, Src1, Src2: HRGN; fnCombineMode: Longint): Longint;
function TCDWidgetSet.CombineRgn(Dest, Src1, Src2: HRGN; fnCombineMode: Longint): Longint;
var
RDest,RSrc1,RSrc2: QRegionH;
DestRgn: TLazRegion absolute Dest;
Src1Rgn: TLazRegion absolute Src1;
Src2Rgn: TLazRegion absolute Src2;
begin
result:=ERROR;
Result := ERROR;
if not IsValidGDIObject(Dest) or not IsValidGDIObject(Src1) then
exit
if not IsValidGDIObject(Dest) or not IsValidGDIObject(Src1) then Exit;
if (fnCombineMode<>RGN_COPY) and not IsValidGDIObject(Src2) then Exit;
if fnCombineMode = RGN_COPY then
begin
if Dest <> Src1 then DestRgn.Assign(Src1Rgn);
end;
if Dest = Src1 then
DestRgn.CombineWith(Src2Rgn, fnCombineMode)
else
begin
RDest := TQtRegion(Dest).FHandle;
RSrc1 := TQtRegion(Src1).FHandle;
DestRgn.Assign(Src1Rgn);
DestRgn.CombineWith(Src2Rgn, fnCombineMode);
end;
if (fnCombineMode<>RGN_COPY) and not IsValidGDIObject(Src2) then
exit
else
RSrc2 := TQtRegion(Src2).FHandle;
case fnCombineMode of
RGN_AND:
QRegion_intersected(RSrc1, RDest, RSrc2);
RGN_COPY:
begin
// union of Src1 with a null region
RSrc2 := QRegion_create;
QRegion_united(RSrc1, RDest, RSrc2);
QRegion_destroy(RSrc2);
end;
RGN_DIFF:
QRegion_subtracted(RSrc1, RDest, RSrc2);
RGN_OR:
QRegion_united(RSrc1, RDest, RSrc2);
RGN_XOR:
QRegion_xored(RSrc1, RDest, RSrc2);
end;
if QRegion_isEmpty(RDest) then
Result := NULLREGION
else
begin
if TQtRegion(Dest).IsPolyRegion or (TQtRegion(Dest).numRects > 0) then
Result := COMPLEXREGION
else
Result := SIMPLEREGION;
end;
Result := DestRgn.GetRegionKind();
end;
{------------------------------------------------------------------------------
Method: TQtWidgetSet.CreateCompatibleBitmap
Params: HDC, Width & Height
Returns: HBITMAP
------------------------------------------------------------------------------}
function TQtWidgetSet.CreateCompatibleBitmap(DC: HDC; Width, Height: Integer): HBITMAP;
var
QtDC: TQtDeviceContext;
Format: QImageFormat = QImageFormat_ARGB32;
ADevice: QPaintDeviceH = nil;
ADesktop: QDesktopWidgetH = nil;
begin
{$ifdef VerboseQtWinAPI}
WriteLn('Trace:> [WinAPI CreateCompatibleBitmap]',
' DC:', dbghex(DC),
' Width:', dbgs(Width),
' Height:', dbgs(Height));
{$endif}
Result := 0;
if IsValidDC(DC) then
begin
QtDC := TQtDeviceContext(DC);
case QtDC.getDepth of
1: Format := QImageFormat_Mono;
15, 16: Format := QImageFormat_RGB16;
24: Format := QImageFormat_RGB32;
32: Format := QImageFormat_ARGB32;
end;
end else
begin
ADesktop := QApplication_desktop();
if ADesktop <> nil then
ADevice := QWidget_to_QPaintDevice(ADesktop);
if ADevice <> nil then
begin
case QPaintDevice_depth(ADevice) of
1: Format := QImageFormat_Mono;
15, 16: Format := QImageFormat_RGB16;
24: Format := QImageFormat_RGB32;
32: Format := QImageFormat_ARGB32;
end;
end;
end;
Result := HBitmap(TQtImage.Create(nil, Width, Height, Format));
{$ifdef VerboseQtWinAPI}
WriteLn('Trace:< [WinAPI CreateCompatibleBitmap] Bitmap:', dbghex(Result));
{$endif}
end;*)
{------------------------------------------------------------------------------
Method: CreateBitmap
Params:
@ -500,7 +429,7 @@ begin
Result := HDC(TLazCanvas.Create(nil));
end;
(*{------------------------------------------------------------------------------
{------------------------------------------------------------------------------
Function: CreateEllipticRgn
Params: p1 - X position of the top-left corner
p2 - Y position of the top-left corner
@ -508,16 +437,17 @@ end;
p4 - Y position of the bottom-right corner
Returns: HRGN
------------------------------------------------------------------------------}
function TQtWidgetSet.CreateEllipticRgn(p1, p2, p3, p4: Integer): HRGN;
function TCDWidgetSet.CreateEllipticRgn(p1, p2, p3, p4: Integer): HRGN;
var
QtRegion: TQtRegion;
lRegion: TLazRegion;
begin
{$ifdef VerboseQtWinAPI}
WriteLn('[WinAPI CreateEllipticRgn] ');
{$ifdef VerboseCDRegions}
DebugLn('[WinAPI CreateEllipticRgn] ');
{$endif}
QtRegion := TQtRegion.Create(True, p1, p2, p3, p4, QRegionEllipse);
Result := HRGN(QtRegion);
end;*)
lRegion := TLazRegion.Create;
lRegion.AddEllipse(p1, p2, p3, p4);
Result := HRGN(lRegion);
end;
{------------------------------------------------------------------------------
Function: CreateFontIndirect
@ -5017,17 +4947,18 @@ begin
QCoreApplication_postEvent(Widget.Widget, Event, 1 {high priority});
Result := True;
end;
end;
end;*)
function TQtWidgetSet.PtInRegion(RGN: HRGN; X, Y: Integer): Boolean;
function TCDWidgetSet.PtInRegion(RGN: HRGN; X, Y: Integer): Boolean;
var
lRegion: TLazRegion absolute RGN;
begin
Result := False;
if not IsValidGDIObject(RGN) then
exit;
if not IsValidGDIObject(RGN) then Exit;
Result := TQtRegion(RGN).containsPoint(X, Y);
end;*)
Result := lRegion.IsPointInRegion(X, Y);
end;
{------------------------------------------------------------------------------
Function: Rectangle

View File

@ -52,15 +52,15 @@ function ClipboardGetFormats(ClipboardType: TClipboardType;
function ClipboardGetOwnerShip(ClipboardType: TClipboardType;
OnRequestProc: TClipboardRequestEvent; FormatCount: integer;
Formats: PClipboardFormat): boolean; override;
function ClipboardRegisterFormat(const AMimeType: string): TClipboardFormat; override;
function ClipboardRegisterFormat(const AMimeType: string): TClipboardFormat; override;*)
function CombineRgn(Dest, Src1, Src2: HRGN; fnCombineMode: Longint): Longint; override;*)
function CombineRgn(Dest, Src1, Src2: HRGN; fnCombineMode: Longint): Longint; override;
function CreateBitmap(Width, Height: Integer; Planes, BitCount: Longint; BitmapBits: Pointer): HBITMAP; override;
function CreateBrushIndirect(const LogBrush: TLogBrush): HBRUSH; override;
(*function CreateCaret(Handle : HWND; Bitmap : hBitmap; Width, Height : Integer) : Boolean; override;*)
function CreateCompatibleBitmap(DC: HDC; Width, Height: Integer): HBITMAP; override;
function CreateCompatibleDC(DC: HDC): HDC; override;
//function CreateEllipticRgn(p1, p2, p3, p4: Integer): HRGN; override;
function CreateEllipticRgn(p1, p2, p3, p4: Integer): HRGN; override;
function CreateFontIndirect(const LogFont: TLogFont): HFONT; override;
function CreateFontIndirectEx(const LogFont: TLogFont; const LongFontName: string): HFONT; override;
{$ifndef CD_UseNativeText}
@ -181,9 +181,9 @@ function PeekMessage(var lpMsg : TMsg; Handle : HWND; wMsgFilterMin, wMsgFilterM
function PolyBezier(DC: HDC; Points: PPoint; NumPts: Integer; Filled, Continuous: boolean): boolean; override;
function Polygon(DC: HDC; Points: PPoint; NumPts: Integer; Winding: boolean): boolean; override;
function Polyline(DC: HDC; Points: PPoint; NumPts: Integer): boolean; override;
(*function PostMessage(Handle: HWND; Msg: Cardinal; wParam: WParam; lParam: LParam): Boolean; override;
(*function PostMessage(Handle: HWND; Msg: Cardinal; wParam: WParam; lParam: LParam): Boolean; override;*)
function PtInRegion(RGN: HRGN; X, Y: Integer) : Boolean; override;
*)
function Rectangle(DC: HDC; X1, Y1, X2, Y2: Integer): Boolean; override;
function RectVisible(dc : hdc; const ARect: TRect) : Boolean; override;
(*function RedrawWindow(Wnd: HWND; lprcUpdate: PRECT; hrgnUpdate: HRGN; flags: UINT): Boolean; override;

View File

@ -10,7 +10,7 @@ unit lazregions;
interface
uses
Classes, SysUtils, fpcanvas;
Classes, SysUtils, LCLType, fpcanvas;
type
TLazRegionFillMode = (rfmOddEven, rfmWinding);
@ -21,6 +21,7 @@ type
TLazRegionPart = class
public
function GetBoundingRect: TRect; virtual;
function IsPointInPart(AX, AY: Integer): Boolean; virtual;
end;
@ -41,6 +42,14 @@ type
function IsPointInPart(AX, AY: Integer): Boolean; override;
end;
{ TLazRegionEllipse }
TLazRegionEllipse = class(TLazRegionPart)
public
X1, Y1, X2, Y2: Integer;
function IsPointInPart(AX, AY: Integer): Boolean; override;
end;
{$if defined(ver2_4) or defined(ver2_5) or defined(ver2_6)}
TFPCustomRegion = class
function GetBoundingRect: TRect; virtual; abstract;
@ -59,9 +68,21 @@ type
Rect: TRect; // Used for performance increase when IsSimpleRectRegion is on
constructor Create; virtual;
destructor Destroy; override;
// Management operations
procedure Assign(ASrcRegion: TLazRegion);
procedure Clear;
procedure CombineWith(ASrcRegion: TLazRegion; AOperation: Longint);
function GetRegionKind(): Longint;
function IsSimpleRectEmpty: Boolean;
// Setting the contents
procedure AddPart(APart: TLazRegionPart);
procedure AddRectangle(ARect: TRect);
procedure AddPolygon(var APoints: TPointArray; AFillMode: TLazRegionFillMode);
procedure AddEllipse(AX1, AY1, AX2, AY2: Integer);
procedure SetAsSimpleRectRegion(ARect: TRect);
procedure AddPartsFromRegion(ASrcRegion: TLazRegion);
procedure DoChangeToComplexRegion;
// Overrides of TFPCustomRegion information query routines
function GetBoundingRect: TRect; override;
function IsPointInRegion(AX, AY: Integer): Boolean; override;
end;
@ -137,8 +158,31 @@ begin
Result := inside <> 0;
end;
{ TLazRegionEllipse }
{
The equation of the inner area of an axis aligned ellipse:
(X/a)^2 + (Y/b)^2 <= 1
}
function TLazRegionEllipse.IsPointInPart(AX, AY: Integer): Boolean;
var
a, b: Integer;
begin
a := X2 - X1;
b := Y2 - Y1;
if (a < 0) or (b < 0) then Exit(False);
Result := Sqr(AX/a) + Sqr(AY/b) <= 1;
end;
{ TLazRegionPart }
function TLazRegionPart.GetBoundingRect: TRect;
begin
Result := Bounds(0, 0, 0, 0);
end;
function TLazRegionPart.IsPointInPart(AX, AY: Integer): Boolean;
begin
Result := False;
@ -174,13 +218,71 @@ begin
inherited Destroy;
end;
procedure TLazRegion.Assign(ASrcRegion: TLazRegion);
begin
Clear;
AddPartsFromRegion(ASrcRegion);
end;
procedure TLazRegion.Clear;
var
i: Integer;
begin
// Free all items
for i := 0 to Parts.Count - 1 do
TLazRegionPart(Parts.Items[i]).Free;
Parts.Clear;
IsSimpleRectRegion := True;
Rect := Bounds(0, 0, 0, 0);
end;
procedure TLazRegion.CombineWith(ASrcRegion: TLazRegion; AOperation: Longint);
begin
case AOperation of
{RGN_AND:
QRegion_intersected(RSrc1, RDest, RSrc2);}
RGN_COPY:
begin
Assign(ASrcRegion);
end;
{ RGN_DIFF:
QRegion_subtracted(RSrc1, RDest, RSrc2);}
RGN_OR:
AddPartsFromRegion(ASrcRegion);
{RGN_XOR:
QRegion_xored(RSrc1, RDest, RSrc2);}
end;
end;
function TLazRegion.GetRegionKind: Longint;
begin
if not IsSimpleRectRegion then
Result := COMPLEXREGION
else if IsSimpleRectEmpty() then
Result := NULLREGION
else
Result := SIMPLEREGION;
end;
function TLazRegion.IsSimpleRectEmpty: Boolean;
begin
Result := (Rect.Bottom - Rect.Top <= 0) or (Rect.Right - Rect.Left <= 0);
end;
procedure TLazRegion.AddPart(APart: TLazRegionPart);
begin
Parts.Add(APart);
DoChangeToComplexRegion();
end;
procedure TLazRegion.AddRectangle(ARect: TRect);
var
lNewRect: TLazRegionRect;
begin
lNewRect := TLazRegionRect.Create;
lNewRect.Rect := ARect;
Parts.Add(lNewRect);
AddPart(lNewRect);
end;
procedure TLazRegion.AddPolygon(var APoints: TPointArray;
@ -191,11 +293,53 @@ begin
lNewPolygon := TLazRegionPolygon.Create;
lNewPolygon.Points := APoints;
lNewPolygon.FillMode := AFillMode;
Parts.Add(lNewPolygon);
AddPart(lNewPolygon);
end;
procedure TLazRegion.AddEllipse(AX1, AY1, AX2, AY2: Integer);
var
lNewEllipse: TLazRegionEllipse;
begin
lNewEllipse := TLazRegionEllipse.Create;
lNewEllipse.X1 := AX1;
lNewEllipse.Y1 := AY1;
lNewEllipse.X2 := AX2;
lNewEllipse.Y2 := AY2;
AddPart(lNewEllipse);
end;
procedure TLazRegion.AddPartsFromRegion(ASrcRegion: TLazRegion);
var
i: Integer;
begin
if ASrcRegion.IsSimpleRectRegion then
begin
if IsSimpleRectRegion and IsSimpleRectEmpty() then
Rect := ASrcRegion.Rect
else
AddRectangle(ASrcRegion.Rect);
end
else
begin
for i := 0 to ASrcRegion.Parts.Count-1 do
begin
Parts.Add(ASrcRegion.Parts.Items[i]);
end;
IsSimpleRectRegion := False;
end;
end;
procedure TLazRegion.DoChangeToComplexRegion;
begin
if IsSimpleRectRegion and (not IsSimpleRectEmpty()) then
AddRectangle(Rect);
IsSimpleRectRegion := False;
end;
procedure TLazRegion.SetAsSimpleRectRegion(ARect: TRect);
begin
Clear;
IsSimpleRectRegion := True;
Rect := ARect;
end;