mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-09-06 17:00:38 +02:00
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:
parent
53c2240d9f
commit
f6b773ed90
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user