2964 lines
108 KiB
ObjectPascal
Raw Permalink Blame History

unit SpkGUITools;
{$mode ObjFpc}
{$H+}
{$DEFINE SPKGUITOOLS}
{.$define EnhancedRecordSupport}
//the fpcbugworkaround is only necessary when using inline for DrawRoundRect
{.$define FpcBugWorkAround}
interface
{$MESSAGE HINT 'Every rect in this module are exact rectanges (not like in WINAPI without right and bottom)'}
uses
LCLType, LCLVersion, Graphics, SysUtils, Classes, Controls, StdCtrls,
SpkGraphTools, SpkMath;
type
TCornerPos = (cpLeftTop, cpRightTop, cpLeftBottom, cpRightBottom);
TCornerKind = (cpRound, cpNormal);
TBackgroundKind = (bkSolid, bkVerticalGradient, bkHorizontalGradient,
bkConcave);
TSpkButtonState = (bsIdle,
bsBtnHottrack, bsBtnPressed, bsDropdownHottrack, bsDropdownPressed);
TSpkCheckboxStyle = (cbsCheckbox, cbsRadioButton);
// TSpkCheckboxState = (cbsIdle, cbsHotTrack, cbsPressed, cbsDisabled);
TGUITools = class(TObject)
protected
class procedure FillGradientRectangle(ACanvas: TCanvas; Rect: T2DIntRect;
ColorFrom, ColorTo: TColor; GradientKind: TBackgroundKind);
class procedure SaveClipRgn(DC: HDC; out OrgRgnExists: boolean; out OrgRgn: HRGN);
class procedure RestoreClipRgn(DC: HDC; OrgRgnExists: boolean; var OrgRgn: HRGN);
public
// *** Lines ***
// Performance:
// w/ClipRect: Bitmap is faster (2x)
// wo/ClipRect: Canvas is faster (a little)
class procedure DrawHLine(ABitmap : TBitmap;
x1, x2 : integer;
y : integer;
Color : TColor); overload;
class procedure DrawHLine(ABitmap : TBitmap;
x1, x2 : integer;
y : integer;
Color : TColor;
ClipRect : T2DIntRect); overload;
class procedure DrawHLine(ACanvas : TCanvas;
x1, x2 : integer;
y : integer;
Color : TColor); overload;
class procedure DrawHLine(ACanvas : TCanvas;
x1, x2 : integer;
y : integer;
Color : TColor;
ClipRect : T2DIntRect); overload;
// Performance:
// w/ClipRect: Bitmap is faster (2x)
// wo/ClipRect: Canvas is faster (a little)
class procedure DrawVLine(ABitmap : TBitmap;
x : integer;
y1, y2 : integer;
Color : TColor); overload;
class procedure DrawVLine(ABitmap : TBitmap;
x : integer;
y1, y2 : integer;
Color : TColor;
ClipRect : T2DIntRect); overload;
class procedure DrawVLine(ACanvas : TCanvas;
x : integer;
y1, y2 : integer;
Color : TColor); overload;
class procedure DrawVLine(ACanvas : TCanvas;
x : integer;
y1, y2 : integer;
Color : TColor;
ClipRect : T2DIntRect); overload;
// *** Background and frame tools ***
// Performance:
// w/ClipRect: Bitmap is faster (extremely)
// wo/ClipRect: Bitmap is faster (extremely)
class procedure DrawAARoundCorner(ABitmap : TBitmap;
Point : T2DIntVector;
Radius : integer;
CornerPos : TCornerPos;
Color : TColor); overload;
class procedure DrawAARoundCorner(ABitmap : TBitmap;
Point : T2DIntVector;
Radius : integer;
CornerPos : TCornerPos;
Color : TColor;
ClipRect : T2DIntRect); overload;
class procedure DrawAARoundCorner(ACanvas : TCanvas;
Point : T2DIntVector;
Radius : integer;
CornerPos : TCornerPos;
Color : TColor); overload;
class procedure DrawAARoundCorner(ACanvas : TCanvas;
Point : T2DIntVector;
Radius : integer;
CornerPos : TCornerPos;
Color : TColor;
ClipRect : T2DIntRect); overload;
// Performance:
// w/ClipRect: Bitmap is faster (extremely)
// wo/ClipRect: Bitmap is faster (extremely)
class procedure DrawAARoundFrame(ABitmap : TBitmap;
Rect : T2DIntRect;
Radius : integer;
Color : TColor); overload;
class procedure DrawAARoundFrame(ABitmap : TBitmap;
Rect : T2DIntRect;
Radius : integer;
Color : TColor;
ClipRect : T2DIntRect); overload;
class procedure DrawAARoundFrame(ACanvas : TCanvas;
Rect : T2DIntRect;
Radius : integer;
Color : TColor); overload;
class procedure DrawAARoundFrame(ACanvas : TCanvas;
Rect : T2DIntRect;
Radius : integer;
Color : TColor;
ClipRect : T2DIntRect); overload;
class procedure RenderBackground(ABuffer : TBitmap;
Rect : T2DIntRect;
Color1, Color2 : TColor;
BackgroundKind : TBackgroundKind);
class procedure CopyRoundCorner(ABuffer : TBitmap;
ABitmap : TBitmap;
SrcPoint : T2DIntVector;
DstPoint : T2DIntVector;
Radius : integer;
CornerPos : TCornerPos;
Convex : boolean = true); overload;
class procedure CopyRoundCorner(ABuffer : TBitmap;
ABitmap : TBitmap;
SrcPoint : T2DIntVector;
DstPoint : T2DIntVector;
Radius : integer;
CornerPos : TCornerPos;
ClipRect : T2DIntRect;
Convex : boolean = true); overload;
class procedure CopyCorner(ABuffer : TBitmap;
ABitmap: TBitmap;
SrcPoint : T2DIntVector;
DstPoint: T2DIntVector;
Radius: integer); overload; inline;
class procedure CopyCorner(ABuffer : TBitmap;
ABitmap: TBitmap;
SrcPoint : T2DIntVector;
DstPoint: T2DIntVector;
Radius: integer;
ClipRect : T2DIntRect); overload; inline;
class procedure CopyRectangle(ABuffer : TBitmap;
ABitmap: TBitmap;
SrcPoint : T2DIntVector;
DstPoint: T2DIntVector;
Width: integer;
Height : integer); overload;
class procedure CopyRectangle(ABuffer : TBitmap;
ABitmap : TBitmap;
SrcPoint : T2DIntVector;
DstPoint : T2DIntVector;
Width : integer;
Height : integer;
ClipRect : T2DIntRect); overload;
class procedure CopyMaskRectangle(ABuffer : TBitmap;
AMask : TBitmap;
ABitmap : TBitmap;
SrcPoint : T2DIntVector;
DstPoint : T2DIntVector;
Width : integer;
Height : integer); overload;
class procedure CopyMaskRectangle(ABuffer : TBitmap;
AMask : TBitmap;
ABitmap : TBitmap;
SrcPoint : T2DIntVector;
DstPoint : T2DIntVector;
Width : integer;
Height : integer;
ClipRect : T2DIntRect); overload;
// Performance (RenderBackground + CopyRoundRect vs DrawRoundRect):
// w/ClipRect : Bitmap faster for smaller radiuses, Canvas faster for larger
// wo/ClipRect : Bitmap faster for smaller radiuses, Canvas faster for larger
class procedure CopyRoundRect(ABuffer : TBitmap;
ABitmap : TBitmap;
SrcPoint : T2DIntVector;
DstPoint : T2DIntVector;
Width, Height : integer;
Radius : integer;
LeftTopRound : boolean = true;
RightTopRound : boolean = true;
LeftBottomRound : boolean = true;
RightBottomRound : boolean = true); overload;
class procedure CopyRoundRect(ABuffer : TBitmap;
ABitmap : TBitmap;
SrcPoint : T2DIntVector;
DstPoint : T2DIntVector;
Width, Height : integer;
Radius : integer;
ClipRect : T2DIntRect;
LeftTopRound : boolean = true;
RightTopRound : boolean = true;
LeftBottomRound : boolean = true;
RightBottomRound : boolean = true); overload;
class procedure DrawRoundRect(ACanvas : TCanvas;
Rect : T2DIntRect;
Radius : integer;
ColorFrom : TColor;
ColorTo : TColor;
GradientKind : TBackgroundKind;
LeftTopRound : boolean = true;
RightTopRound : boolean = true;
LeftBottomRound : boolean = true;
RightBottomRound : boolean = true); overload;
class procedure DrawRoundRect(ACanvas : TCanvas;
Rect : T2DIntRect;
Radius : integer;
ColorFrom : TColor;
ColorTo : TColor;
GradientKind : TBackgroundKind;
ClipRect : T2DIntRect;
LeftTopRound : boolean = true;
RightTopRound : boolean = true;
LeftBottomRound : boolean = true;
RightBottomRound : boolean = true); overload;
class procedure DrawRegion(ACanvas : TCanvas;
Region : HRGN;
Rect : T2DIntRect;
ColorFrom : TColor;
ColorTo : TColor;
GradientKind : TBackgroundKind); overload;
class procedure DrawRegion(ACanvas : TCanvas;
Region : HRGN;
Rect : T2DIntRect;
ColorFrom : TColor;
ColorTo : TColor;
GradientKind : TBackgroundKind;
ClipRect : T2DIntRect); overload;
// Imagelist tools
class procedure DrawImage(ABitmap : TBitmap;
Imagelist : TImageList;
ImageIndex : integer;
Point : T2DIntVector); overload; inline;
class procedure DrawImage(ABitmap : TBitmap;
Imagelist : TImageList;
ImageIndex : integer;
Point : T2DIntVector;
ClipRect : T2DIntRect); overload; inline;
class procedure DrawImage(ACanvas : TCanvas;
Imagelist : TImageList;
ImageIndex : integer;
Point : T2DIntVector); overload; inline;
class procedure DrawImage(ACanvas : TCanvas;
Imagelist : TImageList;
ImageIndex : integer;
Point : T2DIntVector;
ClipRect : T2DIntRect); overload;
class procedure DrawImage(ACanvas: TCanvas;
Imagelist: TImageList;
ImageIndex: integer;
Point : T2DIntVector;
ClipRect: T2DIntRect;
AImageWidthAt96PPI, ATargetPPI: Integer;
ACanvasFactor: Double); overload;
class procedure DrawDisabledImage(ABitmap : TBitmap;
Imagelist : TImageList;
ImageIndex : integer;
Point : T2DIntVector); overload; inline;
class procedure DrawDisabledImage(ABitmap : TBitmap;
Imagelist : TImageList;
ImageIndex : integer;
Point : T2DIntVector;
ClipRect : T2DIntRect); overload; inline;
class procedure DrawDisabledImage(ACanvas : TCanvas;
Imagelist : TImageList;
ImageIndex : integer;
Point : T2DIntVector); overload;
class procedure DrawDisabledImage(ACanvas : TCanvas;
Imagelist : TImageList;
ImageIndex : integer;
Point : T2DIntVector;
ClipRect : T2DIntRect); overload; inline;
// Checkbox
class procedure DrawCheckbox(ACanvas: TCanvas;
x,y: Integer;
AState: TCheckboxState;
AButtonState: TSpkButtonState;
AStyle: TSpkCheckboxStyle); overload;
class procedure DrawCheckbox(ACanvas: TCanvas;
x,y: Integer;
AState: TCheckboxState;
AButtonState: TSpkButtonState;
AStyle: TSpkCheckboxStyle;
ClipRect: T2DIntRect); overload;
// Text tools
class procedure DrawText(ABitmap : TBitmap;
x, y : integer;
const AText : string;
TextColor: TColor); overload;
class procedure DrawText(ABitmap : TBitmap;
x, y : integer;
const AText : string;
TextColor : TColor;
ClipRect: T2DIntRect); overload;
class procedure DrawMarkedText(ACanvas : TCanvas;
x, y : integer;
const AText, AMarkPhrase : string;
TextColor : TColor;
CaseSensitive : boolean = false); overload;
class procedure DrawMarkedText(ACanvas : TCanvas;
x, y : integer;
const AText, AMarkPhrase : string;
TextColor : TColor;
ClipRect : T2DIntRect;
CaseSensitive : boolean = false); overload;
class procedure DrawText(ACanvas : TCanvas;
x, y : integer;
const AText : string;
TextColor : TColor); overload;
class procedure DrawText(ACanvas : TCanvas;
x, y : integer;
const AText : string;
TextColor : TColor;
ClipRect : T2DIntRect); overload;
class procedure DrawFitWText(ABitmap : TBitmap;
x1, x2 : integer;
y : integer;
const AText : string;
TextColor : TColor;
Align : TAlignment); overload;
class procedure DrawFitWText(ACanvas : TCanvas;
x1, x2 : integer;
y : integer;
const AText : string;
TextColor : TColor;
Align : TAlignment); overload;
class procedure DrawOutlinedText(ABitmap : TBitmap;
x, y : integer;
const AText : string;
TextColor : TColor;
OutlineColor : TColor); overload;
class procedure DrawOutlinedText(ABitmap : TBitmap;
x, y : integer;
const AText : string;
TextColor : TColor;
OutlineColor : TColor;
ClipRect : T2DIntRect); overload;
class procedure DrawOutlinedText(ACanvas : TCanvas;
x, y : integer;
const AText : string;
TextColor : TColor;
OutlineColor : TColor); overload;
class procedure DrawOutlinedText(ACanvas : TCanvas;
x, y : integer;
const AText : string;
TextColor : TColor;
OutlineColor : TColor;
ClipRect : T2DIntRect); overload;
class procedure DrawFitWOutlinedText(ABitmap: TBitmap;
x1, x2 : integer;
y: integer;
const AText: string;
TextColor,
OutlineColor: TColor;
Align: TAlignment); overload;
class procedure DrawFitWOutlinedText(ACanvas: TCanvas;
x1, x2 : integer;
y: integer;
const AText: string;
TextColor,
OutlineColor: TColor;
Align: TAlignment); overload;
end;
implementation
uses
Types, LCLIntf, IntfGraphics, Themes;
{ TSpkGUITools }
class procedure TGUITools.CopyRoundCorner(ABuffer, ABitmap: TBitmap; SrcPoint,
DstPoint: T2DIntVector; Radius: integer; CornerPos: TCornerPos;
ClipRect: T2DIntRect; Convex: boolean);
var
BufferRect, BitmapRect, TempRect: T2DIntRect;
OrgSrcRect, UnClippedDstRect, OrgDstRect: T2DIntRect;
SrcRect: T2DIntRect;
Offset: T2DIntVector;
Center: T2DIntVector;
y: Integer;
SrcLine: Pointer;
DstLine: Pointer;
SrcPtr, DstPtr : PByte;
x: Integer;
Dist : double;
SrcImg, DestImg: TLazIntfImage;
begin
if (ABuffer.PixelFormat <> pf24Bit) or (ABitmap.PixelFormat <> pf24Bit) then
raise Exception.Create('TSpkGUITools.CopyRoundCorner: Only 24-bit bitmaps are accepted!');
// Validation
if Radius < 1 then
exit;
if (ABuffer.Width = 0) or (ABuffer.Height = 0) or
(ABitmap.Width = 0) or (ABitmap.Height = 0) then exit;
//todo minimize use of temps here
{$ifdef EnhancedRecordSupport}
BufferRect := T2DIntRect.Create(0, 0, ABuffer.width-1, ABuffer.height-1);
if not BufferRect.IntersectsWith(
T2DIntRect.Create(SrcPoint.x, SrcPoint.y, SrcPoint.x+Radius-1, SrcPoint.y+Radius-1),
OrgSrcRect
)
then
exit;
{$else}
BufferRect.Create(0, 0, ABuffer.Width-1, ABuffer.Height-1);
TempRect.Create(SrcPoint.x, SrcPoint.y, SrcPoint.x+Radius-1, SrcPoint.y+Radius-1);
if not BufferRect.IntersectsWith(TempRect, OrgSrcRect) then
exit;
{$endif}
{$ifdef EnhancedRecordSupport}
BitmapRect := T2DIntRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not BitmapRect.IntersectsWith(
T2DIntRect.Create(DstPoint.x, DstPoint.y, DstPoint.x+Radius-1, DstPoint.y+Radius-1),
UnClippedDstRect
)
then
exit;
{$else}
BitmapRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
//todo: calling create twice
TempRect.Create(DstPoint.x, DstPoint.y, DstPoint.x+Radius-1, DstPoint.y+Radius-1);
if not(BitmapRect.IntersectsWith(TempRect, UnClippedDstRect)) then
exit;
{$endif}
if not(ClipRect.IntersectsWith(UnClippedDstRect, OrgDstRect)) then
exit;
Offset := DstPoint - SrcPoint;
if not(OrgSrcRect.IntersectsWith(OrgDstRect - Offset, SrcRect)) then
exit;
// We position the center of the arc
{$ifdef EnhancedRecordSupport}
case CornerPos of
cpLeftTop:
Center := T2DIntVector.Create(SrcPoint.x + Radius - 1, SrcPoint.y + Radius - 1);
cpRightTop:
Center := T2DIntVector.Create(SrcPoint.x, SrcPoint.y + Radius - 1);
cpLeftBottom:
Center := T2DIntVector.Create(SrcPoint.x + Radius - 1, SrcPoint.y);
cpRightBottom:
Center := T2DIntVector.Create(SrcPoint.x, SrcPoint.y);
end;
{$else}
case CornerPos of
cpLeftTop:
Center.Create(SrcPoint.x + Radius - 1, SrcPoint.y + Radius - 1);
cpRightTop:
Center.Create(SrcPoint.x, SrcPoint.y + Radius - 1);
cpLeftBottom:
Center.Create(SrcPoint.x + Radius - 1, SrcPoint.y);
cpRightBottom:
Center.Create(SrcPoint.x, SrcPoint.y);
end;
{$endif}
// Is there anything to be processed?
if Convex then
begin
//todo: remove the check since is not necessary
if (SrcRect.Left <= SrcRect.right) and (SrcRect.Top <= SrcRect.Bottom) then
begin
SrcImg := ABuffer.CreateIntfImage;
DestImg := ABitmap.CreateIntfImage;
for y := SrcRect.Top to SrcRect.Bottom do
begin
SrcLine := SrcImg.GetDataLineStart(y);
DstLine := DestImg.GetDataLineStart(y+Offset.y);
SrcPtr := {%H-}pointer({%H-}PtrInt(SrcLine) + SrcRect.Left*3);
DstPtr := {%H-}pointer({%H-}PtrInt(DstLine) + 3*(SrcRect.Left + Offset.x));
for x := SrcRect.Left to SrcRect.Right do
begin
{$ifdef EnhancedRecordSupport}
Dist := Center.DistanceTo(T2DIntVector.Create(x, y));
{$else}
Dist := Center.DistanceTo(x, y);
{$endif}
if Dist <= (Radius-1) then
Move(SrcPtr^, DstPtr^, 3);
inc(SrcPtr, 3);
inc(DstPtr, 3);
end;
end;
ABitmap.LoadFromIntfImage(DestImg);
SrcImg.Destroy;
DestImg.Destroy;
end;
end else
begin
if (SrcRect.Left <= SrcRect.Right) and (SrcRect.Top <= SrcRect.Bottom) then
begin
SrcImg := ABuffer.CreateIntfImage;
DestImg := ABitmap.CreateIntfImage;
for y := SrcRect.Top to SrcRect.Bottom do
begin
SrcLine := SrcImg.GetDataLineStart(y);
DstLine := DestImg.GetDataLineStart(y+Offset.y);
SrcPtr := {%H-}pointer({%H-}PtrInt(SrcLine) + 3*SrcRect.Left);
DstPtr := {%H-}pointer({%H-}PtrInt(DstLine) + 3*(SrcRect.Left + Offset.x));
for x := SrcRect.Left to SrcRect.Right do
begin
{$ifdef EnhancedRecordSupport}
Dist := Center.DistanceTo(T2DIntVector.Create(x, y));
{$else}
Dist := Center.DistanceTo(x, y);
{$endif}
if Dist >= (Radius-1) then
Move(SrcPtr^, DstPtr^, 3);
inc(SrcPtr,3);
inc(DstPtr,3);
end;
end;
ABitmap.LoadFromIntfImage(DestImg);
SrcImg.Destroy;
DestImg.Destroy;
end;
end;
end;
class procedure TGUITools.CopyRoundRect(ABuffer, ABitmap: TBitmap; SrcPoint,
DstPoint: T2DIntVector; Width, Height, Radius: integer; ClipRect: T2DIntRect;
LeftTopRound, RightTopRound, LeftBottomRound, RightBottomRound: boolean);
begin
if (ABuffer.PixelFormat <> pf24Bit) or (ABitmap.PixelFormat <> pf24Bit) then
raise Exception.Create('TSpkGUITools.CopyBackground: Only 24 bit bitmaps are accepted!');
if Radius < 0 then
exit;
if (Radius > Width div 2) or (Radius > Height div 2) then
exit;
if (ABuffer.Width = 0) or (ABuffer.Height = 0) or
(ABitmap.Width = 0) or (ABitmap.Height = 0) then exit;
{$REGION 'We fill the rectangles'}
// Mountain /????
// Góra
CopyRectangle(ABuffer,
ABitmap,
{$ifdef EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Radius, SrcPoint.y),
T2DIntPoint.Create(DstPoint.x + Radius, DstPoint.y),
{$else}
Create2DIntPoint(SrcPoint.x + Radius, SrcPoint.y),
Create2DIntPoint(DstPoint.x + Radius, DstPoint.y),
{$endif}
Width - 2*Radius,
Radius,
ClipRect);
// Down
// Dó³
CopyRectangle(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Radius, SrcPoint.y + Height - Radius),
T2DIntPoint.Create(DstPoint.x + Radius, DstPoint.y + Height - Radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x + Radius, SrcPoint.y + Height - Radius),
Create2DIntPoint(DstPoint.x + Radius, DstPoint.y + Height - Radius),
{$ENDIF}
Width - 2*Radius,
Radius,
ClipRect);
// Agent (???)
// Œrodek
CopyRectangle(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x, SrcPoint.y + Radius),
T2DIntPoint.Create(DstPoint.x, DstPoint.y + Radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x, SrcPoint.y + Radius),
Create2DIntPoint(DstPoint.x, DstPoint.y + Radius),
{$ENDIF}
Width,
Height - 2*Radius,
ClipRect);
{$ENDREGION}
// We fill the corners
{$REGION 'Left upper'}
if LeftTopRound then
TGUITools.CopyRoundCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x, SrcPoint.y),
T2DIntPoint.Create(DstPoint.x, DstPoint.y),
{$ELSE}
Create2DIntPoint(SrcPoint.x, SrcPoint.y),
Create2DIntPoint(DstPoint.x, DstPoint.y),
{$ENDIF}
Radius,
cpLeftTop,
ClipRect,
true)
else
TGUITools.CopyCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x, SrcPoint.y),
T2DIntPoint.Create(DstPoint.x, DstPoint.y),
{$ELSE}
Create2DIntPoint(SrcPoint.x, SrcPoint.y),
Create2DIntPoint(DstPoint.x, DstPoint.y),
{$ENDIF}
Radius,
ClipRect);
{$ENDREGION}
{$REGION 'Right upper'}
if RightTopRound then
TGUITools.CopyRoundCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Width - Radius, SrcPoint.y),
T2DIntPoint.Create(DstPoint.x + Width - Radius, DstPoint.y),
{$ELSE}
Create2DIntPoint(SrcPoint.x + Width - Radius, SrcPoint.y),
Create2DIntPoint(DstPoint.x + Width - Radius, DstPoint.y),
{$ENDIF}
Radius,
cpRightTop,
ClipRect,
true)
else
TGUITools.CopyCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Width - Radius, SrcPoint.y),
T2DIntPoint.Create(DstPoint.x + Width - Radius, DstPoint.y),
{$ELSE}
Create2DIntPoint(SrcPoint.x + Width - Radius, SrcPoint.y),
Create2DIntPoint(DstPoint.x + Width - Radius, DstPoint.y),
{$ENDIF}
Radius,
ClipRect);
{$ENDREGION}
{$REGION 'Left bottom'}
if LeftBottomRound then
TGUITools.CopyRoundCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x, SrcPoint.y + Height - Radius),
T2DIntPoint.Create(DstPoint.x, DstPoint.y + Height - Radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x, SrcPoint.y + Height - Radius),
Create2DIntPoint(DstPoint.x, DstPoint.y + Height - Radius),
{$ENDIF}
Radius,
cpLeftBottom,
ClipRect,
true)
else
TGUITools.CopyCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x, SrcPoint.y + Height - Radius),
T2DIntPoint.Create(DstPoint.x, DstPoint.y + Height - Radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x, SrcPoint.y + Height - Radius),
Create2DIntPoint(DstPoint.x, DstPoint.y + Height - Radius),
{$ENDIF}
Radius,
ClipRect);
{$ENDREGION}
{$REGION 'Right bottom'}
if RightBottomRound then
TGUITools.CopyRoundCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Width - Radius, SrcPoint.y + Height - Radius),
T2DIntPoint.Create(DstPoint.x + Width - Radius, DstPoint.y + Height - Radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x + Width - Radius, SrcPoint.y + Height - Radius),
Create2DIntPoint(DstPoint.x + Width - Radius, DstPoint.y + Height - Radius),
{$ENDIF}
Radius,
cpRightBottom,
ClipRect,
true)
else
TGUITools.CopyCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Width - Radius, SrcPoint.y + Height - Radius),
T2DIntPoint.Create(DstPoint.x + Width - Radius, DstPoint.y + Height - Radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x + Width - Radius, SrcPoint.y + Height - Radius),
Create2DIntPoint(DstPoint.x + Width - Radius, DstPoint.y + Height - Radius),
{$ENDIF}
Radius,
ClipRect);
{$ENDREGION'}
end;
class procedure TGUITools.CopyRoundRect(ABuffer : TBitmap; ABitmap: TBitmap; SrcPoint,
DstPoint: T2DIntVector; Width, Height, Radius: integer; LeftTopRound,
RightTopRound, LeftBottomRound, RightBottomRound: boolean);
begin
if (ABuffer.PixelFormat <> pf24bit) or (ABitmap.PixelFormat <> pf24bit) then
raise exception.create('TSpkGUITools.CopyBackground: Only 24 bit bitmaps are accepted!');
if Radius < 0 then
exit;
if (Radius > Width div 2) or (Radius > Height div 2) then
exit;
if (ABuffer.Width = 0) or (ABuffer.Height = 0) or
(ABitmap.Width = 0) or (ABitmap.Height = 0) then exit;
{$REGION 'We fill the rectangles'}
// Góra
CopyRectangle(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Radius, SrcPoint.y),
T2DIntPoint.Create(DstPoint.x + Radius, DstPoint.y),
{$ELSE}
Create2DIntPoint(SrcPoint.x + Radius, SrcPoint.y),
Create2DIntPoint(DstPoint.x + Radius, DstPoint.y),
{$ENDIF}
Width - 2*Radius,
Radius);
// Dó³
CopyRectangle(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Radius, SrcPoint.y + Height - radius),
T2DIntPoint.Create(DstPoint.x + Radius, DstPoint.y + Height - radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x + Radius, SrcPoint.y + Height - radius),
Create2DIntPoint(DstPoint.x + Radius, DstPoint.y + Height - radius),
{$ENDIF}
Width - 2*Radius,
Radius);
// Œrodek
CopyRectangle(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x, SrcPoint.y + Radius),
T2DIntPoint.Create(DstPoint.x, DstPoint.y + Radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x, SrcPoint.y + Radius),
Create2DIntPoint(DstPoint.x, DstPoint.y + Radius),
{$ENDIF}
Width,
Height - 2*Radius);
{$ENDREGION}
// We fill the corners
{$REGION 'Left upper'}
if LeftTopRound then
TGUITools.CopyRoundCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x, SrcPoint.y),
T2DIntPoint.Create(DstPoint.x, DstPoint.y),
{$ELSE}
Create2DIntPoint(SrcPoint.x, SrcPoint.y),
Create2DIntPoint(DstPoint.x, DstPoint.y),
{$ENDIF}
Radius,
cpLeftTop,
true)
else
TGUITools.CopyCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x, SrcPoint.y),
T2DIntPoint.Create(DstPoint.x, DstPoint.y),
{$ELSE}
Create2DIntPoint(SrcPoint.x, SrcPoint.y),
Create2DIntPoint(DstPoint.x, DstPoint.y),
{$ENDIF}
Radius);
{$ENDREGION}
{$REGION 'Right upper'}
if RightTopRound then
TGUITools.CopyRoundCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Width - Radius, SrcPoint.y),
T2DIntPoint.Create(DstPoint.x + Width - Radius, DstPoint.y),
{$ELSE}
Create2DIntPoint(SrcPoint.x + Width - Radius, SrcPoint.y),
Create2DIntPoint(DstPoint.x + Width - Radius, DstPoint.y),
{$ENDIF}
Radius,
cpRightTop,
true)
else
TGUITools.CopyCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Width - Radius, SrcPoint.y),
T2DIntPoint.Create(DstPoint.x + Width - Radius, DstPoint.y),
{$ELSE}
Create2DIntPoint(SrcPoint.x + Width - Radius, SrcPoint.y),
Create2DIntPoint(DstPoint.x + Width - Radius, DstPoint.y),
{$ENDIF}
Radius);
{$ENDREGION}
{$REGION 'Left bottom'}
if LeftBottomRound then
TGUITools.CopyRoundCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x, SrcPoint.y + Height - Radius),
T2DIntPoint.Create(DstPoint.x, DstPoint.y + Height - Radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x, SrcPoint.y + Height - Radius),
Create2DIntPoint(DstPoint.x, DstPoint.y + Height - Radius),
{$ENDIF}
Radius,
cpLeftBottom,
true)
else
TGUITools.CopyCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x, SrcPoint.y + Height - Radius),
T2DIntPoint.Create(DstPoint.x, DstPoint.y + Height - Radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x, SrcPoint.y + Height - Radius),
Create2DIntPoint(DstPoint.x, DstPoint.y + Height - Radius),
{$ENDIF}
Radius);
{$ENDREGION}
{$REGION 'Right bottom'}
if RightBottomRound then
TGUITools.CopyRoundCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Width - Radius, SrcPoint.y + Height - Radius),
T2DIntPoint.Create(DstPoint.x + Width - Radius, DstPoint.y + Height - Radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x + Width - Radius, SrcPoint.y + Height - Radius),
Create2DIntPoint(DstPoint.x + Width - Radius, DstPoint.y + Height - Radius),
{$ENDIF}
Radius,
cpRightBottom,
true)
else
TGUITools.CopyCorner(ABuffer,
ABitmap,
{$IFDEF EnhancedRecordSupport}
T2DIntPoint.Create(SrcPoint.x + Width - Radius, SrcPoint.y + Height - Radius),
T2DIntPoint.Create(DstPoint.x + Width - Radius, DstPoint.y + Height - Radius),
{$ELSE}
Create2DIntPoint(SrcPoint.x + Width - Radius, SrcPoint.y + Height - Radius),
Create2DIntPoint(DstPoint.x + Width - Radius, DstPoint.y + Height - Radius),
{$ENDIF}
Radius);
{$ENDREGION}
end;
class procedure TGUITools.CopyRectangle(ABuffer, ABitmap: TBitmap; SrcPoint,
DstPoint: T2DIntVector; Width, Height: integer);
var
BufferRect, BitmapRect: T2DIntRect;
SrcRect, DstRect: T2DIntRect;
ClippedSrcRect: T2DIntRect;
Offset: T2DIntVector;
y: Integer;
SrcLine: Pointer;
DstLine: Pointer;
SrcImg: TLazIntfImage;
DestImg: TLazIntfImage;
begin
if (ABuffer.PixelFormat <> pf24Bit) or (ABitmap.PixelFormat <> pf24Bit) then
raise exception.create('TSpkGUITools.CopyRoundCorner: Only 24 bit bitmaps are accepted!');
// Validation
if (Width < 1) or (Height < 1) then
exit;
if (ABuffer.Width = 0) or (ABuffer.Height = 0) or
(ABitmap.Width = 0) or (ABitmap.Height = 0) then exit;
{$IFDEF EnhancedRecordSupport}
// Truncate the source rect to the source bitmap
BufferRect := T2DIntRect.Create(0, 0, ABuffer.Width-1, ABuffer.Height-1);
if not BufferRect.IntersectsWith(
T2DIntRect.Create(SrcPoint.x, SrcPoint.y, SrcPoint.x+Width-1, SrcPoint.y+Height-1),
SrcRect
)
then
exit;
// We cut the target rect to the target bitmap
BitmapRect := T2DIntRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not BitmapRect.IntersectsWith(
T2DIntRect.Create(DstPoint.x, DstPoint.y, DstPoint.x+Width-1, DstPoint.y+Height-1),
DstRect
)
then
exit;
{$ELSE}
// Truncate the source rect to the source bitmap
BufferRect.Create(0, 0, ABuffer.Width-1, ABuffer.Height-1);
if not BufferRect.IntersectsWith(
Create2DIntRect(SrcPoint.x, SrcPoint.y, SrcPoint.x+Width-1, SrcPoint.y+Height-1),
SrcRect
)
then
exit;
// We cut the target rect to the target bitmap
BitmapRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not BitmapRect.IntersectsWith(
Create2DIntRect(DstPoint.x, DstPoint.y, DstPoint.x+Width-1, DstPoint.y+Height-1),
DstRect
)
then
exit;
{$ENDIF}
// We are counting the source offset to the target recta
Offset := DstPoint - SrcPoint;
// Sprawdzamy, czy na³o¿one na siebie recty: Ÿród³owy i docelowy przesuniêty o
// offset maj¹ jak¹œ czêœæ wspóln¹
// Google-translated:
// Verify that the rectangular overhead: source and target shifted by offset have some common
if not SrcRect.IntersectsWith(DstRect - Offset, ClippedSrcRect) then
exit;
// If there is anything to process, do the operation
if (ClippedSrcRect.Left <= ClippedSrcRect.Right) and
(ClippedSrcRect.Top <= ClippedSrcRect.Bottom) then
begin
SrcImg := ABuffer.CreateIntfImage;
DestImg := ABitmap.CreateIntfImage;
for y := ClippedSrcRect.Top to ClippedSrcRect.Bottom do
begin
SrcLine := SrcImg.GetDataLineStart(y);
DstLine := DestImg.GetDataLineStart(y+Offset.y);
Move({%H-}pointer({%H-}PtrInt(SrcLine) + 3*ClippedSrcRect.Left)^,
{%H-}pointer({%H-}PtrInt(DstLine) + 3*(ClippedSrcRect.Left + Offset.x))^,
3*ClippedSrcRect.Width);
end;
ABitmap.LoadFromIntfImage(DestImg);
SrcImg.Destroy;
DestImg.Destroy;
end;
end;
class procedure TGUITools.CopyCorner(ABuffer, ABitmap: TBitmap;
SrcPoint, DstPoint: T2DIntVector; Radius: integer);
begin
CopyRectangle(ABuffer, ABitmap, SrcPoint, DstPoint, Radius, Radius);
end;
class procedure TGUITools.CopyCorner(ABuffer, ABitmap: TBitmap; SrcPoint,
DstPoint: T2DIntVector; Radius: integer; ClipRect: T2DIntRect);
begin
CopyRectangle(ABuffer, ABitmap, SrcPoint, DstPoint, Radius, Radius, ClipRect);
end;
class procedure TGUITools.CopyMaskRectangle(ABuffer, AMask, ABitmap: TBitmap;
SrcPoint, DstPoint: T2DIntVector; Width, Height: integer);
var
BufferRect, BitmapRect: T2DIntRect;
SrcRect, DstRect: T2DIntRect;
ClippedSrcRect: T2DIntRect;
Offset: T2DIntVector;
y: Integer;
SrcLine: Pointer;
MaskLine: Pointer;
DstLine: Pointer;
SrcImg: TLazIntfImage;
MaskImg: TLazIntfImage;
DestImg: TLazIntfImage;
i: Integer;
begin
if (ABuffer.PixelFormat <> pf24Bit) or (ABitmap.PixelFormat <> pf24Bit) then
raise Exception.Create('TSpkGUITools.CopyRoundCorner: Only 24 bit bitmaps are accepted!');
if (AMask.PixelFormat <> pf8bit) then
raise Exception.Create('TSpkGUITools.CopyRoundCorner: Only 8-bit masks are accepted!');
// Validation
if (Width < 1) or (Height < 1) then
exit;
if (ABuffer.Width = 0) or (ABuffer.Height = 0) or
(ABitmap.Width = 0) or (ABitmap.Height = 0) then exit;
if (ABuffer.Width <> AMask.Width) or (ABuffer.Height <> AMask.Height) then
exit;
{$IFDEF EnhancedRecordSupport}
// Truncate the source rect to the source bitmap
BufferRect := T2DIntRect.Create(0, 0, ABuffer.Width-1, ABuffer.Height-1);
if not BufferRect.IntersectsWith(
T2DIntRect.Create(SrcPoint.x, SrcPoint.y, SrcPoint.x+Width-1, SrcPoint.y+Height-1),
SrcRect
) then
exit;
// We cut the target rect to the target bitmap
BitmapRect := T2DIntRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not BitmapRect.IntersectsWith(
T2DIntRect.Create(DstPoint.x, DstPoint.y, DstPoint.x+Width-1, DstPoint.y+Height-1),
DstRect
) then
exit;
{$ELSE}
// Truncate the source rect to the source bitmap
BufferRect.Create(0, 0, ABuffer.Width-1, ABuffer.Height-1);
if not BufferRect.IntersectsWith(
Create2DIntRect(SrcPoint.x, SrcPoint.y, SrcPoint.x+Width-1, SrcPoint.y+Height-1),
SrcRect
) then
exit;
// Trim the target rect to the target bitmap
BitmapRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not BitmapRect.IntersectsWith(
Create2DIntRect(DstPoint.x, DstPoint.y, DstPoint.x+Width-1, DstPoint.y+Height-1),
DstRect
) then
exit;
{$ENDIF}
// We are counting the source offset to the target recta
Offset := DstPoint - SrcPoint;
// Sprawdzamy, czy na³o¿one na siebie recty: Ÿród³owy i docelowy przesuniêty o
// offset maj¹ jak¹œ czêœæ wspóln¹
// Google-translated:
// We check that the rectangles that are superimposed on each other:
// source and target shifted by offset have some common
if not(SrcRect.IntersectsWith(DstRect - Offset, ClippedSrcRect)) then
exit;
// If there is anything to process, do the operation
if (ClippedSrcRect.Left <= ClippedSrcRect.Right) and
(ClippedSrcRect.Top <= ClippedSrcRect.Bottom) then
begin
SrcImg := ABuffer.CreateIntfImage;
DestImg := ABitmap.CreateIntfImage;
MaskImg := AMask.CreateIntfImage;
for y := ClippedSrcRect.Top to ClippedSrcRect.Bottom do
begin
SrcLine := SrcImg.GetDataLineStart(y);
SrcLine := {%H-}pointer({%H-}PtrInt(SrcLine) + 3 * ClippedSrcRect.left);
MaskLine := MaskImg.GetDataLineStart(y);
MaskLine := {%H-}pointer({%H-}PtrInt(MaskLine) + ClippedSrcRect.left);
DstLine := DestImg.GetDataLineStart(y+Offset.y);
DstLine := {%H-}pointer({%H-}PtrInt(DstLine) + 3 * (ClippedSrcRect.left + Offset.x));
for i := 0 to ClippedSrcRect.Width - 1 do
begin
if PByte(MaskLine)^ < 128 then
Move(SrcLine^, DstLine^, 3);
SrcLine := {%H-}pointer({%H-}PtrInt(SrcLine)+3);
DstLine := {%H-}pointer({%H-}PtrInt(DstLine)+3);
MaskLine := {%H-}pointer({%H-}PtrInt(MaskLine)+1);
end;
end;
ABitmap.LoadFromIntfImage(DestImg);
DestImg.Destroy;
SrcImg.Destroy;
MaskImg.Destroy;
end;
end;
class procedure TGUITools.CopyMaskRectangle(ABuffer, AMask, ABitmap: TBitmap;
SrcPoint, DstPoint: T2DIntVector; Width, Height: integer;
ClipRect: T2DIntRect);
var
BufferRect, BitmapRect: T2DIntRect;
SrcRect, DstRect: T2DIntRect;
ClippedSrcRect, ClippedDstRect: T2DIntRect;
Offset: T2DIntVector;
y: Integer;
SrcImg: TLazIntfImage;
MaskImg: TLazIntfImage;
DestImg: TLazIntfImage;
SrcLine: Pointer;
DstLine: Pointer;
i: Integer;
MaskLine: Pointer;
begin
if (ABuffer.PixelFormat <> pf24Bit) or (ABitmap.PixelFormat <> pf24Bit) then
raise Exception.Create('TSpkGUITools.CopyMaskRectangle: Only 24 bit bitmaps are accepted!');
if AMask.PixelFormat<>pf8bit then
raise Exception.Create('TSpkGUITools.CopyMaskRectangle: Only 8-bit masks are accepted!');
// Validation
if (Width < 1) or (Height < 1) then
exit;
if (ABuffer.Width = 0) or (ABuffer.Height = 0) or
(ABitmap.Width = 0) or (ABitmap.Height = 0) then exit;
if (ABuffer.Width <> AMask.Width) or
(ABuffer.Height <> AMask.Height)
then
raise Exception.Create('TSpkGUITools.CopyMaskRectangle: The mask has incorrect dimensions!');
{$IFDEF EnhancedRecordSupport}
// Truncate the source rect to the source bitmap
BufferRect := T2DIntRect.Create(0, 0, ABuffer.Width-1, ABuffer.Height-1);
if not BufferRect.IntersectsWith(
T2DIntRect.Create(SrcPoint.x, SrcPoint.y, SrcPoint.x+Width-1, SrcPoint.y+Height-1),
SrcRect
)
then
exit;
// Przycinamy docelowy rect do obszaru docelowej bitmapy
BitmapRect:=T2DIntRect.create(0, 0, ABitmap.width-1, ABitmap.height-1);
if not(BitmapRect.IntersectsWith(T2DIntRect.create(DstPoint.x,
DstPoint.y,
DstPoint.x+Width-1,
DstPoint.y+Height-1),
DstRect)) then exit;
{$ELSE}
// Przycinamy Ÿród³owy rect do obszaru Ÿród³owej bitmapy
BufferRect.create(0, 0, ABuffer.width-1, ABuffer.height-1);
if not(BufferRect.IntersectsWith(Create2DIntRect(SrcPoint.x,
SrcPoint.y,
SrcPoint.x+Width-1,
SrcPoint.y+Height-1),
SrcRect)) then exit;
// Przycinamy docelowy rect do obszaru docelowej bitmapy
BitmapRect.create(0, 0, ABitmap.width-1, ABitmap.height-1);
if not(BitmapRect.IntersectsWith(Create2DIntRect(DstPoint.x,
DstPoint.y,
DstPoint.x+Width-1,
DstPoint.y+Height-1),
DstRect)) then exit;
{$ENDIF}
// Dodatkowo przycinamy docelowy rect
if not(DstRect.IntersectsWith(ClipRect, ClippedDstRect)) then
Exit;
// Liczymy offset Ÿród³owego do docelowego recta
Offset:=DstPoint - SrcPoint;
// Sprawdzamy, czy na³o¿one na siebie recty: Ÿród³owy i docelowy przesuniêty o
// offset maj¹ jak¹œ czêœæ wspóln¹
if not(SrcRect.IntersectsWith(ClippedDstRect - Offset, ClippedSrcRect)) then exit;
// Jeœli jest cokolwiek do przetworzenia, wykonaj operacjê
if (ClippedSrcRect.left<=ClippedSrcRect.right) and (ClippedSrcRect.top<=ClippedSrcRect.bottom) then
begin
SrcImg := ABuffer.CreateIntfImage;
DestImg := ABitmap.CreateIntfImage;
MaskImg := ABitmap.CreateIntfImage;
for y := ClippedSrcRect.top to ClippedSrcRect.bottom do
begin
SrcLine:=SrcImg.GetDataLineStart(y);
SrcLine:={%H-}pointer({%H-}PtrInt(SrcLine) + 3 * ClippedSrcRect.left);
MaskLine:=MaskImg.GetDataLineStart(y);
MaskLine:={%H-}pointer({%H-}PtrInt(MaskLine) + ClippedSrcRect.left);
DstLine:=DestImg.GetDataLineStart(y+Offset.y);
DstLine:={%H-}pointer({%H-}PtrInt(DstLine) + 3 * (ClippedSrcRect.left + Offset.x));
for i := 0 to ClippedSrcRect.width - 1 do
begin
if PByte(MaskLine)^<128 then
Move(SrcLine^, DstLine^, 3);
SrcLine:={%H-}pointer({%H-}PtrInt(SrcLine)+3);
DstLine:={%H-}pointer({%H-}PtrInt(DstLine)+3);
MaskLine:={%H-}pointer({%H-}PtrInt(MaskLine)+1);
end;
end;
ABitmap.LoadFromIntfImage(DestImg);
SrcImg.Destroy;
DestImg.Destroy;
MaskImg.Destroy;
end;
end;
class procedure TGUITools.CopyRectangle(ABuffer, ABitmap: TBitmap; SrcPoint,
DstPoint: T2DIntVector; Width, Height: integer; ClipRect: T2DIntRect);
var BufferRect, BitmapRect : T2DIntRect;
SrcRect, DstRect : T2DIntRect;
ClippedSrcRect, ClippedDstRect : T2DIntRect;
Offset : T2DIntVector;
y: Integer;
DestImg: TLazIntfImage;
SrcImg: TLazIntfImage;
SrcLine: Pointer;
DstLine: Pointer;
begin
if (ABuffer.PixelFormat<>pf24bit) or (ABitmap.PixelFormat<>pf24bit) then
raise exception.create('TSpkGUITools.CopyRoundCorner: Tylko 24-bitowe bitmapy s¹ akceptowane!');
// Sprawdzanie poprawnoœci
if (Width<1) or (Height<1) then
exit;
if (ABuffer.width=0) or (ABuffer.height=0) or
(ABitmap.width=0) or (ABitmap.height=0) then exit;
{$IFDEF EnhancedRecordSupport}
// Przycinamy Ÿród³owy rect do obszaru Ÿród³owej bitmapy
BufferRect:=T2DIntRect.create(0, 0, ABuffer.width-1, ABuffer.height-1);
if not(BufferRect.IntersectsWith(T2DIntRect.create(SrcPoint.x,
SrcPoint.y,
SrcPoint.x+Width-1,
SrcPoint.y+Height-1),
SrcRect)) then exit;
// Przycinamy docelowy rect do obszaru docelowej bitmapy
BitmapRect:=T2DIntRect.create(0, 0, ABitmap.width-1, ABitmap.height-1);
if not(BitmapRect.IntersectsWith(T2DIntRect.create(DstPoint.x,
DstPoint.y,
DstPoint.x+Width-1,
DstPoint.y+Height-1),
DstRect)) then exit;
{$ELSE}
// Przycinamy Ÿród³owy rect do obszaru Ÿród³owej bitmapy
BufferRect.create(0, 0, ABuffer.width-1, ABuffer.height-1);
if not(BufferRect.IntersectsWith(Create2DIntRect(SrcPoint.x,
SrcPoint.y,
SrcPoint.x+Width-1,
SrcPoint.y+Height-1),
SrcRect)) then exit;
// Przycinamy docelowy rect do obszaru docelowej bitmapy
BitmapRect.create(0, 0, ABitmap.width-1, ABitmap.height-1);
if not(BitmapRect.IntersectsWith(Create2DIntRect(DstPoint.x,
DstPoint.y,
DstPoint.x+Width-1,
DstPoint.y+Height-1),
DstRect)) then exit;
{$ENDIF}
// Dodatkowo przycinamy docelowy rect
if not(DstRect.IntersectsWith(ClipRect, ClippedDstRect)) then
Exit;
// Liczymy offset Ÿród³owego do docelowego recta
Offset:=DstPoint - SrcPoint;
// Sprawdzamy, czy na³o¿one na siebie recty: Ÿród³owy i docelowy przesuniêty o
// offset maj¹ jak¹œ czêœæ wspóln¹
if not(SrcRect.IntersectsWith(ClippedDstRect - Offset, ClippedSrcRect)) then exit;
// Jeœli jest cokolwiek do przetworzenia, wykonaj operacjê
if (ClippedSrcRect.left<=ClippedSrcRect.right) and (ClippedSrcRect.top<=ClippedSrcRect.bottom) then
begin
SrcImg := ABuffer.CreateIntfImage;
DestImg := ABitmap.CreateIntfImage;
for y := ClippedSrcRect.top to ClippedSrcRect.bottom do
begin
SrcLine:=SrcImg.GetDataLineStart(y);
DstLine:=DestImg.GetDataLineStart(y+Offset.y);
Move({%H-}pointer({%H-}PtrInt(SrcLine) + 3*ClippedSrcRect.left)^,
{%H-}pointer({%H-}PtrInt(DstLine) + 3*(ClippedSrcRect.left + Offset.x))^,
3*ClippedSrcRect.Width);
end;
ABitmap.LoadFromIntfImage(DestImg);
DestImg.Destroy;
SrcImg.Destroy;
end;
end;
class procedure TGUITools.CopyRoundCorner(ABuffer: TBitmap; ABitmap: TBitmap;
SrcPoint, DstPoint: T2DIntVector; Radius: integer; CornerPos: TCornerPos;
Convex: boolean);
var BufferRect, BitmapRect : T2DIntRect;
OrgSrcRect, OrgDstRect : T2DIntRect;
SrcRect : T2DIntRect;
Offset : T2DIntVector;
Center: T2DIntVector;
y: Integer;
SrcImg: TLazIntfImage;
DestImg: TLazIntfImage;
SrcLine: Pointer;
DstLine: Pointer;
SrcPtr, DstPtr : PByte;
x: Integer;
Dist : double;
begin
if (ABuffer.PixelFormat<>pf24bit) or (ABitmap.PixelFormat<>pf24bit) then
raise exception.create('TSpkGUITools.CopyRoundCorner: Tylko 24-bitowe bitmapy s¹ akceptowane!');
// Sprawdzanie poprawnoœci
if Radius<1 then
exit;
if (ABuffer.width=0) or (ABuffer.height=0) or
(ABitmap.width=0) or (ABitmap.height=0) then exit;
{$IFDEF EnhancedRecordSupport}
BufferRect:=T2DIntRect.create(0, 0, ABuffer.width-1, ABuffer.height-1);
if not(BufferRect.IntersectsWith(T2DIntRect.create(SrcPoint.x,
SrcPoint.y,
SrcPoint.x+Radius-1,
SrcPoint.y+Radius-1),
OrgSrcRect)) then exit;
BitmapRect:=T2DIntRect.create(0, 0, ABitmap.width-1, ABitmap.height-1);
if not(BitmapRect.IntersectsWith(T2DIntRect.create(DstPoint.x,
DstPoint.y,
DstPoint.x+Radius-1,
DstPoint.y+Radius-1),
OrgDstRect)) then exit;
{$ELSE}
BufferRect.create(0, 0, ABuffer.width-1, ABuffer.height-1);
if not(BufferRect.IntersectsWith(Create2DIntRect(SrcPoint.x,
SrcPoint.y,
SrcPoint.x+Radius-1,
SrcPoint.y+Radius-1),
OrgSrcRect)) then exit;
BitmapRect.create(0, 0, ABitmap.width-1, ABitmap.height-1);
if not(BitmapRect.IntersectsWith(Create2DIntRect(DstPoint.x,
DstPoint.y,
DstPoint.x+Radius-1,
DstPoint.y+Radius-1),
OrgDstRect)) then exit;
{$ENDIF}
Offset:=DstPoint - SrcPoint;
if not(OrgSrcRect.IntersectsWith(OrgDstRect - Offset, SrcRect)) then exit;
// Ustalamy pozycjê œrodka ³uku
{$IFDEF EnhancedRecordSupport}
case CornerPos of
cpLeftTop: Center:=T2DIntVector.create(SrcPoint.x + radius - 1, SrcPoint.y + Radius - 1);
cpRightTop: Center:=T2DIntVector.create(SrcPoint.x, SrcPoint.y + Radius - 1);
cpLeftBottom: Center:=T2DIntVector.Create(SrcPoint.x + radius - 1, SrcPoint.y);
cpRightBottom: Center:=T2DIntVector.Create(SrcPoint.x, SrcPoint.y);
end;
{$ELSE}
case CornerPos of
cpLeftTop: Center.create(SrcPoint.x + radius - 1, SrcPoint.y + Radius - 1);
cpRightTop: Center.create(SrcPoint.x, SrcPoint.y + Radius - 1);
cpLeftBottom: Center.Create(SrcPoint.x + radius - 1, SrcPoint.y);
cpRightBottom: Center.Create(SrcPoint.x, SrcPoint.y);
end;
{$ENDIF}
// Czy jest cokolwiek do przetworzenia?
if Convex then
begin
if (SrcRect.left<=SrcRect.right) and (SrcRect.top<=SrcRect.bottom) then
begin
SrcImg := ABuffer.CreateIntfImage;
DestImg := ABitmap.CreateIntfImage;
for y := SrcRect.top to SrcRect.bottom do
begin
SrcLine:=SrcImg.GetDataLineStart(y);
DstLine:=DestImg.GetDataLineStart(y+Offset.y);
SrcPtr:={%H-}pointer({%H-}PtrInt(SrcLine) + 3*SrcRect.left);
DstPtr:={%H-}pointer({%H-}PtrInt(DstLine) + 3*(SrcRect.left + Offset.x));
for x := SrcRect.left to SrcRect.right do
begin
{$IFDEF EnhancedRecordSupport}
Dist:=Center.DistanceTo(T2DVector.create(x, y));
{$ELSE}
Dist:=Center.DistanceTo(x, y);
{$ENDIF}
if Dist <= (Radius-1) then
Move(SrcPtr^,DstPtr^,3);
inc(SrcPtr,3);
inc(DstPtr,3);
end;
end;
ABitmap.LoadFromIntfImage(DestImg);
SrcImg.Destroy;
DestImg.Destroy;
end;
end
else
begin
if (SrcRect.left<=SrcRect.right) and (SrcRect.top<=SrcRect.bottom) then
begin
SrcImg := ABuffer.CreateIntfImage;
DestImg := ABitmap.CreateIntfImage;
for y := SrcRect.top to SrcRect.bottom do
begin
SrcLine:=SrcImg.GetDataLineStart(y);
DstLine:=DestImg.GetDataLineStart(y+Offset.y);
SrcPtr:={%H-}pointer({%H-}PtrInt(SrcLine) + 3*SrcRect.left);
DstPtr:={%H-}pointer({%H-}PtrInt(DstLine) + 3*(SrcRect.left + Offset.x));
for x := SrcRect.left to SrcRect.right do
begin
{$IFDEF EnhancedRecordSupport}
Dist:=Center.DistanceTo(T2DVector.create(x, y));
{$ELSE}
Dist:=Center.DistanceTo(x, y);
{$ENDIF}
if Dist >= (Radius-1) then
Move(SrcPtr^,DstPtr^,3);
inc(SrcPtr,3);
inc(DstPtr,3);
end;
end;
ABitmap.LoadFromIntfImage(DestImg);
SrcImg.Destroy;
DestImg.Destroy;
end;
end;
end;
class procedure TGUITools.DrawAARoundCorner(ABitmap: TBitmap; Point: T2DIntVector;
Radius: integer; CornerPos: TCornerPos; Color: TColor);
var
CornerRect: T2DIntRect;
Center: T2DIntVector;
colorR, colorG, colorB: byte;
x, y: integer;
RadiusDist: double;
OrgCornerRect: T2DIntRect;
BitmapRect: T2DIntRect;
cr, cg, cb: Byte;
begin
if ABitmap.PixelFormat <> pf24bit then
raise Exception.Create('TSpkGUITools.DrawAARoundCorner: Bitmapa musi byæ w trybie 24-bitowym!');
// Sprawdzamy poprawnoϾ
if Radius < 1 then
exit;
if (ABitmap.Width=0) or (ABitmap.Height=0) then
exit;
{$IFDEF EnhancedRecordSupport}
// <20>?ród³owy rect...
OrgCornerRect := T2DIntRect.Create(Point.x,
Point.y,
Point.x + radius - 1,
Point.y + radius - 1);
// ...przycinamy do rozmiarów bitmapy
BitmapRect := T2DIntRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
{$ELSE}
// <20>?ród³owy rect...
OrgCornerRect.Create(Point.x,
Point.y,
Point.x + radius - 1,
Point.y + radius - 1);
// ...przycinamy do rozmiarów bitmapy
BitmapRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
{$ENDIF}
if not BitmapRect.intersectsWith(OrgCornerRect, CornerRect) then
exit;
// Jeœli nie ma czego rysowaæ, wychodzimy
if (CornerRect.Left > CornerRect.Right) or (CornerRect.Top > CornerRect.Bottom) then
exit;
// Szukamy œrodka ³uku - zale¿nie od rodzaju naro¿nika
{$IFDEF EnhancedRecordSupport}
case CornerPos of
cpLeftTop:
Center := T2DIntVector.Create(Point.x + radius - 1, Point.y + Radius - 1);
cpRightTop:
Center := T2DIntVector.Create(Point.x, Point.y + Radius - 1);
cpLeftBottom:
Center := T2DIntVector.Create(Point.x + radius - 1, Point.y);
cpRightBottom:
Center := T2DIntVector.Create(Point.x, Point.y);
end;
{$ELSE}
case CornerPos of
cpLeftTop:
Center.Create(Point.x + radius - 1, Point.y + Radius - 1);
cpRightTop:
Center.Create(Point.x, Point.y + Radius - 1);
cpLeftBottom:
Center.Create(Point.x + radius - 1, Point.y);
cpRightBottom:
Center.Create(Point.x, Point.y);
end;
{$ENDIF}
Color := ColorToRGB(Color);
colorR := GetRValue(Color);
colorG := GetGValue(Color);
colorB := GetBValue(Color);
for y := CornerRect.Top to CornerRect.Bottom do
begin
for x := CornerRect.Left to CornerRect.Right do
begin
{$IFDEF EnhancedRecordSupport}
RadiusDist := 1 - abs((Radius - 1) - Center.DistanceTo(T2DIntVector.create(x, y)));
{$ELSE}
RadiusDist := 1 - abs((Radius - 1) - Center.DistanceTo(x, y));
{$ENDIF}
if RadiusDist > 0 then
begin
RedGreenBlue(ColorToRGB(ABitmap.Canvas.Pixels[x,y]), cr, cg, cb);
cb := round(cb + (ColorB - cb) * RadiusDist);
cg := round(cg + (ColorG - cg) * RadiusDist);
cr := round(cr + (ColorR - cr) * RadiusDist);
ABitmap.Canvas.Pixels[x,y] := RGBToColor(cr,cg,cb);
end;
end;
end;
end;
class procedure TGUITools.DrawAARoundCorner(ABitmap: TBitmap;
Point: T2DIntVector; Radius: integer; CornerPos: TCornerPos; Color: TColor;
ClipRect: T2DIntRect);
var
CornerRect: T2DIntRect;
Center: T2DIntVector;
colorR, colorG, colorB: byte;
x, y: integer;
RadiusDist: double;
OrgCornerRect: T2DIntRect;
UnClippedCornerRect : T2DIntRect;
BitmapRect: T2DIntRect;
cr,cb,cg: byte;
begin
if ABitmap.PixelFormat<>pf24bit then
raise Exception.Create('TSpkGUITools.DrawAARoundCorner: Bitmap must be in 24-bit mode!');
if Radius < 1 then
exit;
if (ABitmap.Width = 0) or (ABitmap.Height = 0) then
exit;
{$IFDEF EnhancedRecordSupport}
// Source rect...
OrgCornerRect := T2DIntRect.Create(
Point.x, Point.y, Point.x + radius - 1, Point.y + radius - 1
);
// ... cut to size bitmap
BitmapRect := T2DIntRect.Create(
0, 0, ABitmap.Width-1, ABitmap.Height-1);
{$ELSE}
// Source rect...
OrgCornerRect.Create(Point.x,
Point.y,
Point.x + radius - 1,
Point.y + radius - 1);
// ... cut to size bitmap
BitmapRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
{$ENDIF}
if not BitmapRect.IntersectsWith(OrgCornerRect, UnClippedCornerRect) then
exit;
// ClipRect
if not UnClippedCornerRect.IntersectsWith(ClipRect, CornerRect) then
exit;
// If there is nothing to draw, we leave
if (CornerRect.Left > CornerRect.Right) or
(CornerRect.Top > CornerRect.Bottom)
then
exit;
// We seek the center of the arc - depending on the type of corner
{$IFDEF EnhancedRecordSupport}
case CornerPos of
cpLeftTop:
Center := T2DIntVector.Create(Point.x + radius - 1, Point.y + Radius - 1);
cpRightTop:
Center := T2DIntVector.Create(Point.x, Point.y + Radius - 1);
cpLeftBottom:
Center := T2DIntVector.Create(Point.x + radius - 1, Point.y);
cpRightBottom:
Center := T2DIntVector.Create(Point.x, Point.y);
end;
{$ELSE}
case CornerPos of
cpLeftTop:
Center.Create(Point.x + radius - 1, Point.y + Radius - 1);
cpRightTop:
Center.Create(Point.x, Point.y + Radius - 1);
cpLeftBottom:
Center.Create(Point.x + radius - 1, Point.y);
cpRightBottom:
Center.Create(Point.x, Point.y);
end;
{$ENDIF}
Color := ColorToRGB(Color);
colorR := GetRValue(Color);
colorG := GetGValue(Color);
colorB := GetBValue(Color);
for y := CornerRect.Top to CornerRect.Bottom do
begin
for x := CornerRect.Left to CornerRect.Right do
begin
{$IFDEF EnhancedRecordSupport}
RadiusDist := 1 - abs((Radius - 1) - Center.DistanceTo(T2DIntVector.create(x, y)));
{$ELSE}
RadiusDist := 1 - abs((Radius - 1) - Center.DistanceTo(x, y));
{$ENDIF}
if RadiusDist > 0 then
begin
RedGreenBlue(ColorToRGB(ABitmap.Canvas.Pixels[x,y]), cr, cg, cb);
cb := round(cb + (ColorB - cb) * RadiusDist);
cg := round(cg + (ColorG - cg) * RadiusDist);
cr := round(cr + (ColorR - cr) * RadiusDist);
ABitmap.Canvas.Pixels[x,y] := RGBToColor(cr,cg,cb);
end;
end;
end;
end;
class procedure TGUITools.DrawAARoundCorner(ACanvas: TCanvas;
Point: T2DIntVector; Radius: integer; CornerPos: TCornerPos; Color: TColor);
var
Center: T2DIntVector;
OrgColor: TColor;
x, y: integer;
RadiusDist: double;
CornerRect: T2DIntRect;
begin
if Radius<1 then
exit;
{$IFDEF EnhancedRecordSupport}
// Source rect
CornerRect := T2DIntRect.Create(
Point.x, Point.y, Point.x + radius - 1, Point.y + radius - 1
);
// We seek the center of the arc - depending on the type of corner
case CornerPos of
cpLeftTop:
Center := T2DIntVector.Create(Point.x + radius - 1, Point.y + Radius - 1);
cpRightTop:
Center := T2DIntVector.Create(Point.x, Point.y + Radius - 1);
cpLeftBottom:
Center := T2DIntVector.Create(Point.x + radius - 1, Point.y);
cpRightBottom:
Center := T2DIntVector.Create(Point.x, Point.y);
end;
{$ELSE}
// Source rect
CornerRect.Create(Point.x, Point.y, Point.x + radius - 1, Point.y + radius - 1);
// We seek the center of the arc - depending on the type of corner
case CornerPos of
cpLeftTop:
Center.Create(Point.x + radius - 1, Point.y + Radius - 1);
cpRightTop:
Center.Create(Point.x, Point.y + Radius - 1);
cpLeftBottom:
Center.Create(Point.x + radius - 1, Point.y);
cpRightBottom:
Center.Create(Point.x, Point.y);
end;
{$ENDIF}
Color := ColorToRGB(Color);
for y := CornerRect.Top to CornerRect.Bottom do
begin
for x := CornerRect.Left to CornerRect.Right do
begin
{$IFDEF EnhancedRecordSupport}
RadiusDist := 1 - abs((Radius - 1) - Center.DistanceTo(T2DIntVector.Create(x, y)));
{$ELSE}
RadiusDist := 1 - abs((Radius - 1) - Center.DistanceTo(x, y));
{$ENDIF}
if RadiusDist > 0 then
begin
OrgColor := ACanvas.Pixels[x, y];
ACanvas.Pixels[x, y] := TColorTools.Shade(OrgColor, Color, RadiusDist);
end;
end;
end;
end;
class procedure TGUITools.DrawAARoundCorner(ACanvas: TCanvas;
Point: T2DIntVector; Radius: integer; CornerPos: TCornerPos; Color: TColor;
ClipRect: T2DIntRect);
var
UseOrgClipRgn: boolean;
ClipRgn: HRGN;
OrgRgn: HRGN;
begin
// Store the original ClipRgn and set a new one
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
ClipRgn := CreateRectRgn(ClipRect.Left, ClipRect.Top, ClipRect.Right+1, ClipRect.Bottom+1);
if UseOrgClipRgn then
CombineRgn(ClipRgn, ClipRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, ClipRgn);
DrawAARoundCorner(ACanvas, Point, Radius, CornerPos, Color);
// Restores previous ClipRgn and removes used regions
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(ClipRgn);
end;
class procedure TGUITools.DrawAARoundFrame(ABitmap: TBitmap; Rect: T2DIntRect;
Radius: integer; Color: TColor; ClipRect: T2DIntRect);
begin
if ABitmap.PixelFormat <> pf24Bit then
raise Exception.Create('TGUITools.DrawAARoundFrame: Bitmap must be in 24-bit mode!');
if Radius < 1 then
exit;
if (Radius > Rect.Width div 2) or (Radius > Rect.Height div 2) then
exit;
// DrawAARoundCorner is protected against drawing outside the area
{$IFDEF EnhancedRecordSupport}
DrawAARoundCorner(ABitmap, T2DIntVector.Create(Rect.Left, Rect.Top), Radius, cpLeftTop, Color, ClipRect);
DrawAARoundCorner(ABitmap, T2DIntVector.Create(Rect.Right - Radius + 1, Rect.Top), Radius, cpRightTop, Color, ClipRect);
DrawAARoundCorner(ABitmap, T2DIntVector.Create(Rect.Left, Rect.Bottom - Radius + 1), Radius, cpLeftBottom, Color, ClipRect);
DrawAARoundCorner(ABitmap, T2DIntVector.Create(Rect.Right - Radius + 1, Rect.Bottom - Radius + 1), Radius, cpRightBottom, Color, ClipRect);
{$ELSE}
DrawAARoundCorner(ABitmap, Create2DIntVector(Rect.Left, Rect.Top), Radius, cpLeftTop, Color, ClipRect);
DrawAARoundCorner(ABitmap, Create2DIntVector(Rect.Right - Radius + 1, Rect.Top), Radius, cpRightTop, Color, ClipRect);
DrawAARoundCorner(ABitmap, Create2DIntVector(Rect.Left, Rect.Bottom - Radius + 1), Radius, cpLeftBottom, Color, ClipRect);
DrawAARoundCorner(ABitmap, Create2DIntVector(Rect.Right - Radius + 1, Rect.Bottom - Radius + 1), Radius, cpRightBottom, Color, ClipRect);
{$ENDIF}
ABitmap.Canvas.Pen.Color := Color;
ABitmap.Canvas.pen.Style := psSolid;
// Draw*Line is protected against drawing outside the area
DrawVLine(ABitmap, Rect.Left, Rect.top + Radius, Rect.Bottom - Radius, Color, ClipRect);
DrawVLine(ABitmap, Rect.Right, Rect.top + Radius, Rect.Bottom - Radius, Color, ClipRect);
DrawHLine(ABitmap, Rect.Left + Radius, Rect.Right - Radius, Rect.Top, Color, ClipRect);
DrawHLine(ABitmap, Rect.Left + Radius, Rect.Right - Radius, Rect.Bottom, Color, ClipRect);
end;
class procedure TGUITools.DrawAARoundFrame(ABitmap: TBitmap; Rect: T2DIntRect;
Radius: integer; Color: TColor);
begin
if ABitmap.PixelFormat <> pf24Bit then
raise Exception.Create('TGUITools.DrawAARoundFrame: Bitmap must be in 24-bit mode!');
if Radius < 1 then
exit;
if (Radius > Rect.Width div 2) or (Radius > Rect.Height div 2) then
exit;
// DrawAARoundCorner is protected against drawing outside the area
{$IFDEF EnhancedRecordSupport}
DrawAARoundCorner(ABitmap, T2DIntVector.Create(Rect.Left, Rect.Top), Radius, cpLeftTop, Color);
DrawAARoundCorner(ABitmap, T2DIntVector.Create(Rect.Right - Radius + 1, Rect.Top), Radius, cpRightTop, Color);
DrawAARoundCorner(ABitmap, T2DIntVector.Create(Rect.Left, Rect.Bottom - Radius + 1), Radius, cpLeftBottom, Color);
DrawAARoundCorner(ABitmap, T2DIntVector.Create(Rect.Right - Radius + 1, Rect.Bottom - Radius + 1), Radius, cpRightBottom, Color);
{$ELSE}
DrawAARoundCorner(ABitmap, Create2DIntVector(Rect.Left, Rect.Top), Radius, cpLeftTop, Color);
DrawAARoundCorner(ABitmap, Create2DIntVector(Rect.Right - Radius + 1, Rect.top), Radius, cpRightTop, Color);
DrawAARoundCorner(ABitmap, Create2DIntVector(Rect.Left, Rect.Bottom - Radius + 1), Radius, cpLeftBottom, Color);
DrawAARoundCorner(ABitmap, Create2DIntVector(Rect.Right - Radius + 1, Rect.Bottom - Radius + 1), Radius, cpRightBottom, Color);
{$ENDIF}
ABitmap.Canvas.Pen.Color := Color;
ABitmap.Canvas.pen.Style := psSolid;
// Draw*Line is protected against drawing outside the area
DrawVLine(ABitmap, Rect.Left, Rect.Top + Radius, Rect.bottom - Radius, Color);
DrawVLine(ABitmap, Rect.Right, Rect.Top + Radius, Rect.bottom - Radius, Color);
DrawHLine(ABitmap, Rect.Left + Radius, Rect.Right - Radius, Rect.Top, Color);
DrawHLine(ABitmap, Rect.Left + Radius, Rect.Right - Radius, Rect.Bottom, Color);
end;
class procedure TGUITools.DrawFitWText(ABitmap: TBitmap; x1, x2, y: integer;
const AText: string; TextColor: TColor; Align : TAlignment);
var
tw: integer;
s: string;
begin
with ABitmap.Canvas do
begin
Font.Color := TextColor;
s := AText;
tw := TextWidth(s);
if tw <= x2-x1+1 then
case Align of
taLeftJustify : TextOut(x1,y,AText);
taRightJustify : TextOut(x2-tw+1,y,AText);
taCenter : TextOut(x1 + ((x2-x1 - tw) div 2), y, AText);
end else
begin
while (s <> '') and (tw > x2-x1+1) do
begin
Delete(s, Length(s), 1);
tw := TextWidth(s+'...');
end;
if tw <= x2-x1+1 then
TextOut(x1, y, s+'...');
end;
end;
end;
class procedure TGUITools.DrawHLine(ACanvas: TCanvas; x1, x2, y: integer;
Color: TColor);
begin
EnsureOrder(x1, x2);
ACanvas.Pen.Color := Color;
ACanvas.MoveTo(x1, y);
ACanvas.LineTo(x2+1,y);
end;
class procedure TGUITools.DrawHLine(ACanvas: TCanvas; x1, x2, y: integer;
Color: TColor; ClipRect: T2DIntRect);
var
UseOrgClipRgn: boolean;
ClipRgn: HRGN;
OrgRgn: HRGN;
begin
// Store the original ClipRgn and set a new one
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
ClipRgn := CreateRectRgn(ClipRect.left, ClipRect.Top, ClipRect.Right+1, ClipRect.Bottom+1);
if UseOrgClipRgn then
CombineRgn(ClipRgn, ClipRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, ClipRgn);
DrawHLine(ACanvas, x1, x2, y, Color);
// Restores previous ClipRgn and removes used regions
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(ClipRgn);
end;
class procedure TGUITools.DrawImage(ABitmap: TBitmap; Imagelist: TImageList;
ImageIndex: integer; Point : T2DIntVector; ClipRect: T2DIntRect);
begin
DrawImage(ABitmap.Canvas, ImageList, ImageIndex, Point, ClipRect);
end;
class procedure TGUITools.DrawImage(ABitmap: TBitmap; Imagelist: TImageList;
ImageIndex: integer; Point: T2DIntVector);
begin
DrawImage(ABitmap.Canvas, ImageList, ImageIndex, Point);
end;
class procedure TGUITools.DrawImage(ACanvas: TCanvas; Imagelist: TImageList;
ImageIndex: integer; Point : T2DIntVector; ClipRect: T2DIntRect);
var
UseOrgClipRgn: Boolean;
OrgRgn: HRGN;
ClipRgn: HRGN;
//ImageIcon: TIcon; // wp: no longer needed -- see below
ImageBitmap: TBitmap;
begin
// Storing original ClipRgn and applying a new one
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
ClipRgn := CreateRectRgn(ClipRect.left, ClipRect.Top, ClipRect.Right+1, ClipRect.Bottom+1);
if UseOrgClipRgn then
CombineRgn(ClipRgn, ClipRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, ClipRgn);
ImageList.Draw(ACanvas, Point.X, Point.Y, ImageIndex);
(*
{ wp: Next part fixes issue https://sourceforge.net/p/lazarus-ccr/bugs/35/ }
ImageBitmap := TBitmap.Create;
ImageList.GetBitmap(ImageIndex, ImageBitmap);
ACanvas.Draw(Point.x, Point.y, ImageBitmap);
ImageBitmap.Free;
*)
{ wp: The following lines were removed and replaced by the "ImageBitmap" lines
above in order to fix the "handle leak" of
https://sourceforge.net/p/lazarus-ccr/bugs/35/
Not daring to touch the ImageList.Draw which would have worked as well. }
(*
// avoid exclusive draw. draw with local canvas itself.
//ImageList.Draw(ACanvas, Point.x, Point.y, ImageIndex);
{$IfDef LCLWin32}
ImageIcon := TIcon.Create;
ImageList.GetIcon(ImageIndex, ImageIcon);
ACanvas.Draw(Point.x, Point.y, ImageIcon);
ImageIcon.Free;
{$Else}
ImageBitmap := TBitmap.Create;
ImageList.GetBitmap(ImageIndex, ImageBitmap);
ACanvas.Draw(Point.x, Point.y, ImageBitmap);
ImageBitmap.Free;
{$EndIf}
*)
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(ClipRgn);
end;
class procedure TGUITools.DrawImage(ACanvas: TCanvas; Imagelist: TImageList;
ImageIndex: integer; Point : T2DIntVector; ClipRect: T2DIntRect;
AImageWidthAt96PPI, ATargetPPI: Integer; ACanvasFactor: Double);
var
UseOrgClipRgn: Boolean;
OrgRgn: HRGN;
ClipRgn: HRGN;
//ImageIcon: TIcon; // wp: no longer needed -- see below
ImageBitmap: TBitmap;
begin
// Storing original ClipRgn and applying a new one
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
ClipRgn := CreateRectRgn(ClipRect.left, ClipRect.Top, ClipRect.Right+1, ClipRect.Bottom+1);
if UseOrgClipRgn then
CombineRgn(ClipRgn, ClipRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, ClipRgn);
{$IF LCL_FULLVERSION >= 1090000}
ImageList.DrawForPPI(ACanvas, Point.X, Point.Y, ImageIndex,
AImageWidthAt96PPI, ATargetPPI, ACanvasFactor);
{$ELSE}
ImageList.Draw(ACanvas, Point.X, Point.Y, ImageIndex);
{$ENDIF}
(*
{ wp: Next part fixes issue https://sourceforge.net/p/lazarus-ccr/bugs/35/ }
ImageBitmap := TBitmap.Create;
ImageList.GetBitmap(ImageIndex, ImageBitmap);
ACanvas.Draw(Point.x, Point.y, ImageBitmap);
ImageBitmap.Free;
*)
{ wp: The following lines were removed and replaced by the "ImageBitmap" lines
above in order to fix the "handle leak" of
https://sourceforge.net/p/lazarus-ccr/bugs/35/
Not daring to touch the ImageList.Draw which would have worked as well. }
(*
// avoid exclusive draw. draw with local canvas itself.
//ImageList.Draw(ACanvas, Point.x, Point.y, ImageIndex);
{$IfDef LCLWin32}
ImageIcon := TIcon.Create;
ImageList.GetIcon(ImageIndex, ImageIcon);
ACanvas.Draw(Point.x, Point.y, ImageIcon);
ImageIcon.Free;
{$Else}
ImageBitmap := TBitmap.Create;
ImageList.GetBitmap(ImageIndex, ImageBitmap);
ACanvas.Draw(Point.x, Point.y, ImageBitmap);
ImageBitmap.Free;
{$EndIf}
*)
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(ClipRgn);
end;
class procedure TGUITools.DrawMarkedText(ACanvas: TCanvas; x, y: integer; const AText,
AMarkPhrase: string; TextColor : TColor; ClipRect: T2DIntRect; CaseSensitive: boolean);
var
UseOrgClipRgn: Boolean;
OrgRgn: HRGN = 0;
ClipRgn: HRGN = 0;
begin
// Store the original ClipRgn and set a new one
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
ClipRgn := CreateRectRgn(ClipRect.left, ClipRect.Top, ClipRect.Right+1, ClipRect.Bottom+1);
if UseOrgClipRgn then
CombineRgn(ClipRgn, ClipRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, ClipRgn);
DrawMarkedText(ACanvas, x, y, AText, AMarkPhrase, TextColor, CaseSensitive);
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(ClipRgn);
end;
class procedure TGUITools.DrawMarkedText(ACanvas: TCanvas; x, y: integer; const AText,
AMarkPhrase: string; TextColor : TColor; CaseSensitive : boolean);
var
TextToDraw: string;
BaseText: string;
MarkText: string;
MarkPos: Integer;
x1: integer;
s: string;
MarkTextLength: Integer;
begin
TextToDraw := AText;
if CaseSensitive then
begin
BaseText := AText;
MarkText := AMarkPhrase;
end else
begin
BaseText := AnsiUpperCase(AText);
MarkText := AnsiUpperCase(AMarkPhrase);
end;
x1 := x;
MarkTextLength := Length(MarkText);
ACanvas.Font.Color := TextColor;
ACanvas.Brush.Style := bsClear;
MarkPos := pos(MarkText, BaseText);
while MarkPos > 0 do
begin
if MarkPos > 1 then
begin
// Drawing text before highlighted
ACanvas.Font.Style := ACanvas.Font.Style - [fsBold];
s := copy(TextToDraw, 1, MarkPos-1);
ACanvas.TextOut(x1, y, s);
inc(x1, ACanvas.TextWidth(s)+1);
Delete(TextToDraw, 1, MarkPos-1);
Delete(BaseText, 1, MarkPos-1);
end;
// Drawing highlighted text
ACanvas.Font.Style := ACanvas.Font.Style + [fsBold];
s := copy(TextToDraw, 1, MarkTextLength);
ACanvas.TextOut(x1, y, s);
inc(x1, ACanvas.TextWidth(s)+1);
Delete(TextToDraw, 1, MarkTextLength);
Delete(BaseText, 1, MarkTextLength);
MarkPos := pos(MarkText, BaseText);
end;
if Length(BaseText) > 0 then
begin
ACanvas.Font.Style := ACanvas.Font.Style - [fsBold];
ACanvas.TextOut(x1, y, TextToDraw);
end;
end;
class procedure TGUITools.DrawImage(ACanvas: TCanvas; Imagelist: TImageList;
ImageIndex: integer; Point: T2DIntVector);
begin
ImageList.Draw(ACanvas, Point.x, Point.y, ImageIndex);
end;
class procedure TGUITools.DrawOutlinedText(ACanvas: TCanvas; x, y: integer;
const AText: string; TextColor, OutlineColor: TColor);
begin
with ACanvas do
begin
Brush.Style := bsClear;
Font.Color := OutlineColor;
TextOut(x-1, y-1, AText);
TextOut(x, y-1, AText);
TextOut(x+1, y-1, AText);
TextOut(x-1, y, AText);
TextOut(x+1, y, AText);
TextOut(x-1, y+1, AText);
TextOut(x, y+1, AText);
TextOut(x+1, y+1, AText);
Font.Color := TextColor;
TextOut(x, y, AText);
end;
end;
class procedure TGUITools.DrawOutlinedText(ACanvas: TCanvas; x, y: integer;
const AText: string; TextColor, OutlineColor: TColor; ClipRect: T2DIntRect);
var
WinAPIClipRect: TRect;
begin
WinAPIClipRect := ClipRect.ForWinAPI;
with ACanvas do
begin
Brush.Style := bsClear;
Font.Color := OutlineColor;
TextRect(WinAPIClipRect, x-1, y-1, AText);
TextRect(WinAPIClipRect, x, y-1, AText);
TextRect(WinAPIClipRect, x+1, y-1, AText);
TextRect(WinAPIClipRect, x-1, y, AText);
TextRect(WinAPIClipRect, x+1, y, AText);
TextRect(WinAPIClipRect, x-1, y+1, AText);
TextRect(WinAPIClipRect, x, y+1, AText);
TextRect(WinAPIClipRect, x+1, y+1, AText);
Font.Color := TextColor;
TextRect(WinAPIClipRect, x, y, AText);
end;
end;
class procedure TGUITools.DrawHLine(ABitmap: TBitmap; x1, x2, y: integer;
Color: TColor);
var
LineRect: T2DIntRect;
BitmapRect: T2DIntRect;
begin
if ABitmap.PixelFormat <> pf24Bit then
raise Exception.Create('TGUITools.DrawHLine: Bitmap must be in 24-bit mode');
EnsureOrder(x1, x2);
{$IFDEF EnhancedRecordSupport}
BitmapRect := T2DIntRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not BitmapRect.IntersectsWith(T2DIntRect.Create(x1, y, x2, y), LineRect) then
exit;
{$ELSE}
BitmapRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not BitmapRect.IntersectsWith(Create2DIntRect(x1, y, x2, y), LineRect) then
exit;
{$ENDIF}
ABitmap.Canvas.Pen.Color := Color;
ABitmap.Canvas.Pen.Style := psSolid;
ABitmap.Canvas.MoveTo(LineRect.Left, LineRect.Top);
ABitmap.canvas.LineTo(LineRect.Right+1, LineRect.Top);
end;
class procedure TGUITools.DrawHLine(ABitmap: TBitmap; x1, x2, y: integer;
Color: TColor; ClipRect: T2DIntRect);
var
OrgLineRect: T2DIntRect;
LineRect: T2DIntRect;
BitmapRect: T2DIntRect;
begin
if ABitmap.PixelFormat<>pf24bit then
raise Exception.Create('TGUITools.DrawHLine: Bitmap must be in 24-bit mode!');
EnsureOrder(x1, x2);
{$IFDEF EnhancedRecordSupport}
BitmapRect := T2DIntRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not BitmapRect.IntersectsWith(T2DIntRect.Create(x1, y, x2, y), OrgLineRect) then
exit;
{$ELSE}
BitmapRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not BitmapRect.IntersectsWith(Create2DIntRect(x1, y, x2, y), OrgLineRect) then
exit;
{$ENDIF}
if not OrgLineRect.IntersectsWith(ClipRect, LineRect) then
exit;
ABitmap.Canvas.Pen.Color := Color;
ABitmap.Canvas.Pen.Style := psSolid;
ABitmap.Canvas.MoveTo(LineRect.Left, LineRect.Top);
ABitmap.Canvas.LineTo(LineRect.Right+1, LineRect.Top);
end;
class procedure TGUITools.DrawOutlinedText(ABitmap: TBitmap; x, y: integer;
const AText: string; TextColor, OutlineColor: TColor; ClipRect: T2DIntRect);
var
WinAPIClipRect: TRect;
begin
WinAPIClipRect := ClipRect.ForWinAPI;
with ABitmap.canvas do
begin
Brush.Style := bsClear;
Font.Color := OutlineColor;
TextRect(WinAPIClipRect, x-1, y-1, AText);
TextRect(WinAPIClipRect, x, y-1, AText);
TextRect(WinAPIClipRect, x+1, y-1, AText);
TextRect(WinAPIClipRect, x-1, y, AText);
TextRect(WinAPIClipRect, x+1, y, AText);
TextRect(WinAPIClipRect, x-1, y+1, AText);
TextRect(WinAPIClipRect, x, y+1, AText);
TextRect(WinAPIClipRect, x+1, y+1, AText);
Font.Color := TextColor;
TextRect(WinAPIClipRect, x, y, AText);
end;
end;
class procedure TGUITools.DrawRegion(ACanvas: TCanvas; Region: HRGN;
Rect : T2DIntRect; ColorFrom, ColorTo: TColor; GradientKind: TBackgroundKind);
var
UseOrgClipRgn: Boolean;
OrgRgn: HRGN;
begin
// Store the original ClipRgn and set a new one
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
SelectClipRgn(ACanvas.Handle, Region);
FillGradientRectangle(ACanvas, Rect, ColorFrom, ColorTo, GradientKind);
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
end;
class procedure TGUITools.DrawRegion(ACanvas: TCanvas; Region: HRGN;
Rect : T2DIntRect; ColorFrom, ColorTo: TColor; GradientKind: TBackgroundKind;
ClipRect: T2DIntRect);
var
UseOrgClipRgn: boolean;
ClipRgn: HRGN;
OrgRgn: HRGN;
begin
// Store the original ClipRgn and set a new one
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
ClipRgn := CreateRectRgn(ClipRect.left, ClipRect.Top, ClipRect.Right+1, ClipRect.Bottom+1);
if UseOrgClipRgn then
CombineRgn(ClipRgn, ClipRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, ClipRgn);
DrawRegion(ACanvas, Region, Rect, ColorFrom, ColorTo, GradientKind);
// Restores previous ClipRgn and removes used regions
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(ClipRgn);
end;
class procedure TGUITools.DrawRoundRect(ACanvas: TCanvas; Rect: T2DIntRect;
Radius: integer; ColorFrom, ColorTo: TColor; GradientKind: TBackgroundKind;
ClipRect: T2DIntRect; LeftTopRound, RightTopRound, LeftBottomRound,
RightBottomRound: boolean);
var
UseOrgClipRgn: boolean;
ClipRgn: HRGN;
OrgRgn: HRGN;
begin
// Store the original ClipRgn and set a new one
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
ClipRgn := CreateRectRgn(
ClipRect.left, ClipRect.Top, ClipRect.Right+1, ClipRect.Bottom+1
);
if UseOrgClipRgn then
CombineRgn(ClipRgn, ClipRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, ClipRgn);
DrawRoundRect(ACanvas, Rect, Radius, ColorFrom, ColorTo, GradientKind,
LeftTopRound, RightTopRound, LeftBottomRound, RightBottomRound);
// Restores previous ClipRgn and removes used regions
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(ClipRgn);
end;
class procedure TGUITools.DrawText(ACanvas: TCanvas; x, y: integer;
const AText: string; TextColor: TColor);
begin
with ACanvas do
begin
Brush.Style := bsClear;
Font.Color := TextColor;
TextOut(x, y, AText);
end;
end;
class procedure TGUITools.DrawText(ACanvas: TCanvas; x, y: integer;
const AText: string; TextColor: TColor; ClipRect: T2DIntRect);
var
WinAPIClipRect: TRect;
begin
WinAPIClipRect := ClipRect.ForWinAPI;
with ACanvas do
begin
Brush.Style := bsClear;
Font.Color := TextColor;
TextRect(WinAPIClipRect, x, y, AText);
end;
end;
class procedure TGUITools.DrawRoundRect(ACanvas: TCanvas; Rect: T2DIntRect;
Radius: integer; ColorFrom, ColorTo: TColor; GradientKind: TBackgroundKind;
LeftTopRound, RightTopRound, LeftBottomRound, RightBottomRound: boolean);
var
RoundRgn: HRGN;
TmpRgn: HRGN;
OrgRgn: HRGN;
UseOrgClipRgn: Boolean;
begin
if Radius < 0 then
exit;
if Radius > 0 then
begin
//WriteLn('Radius: ', Radius, ' Rect.Width: ', Rect.Width, ' Rect.Height: ', Rect.Height);
// There's a bug in fpc that evaluates the expression below erroneous when using inline
// Radius = 3 and Rect.Width >= 128 and <= 261 will evaluate to true
{$ifdef FpcBugWorkAround}
if (CompareValue(Radius*2, Rect.width) > 0) and (CompareValue(Radius*2, Rect.Height) > 0) then
exit;
{$else}
if (Radius*2 > Rect.Width) or (Radius*2 > Rect.Height) then
exit;
{$endif}
// Zapamiêtywanie oryginalnego ClipRgn i ustawianie nowego
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
if not(LeftTopRound) and
not(RightTopRound) and
not(LeftBottomRound) and
not (RightBottomRound) then
begin
RoundRgn := CreateRectRgn(Rect.Left, Rect.Top, Rect.Right + 1, Rect.Bottom + 1);
end
else
begin
RoundRgn := CreateRoundRectRgn(Rect.Left, Rect.Top, Rect.Right +2, Rect.Bottom + 2, Radius*2, Radius*2);
if not LeftTopRound then
begin
TmpRgn := CreateRectRgn(Rect.Left, Rect.Top, Rect.Left + Radius, Rect.Top + Radius);
CombineRgn(RoundRgn, RoundRgn, TmpRgn, RGN_OR);
DeleteObject(TmpRgn);
end;
if not RightTopRound then
begin
TmpRgn := CreateRectRgn(Rect.Right - Radius + 1, Rect.Top, Rect.Right + 1, Rect.Top + Radius);
CombineRgn(RoundRgn, RoundRgn, TmpRgn, RGN_OR);
DeleteObject(TmpRgn);
end;
if not LeftBottomRound then
begin
TmpRgn := CreateRectRgn(Rect.Left, Rect.Bottom - Radius + 1, Rect.Left + Radius, Rect.Bottom + 1);
CombineRgn(RoundRgn, RoundRgn, TmpRgn, RGN_OR);
DeleteObject(TmpRgn);
end;
if not RightBottomRound then
begin
TmpRgn := CreateRectRgn(Rect.Right - Radius + 1, Rect.Bottom - Radius + 1, Rect.Right + 1, Rect.Bottom + 1);
CombineRgn(RoundRgn, RoundRgn, TmpRgn, RGN_OR);
DeleteObject(TmpRgn);
end;
end;
if UseOrgClipRgn then
CombineRgn(RoundRgn, RoundRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, RoundRgn);
end; // if Radius > 0
ColorFrom := ColorToRGB(ColorFrom);
ColorTo := ColorToRGB(ColorTo);
FillGradientRectangle(ACanvas, Rect, ColorFrom, ColorTo, GradientKind);
if Radius > 0 then
begin
// Restores previous ClipRgn and removes used regions
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(RoundRgn);
end;
end;
class procedure TGUITools.DrawOutlinedText(ABitmap: TBitmap; x, y: integer;
const AText: string; TextColor, OutlineColor: TColor);
begin
with ABitmap.Canvas do
begin
Brush.Style := bsClear;
Font.Color := OutlineColor;
TextOut(x-1, y-1, AText);
TextOut(x, y-1, AText);
TextOut(x+1, y-1, AText);
TextOut(x-1, y, AText);
TextOut(x+1, y, AText);
TextOut(x-1, y+1, AText);
TextOut(x, y+1, AText);
TextOut(x+1, y+1, AText);
Font.Color := TextColor;
TextOut(x, y, AText);
end;
end;
class procedure TGUITools.DrawText(ABitmap: TBitmap; x, y: integer;
const AText: string; TextColor: TColor; ClipRect: T2DIntRect);
var
WinAPIClipRect : TRect;
begin
WinAPIClipRect := ClipRect.ForWinAPI;
with ABitmap.Canvas do
begin
Brush.Style := bsClear;
Font.Color := TextColor;
TextRect(WinAPIClipRect, x, y, AText);
end;
end;
class procedure TGUITools.DrawFitWOutlinedText(ABitmap: TBitmap;
x1, x2, y: integer; const AText: string; TextColor, OutlineColor: TColor;
Align: TAlignment);
var
tw: integer;
s: string;
begin
with ABitmap.Canvas do
begin
s := AText;
tw := TextWidth(s) + 2;
if tw <= x2 - x1 + 1 then
case Align of
taLeftJustify:
TGUITools.DrawOutlinedText(ABitmap,x1, y, AText, TextColor, OutlineColor);
taRightJustify:
TGUITools.DrawOutlinedText(ABitmap,x2-tw+1, y, AText, TextColor, OutlineColor);
taCenter:
TGUITools.DrawOutlinedText(ABitmap,x1 + ((x2-x1 - tw) div 2), y, AText, TextColor, OutlineColor);
end
else
begin
while (s <> '') and (tw > x2 - x1 + 1) do
begin
Delete(s, Length(s), 1);
tw := TextWidth(s + '...') + 2;
end;
if tw <= x2 - x1 + 1 then
TGUITools.DrawOutlinedText(ABitmap, x1, y, s+'...', TextColor, OutlineColor);
end;
end;
end;
class procedure TGUITools.DrawFitWOutlinedText(ACanvas: TCanvas;
x1, x2, y: integer; const AText: string; TextColor, OutlineColor: TColor;
Align: TAlignment);
var
tw: integer;
s: string;
begin
with ACanvas do
begin
s := AText;
tw := TextWidth(s) + 2;
if tw <= x2 - x1 + 1 then
case Align of
taLeftJustify:
TGUITools.DrawOutlinedText(ACanvas,x1, y, AText, TextColor, OutlineColor);
taRightJustify:
TGUITools.DrawOutlinedText(ACanvas,x2-tw+1, y, AText, TextColor, OutlineColor);
taCenter:
TGUITools.DrawOutlinedText(ACanvas,x1 + (x2-x1 - tw) div 2, y, AText, TextColor, OutlineColor);
end
else
begin
while (s <> '') and (tw > x2 - x1 + 1) do
begin
Delete(s, Length(s), 1);
tw := TextWidth(s + '...') + 2;
end;
if tw <= x2 - x1 + 1 then
TGUITools.DrawOutlinedText(ACanvas, x1, y, s+'...', TextColor, OutlineColor);
end;
end;
end;
class procedure TGUITools.FillGradientRectangle(ACanvas: TCanvas;
Rect: T2DIntRect; ColorFrom: TColor; ColorTo: TColor;
GradientKind: TBackgroundKind);
var
Mesh: array of GRADIENTRECT;
GradientVertice: array of TRIVERTEX;
ConcaveColor: TColor;
begin
case GradientKind of
bkSolid:
begin
ACanvas.Brush.Style := bsSolid;
ACanvas.brush.color := ColorFrom;
ACanvas.fillrect(Rect.ForWinAPI);
end;
bkVerticalGradient, bkHorizontalGradient:
begin
SetLength(GradientVertice, 2);
with GradientVertice[0] do
begin
x := Rect.left;
y := Rect.top;
Red := GetRValue(ColorFrom) shl 8;
Green := GetGValue(ColorFrom) shl 8;
Blue := GetBValue(ColorFrom) shl 8;
Alpha := 255 shl 8;
end;
with GradientVertice[1] do
begin
x := Rect.Right + 1;
y := Rect.bottom + 1;
Red := GetRValue(ColorTo) shl 8;
Green := GetGValue(ColorTo) shl 8;
Blue := GetBValue(ColorTo) shl 8;
Alpha := 255 shl 8;
end;
SetLength(Mesh, 1);
Mesh[0].UpperLeft := 0;
Mesh[0].LowerRight := 1;
if GradientKind = bkVerticalGradient then
GradientFill(ACanvas.Handle, @GradientVertice[0], 2, @Mesh[0], 1, GRADIENT_FILL_RECT_V)
else
GradientFill(ACanvas.Handle, @GradientVertice[0], 2, @Mesh[0], 1, GRADIENT_FILL_RECT_H);
end;
bkConcave:
begin
ConcaveColor:=TColorTools.Brighten(ColorFrom, 20);
SetLength(GradientVertice, 4);
with GradientVertice[0] do
begin
x := Rect.left;
y := Rect.top;
Red := GetRValue(ColorFrom) shl 8;
Green := GetGValue(ColorFrom) shl 8;
Blue := GetBValue(ColorFrom) shl 8;
Alpha := 255 shl 8;
end;
with GradientVertice[1] do
begin
x := Rect.Right + 1;
y := Rect.Top + (Rect.height) div 4;
Red := GetRValue(ConcaveColor) shl 8;
Green := GetGValue(ConcaveColor) shl 8;
Blue := GetBValue(ConcaveColor) shl 8;
Alpha := 255 shl 8;
end;
with GradientVertice[2] do
begin
x := Rect.left;
y := Rect.Top + (Rect.height) div 4;
Red := GetRValue(ColorTo) shl 8;
Green := GetGValue(ColorTo) shl 8;
Blue := GetBValue(ColorTo) shl 8;
Alpha := 255 shl 8;
end;
with GradientVertice[3] do
begin
x := Rect.Right + 1;
y := Rect.bottom + 1;
Red := GetRValue(ColorFrom) shl 8;
Green := GetGValue(ColorFrom) shl 8;
Blue := GetBValue(ColorFrom) shl 8;
Alpha := 255 shl 8;
end;
SetLength(Mesh, 2);
Mesh[0].UpperLeft := 0;
Mesh[0].LowerRight := 1;
Mesh[1].UpperLeft := 2;
Mesh[1].LowerRight := 3;
GradientFill(ACanvas.Handle, @GradientVertice[0], 4, @Mesh[0], 2, GRADIENT_FILL_RECT_V);
end;
end;
end;
class procedure TGUITools.DrawFitWText(ACanvas: TCanvas; x1, x2, y: integer;
const AText: string; TextColor: TColor; Align: TAlignment);
var
tw: integer;
s: string;
begin
with ACanvas do
begin
Font.Color := TextColor;
s := AText;
tw := TextWidth(s);
// We draw if the text is changed
if tw <= x2 - x1 + 1 then
case Align of
taLeftJustify : TextOut(x1, y, AText);
taRightJustify : TextOut(x2-tw+1, y, AText);
taCenter : TextOut(x1 + (x2-x1 - tw) div 2, y, AText);
end
else
begin
while (s <> '') and (tw > x2 - x1 + 1) do
begin
Delete(s, Length(s), 1);
tw := TextWidth(s + '...');
end;
if tw <= x2 - x1 + 1 then
TextOut(x1, y, s + '...');
end;
end;
end;
class procedure TGUITools.RenderBackground(ABuffer: TBitmap;
Rect: T2DIntRect; Color1, Color2: TColor; BackgroundKind: TBackgroundKind);
var
TempRect: T2DIntRect;
begin
if ABuffer.PixelFormat<>pf24bit then
raise Exception.Create('TGUITools.RenderBackground: Bitmap must be in 24-bit mode');
if (Rect.Left > Rect.Right) or (Rect.Top > Rect.Bottom) then
exit;
// Both the FillRect method and the WinAPI gradient drawing are
// protected from drawing outside the canvas area.
case BackgroundKind of
bkSolid:
begin
ABuffer.Canvas.Brush.Color := Color1;
ABuffer.Canvas.Brush.Style := bsSolid;
ABuffer.Canvas.FillRect(Rect.ForWinAPI);
end;
bkVerticalGradient:
TGradientTools.VGradient(ABuffer.Canvas, Color1, Color2, Rect.ForWinAPI);
bkHorizontalGradient:
TGradientTools.HGradient(ABuffer.Canvas, Color1, Color2, Rect.ForWinAPI);
bkConcave:
begin
{$IFDEF EnhancedRecordSupport}
TempRect := T2DIntRect.Create(
{$ELSE}
TempRect.Create(
{$ENDIF}
Rect.Left, Rect.Top, Rect.Right, Rect.Top + (Rect.Bottom - Rect.Top) div 4
);
TGradientTools.VGradient(ABuffer.Canvas, Color1, TColorTools.Shade(Color1, Color2, 20), TempRect.ForWinAPI);
{$IFDEF EnhancedRecordSupport}
TempRect := T2DIntRect.Create(
{$ELSE}
TempRect.Create(
{$ENDIF}
Rect.Left, Rect.Top + (Rect.Bottom - Rect.Top) div 4 + 1, Rect.Right, Rect.Bottom
);
TGradientTools.VGradient(ABuffer.Canvas, Color2, Color1, TempRect.ForWinAPI);
end;
end; // case
end;
class procedure TGUITools.RestoreClipRgn(DC: HDC; OrgRgnExists: boolean;
var OrgRgn: HRGN);
begin
if OrgRgnExists then
SelectClipRgn(DC, OrgRgn) else
SelectClipRgn(DC, 0);
DeleteObject(OrgRgn);
end;
class procedure TGUITools.SaveClipRgn(DC: HDC; out OrgRgnExists: boolean;
out OrgRgn: HRGN);
var
i: integer;
begin
OrgRgn := CreateRectRgn(0, 0, 1, 1);
i := GetClipRgn(DC, OrgRgn);
OrgRgnExists := (i=1);
end;
class procedure TGUITools.DrawText(ABitmap: TBitmap; x, y: integer; const AText: string;
TextColor: TColor);
begin
with ABitmap.Canvas do
begin
Brush.Style := bsClear;
Font.Color:= TextColor;
TextOut(x, y, AText);
end;
end;
class procedure TGUITools.DrawVLine(ABitmap: TBitmap; x, y1, y2: integer;
Color: TColor);
var
LineRect: T2DIntRect;
BitmapRect: T2DIntRect;
begin
if ABitmap.PixelFormat <> pf24bit then
raise Exception.Create('TGUITools.DrawHLine: Bitmap must be in 24-bit mode!');
EnsureOrder(y1, y2);
{$IFDEF EnhancedRecordSupport}
BitmapRect := T2DIntRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not (BitmapRect.IntersectsWith(T2DIntRect.Create(x, y1, x, y2), LineRect)) then
exit;
{$ELSE}
BitmapRect.create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not (BitmapRect.IntersectsWith(Create2DIntRect(x, y1, x, y2), LineRect)) then
exit;
{$ENDIF}
ABitmap.Canvas.Pen.color := Color;
ABitmap.Canvas.Pen.style := psSolid;
ABitmap.Canvas.Moveto(LineRect.Left, LineRect.Top);
ABitmap.Canvas.Lineto(LineRect.Left, Linerect.Bottom+1);
end;
class procedure TGUITools.DrawVLine(ABitmap: TBitmap; x, y1, y2: integer;
Color: TColor; ClipRect: T2DIntRect);
var
OrgLineRect: T2DIntRect;
LineRect: T2DIntRect;
BitmapRect: T2DIntRect;
begin
if ABitmap.PixelFormat <> pf24bit then
raise Exception.Create('TGUITools.DrawHLine: Bitmap must be in 24-bit mode!');
EnsureOrder(y1, y2);
{$IFDEF EnhancedRecordSupport}
BitmapRect := T2DIntRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not(BitmapRect.IntersectsWith(T2DIntRect.Create(x, y1, x, y2), OrgLineRect)) then
exit;
{$ELSE}
BitmapRect.Create(0, 0, ABitmap.Width-1, ABitmap.Height-1);
if not(BitmapRect.IntersectsWith(Create2DIntRect(x, y1, x, y2), OrgLineRect)) then
exit;
{$ENDIF}
if not(OrgLineRect.IntersectsWith(ClipRect, LineRect)) then
exit;
ABitmap.Canvas.Pen.Color := Color;
ABitmap.Canvas.Pen.Style := psSolid;
ABitmap.Canvas.Moveto(LineRect.Left, LineRect.Top);
ABitmap.Canvas.Lineto(LineRect.Left, Linerect.Bottom+1);
end;
class procedure TGUITools.DrawVLine(ACanvas: TCanvas; x, y1, y2: integer;
Color: TColor);
begin
EnsureOrder(y1, y2);
ACanvas.Pen.Color := Color;
ACanvas.Moveto(x, y1);
ACanvas.Lineto(x, y2+1);
end;
class procedure TGUITools.DrawVLine(ACanvas: TCanvas; x, y1, y2: integer;
Color: TColor; ClipRect: T2DIntRect);
var
UseOrgClipRgn: boolean;
ClipRgn: HRGN;
OrgRgn: HRGN;
begin
// Store the original ClipRgn and set a new one
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
ClipRgn := CreateRectRgn(ClipRect.left, ClipRect.Top, ClipRect.Right+1, ClipRect.Bottom+1);
if UseOrgClipRgn then
CombineRgn(ClipRgn, ClipRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, ClipRgn);
DrawVLine(ACanvas, x, y1, y2, Color);
// Restores previous ClipRgn and removes used regions
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(ClipRgn);
end;
class procedure TGUITools.DrawAARoundFrame(ACanvas: TCanvas; Rect: T2DIntRect;
Radius: integer; Color: TColor);
begin
if Radius < 1 then
exit;
if (Radius > Rect.Width div 2) or (Radius > Rect.Height div 2) then
exit;
// DrawAARoundCorner is protected against drawing outside the area
{$IFDEF EnhancedRecordSupport}
DrawAARoundCorner(ACanvas, T2DIntVector.create(Rect.Left, Rect.Top), Radius, cpLeftTop, Color);
DrawAARoundCorner(ACanvas, T2DIntVector.create(Rect.Right - Radius + 1, Rect.Top), Radius, cpRightTop, Color);
DrawAARoundCorner(ACanvas, T2DIntVector.create(Rect.Left, Rect.Bottom - Radius + 1), Radius, cpLeftBottom, Color);
DrawAARoundCorner(ACanvas, T2DIntVector.create(Rect.Right - Radius + 1, Rect.Bottom - Radius + 1), Radius, cpRightBottom, Color);
{$ELSE}
DrawAARoundCorner(ACanvas, Create2DIntVector(Rect.Left, Rect.Top), Radius, cpLeftTop, Color);
DrawAARoundCorner(ACanvas, Create2DIntVector(Rect.Right - Radius + 1, Rect.Top), Radius, cpRightTop, Color);
DrawAARoundCorner(ACanvas, Create2DIntVector(Rect.Left, Rect.Bottom - Radius + 1), Radius, cpLeftBottom, Color);
DrawAARoundCorner(ACanvas, Create2DIntVector(Rect.Right - Radius + 1, Rect.Bottom - Radius + 1), Radius, cpRightBottom, Color);
{$ENDIF}
ACanvas.Pen.color := Color;
ACanvas.pen.style := psSolid;
// Draw * Line is protected against drawing outside the area
DrawVLine(ACanvas, Rect.Left, Rect.Top + Radius, Rect.Bottom - Radius, Color);
DrawVLine(ACanvas, Rect.Right, Rect.Top + Radius, Rect.Bottom - Radius, Color);
DrawHLine(ACanvas, Rect.Left + Radius, Rect.Right - Radius, Rect.Top, Color);
DrawHLine(ACanvas, Rect.Left + Radius, Rect.Right - Radius, Rect.Bottom, Color);
end;
class procedure TGUITools.DrawAARoundFrame(ACanvas: TCanvas; Rect: T2DIntRect;
Radius: integer; Color: TColor; ClipRect: T2DIntRect);
var
UseOrgClipRgn: boolean;
ClipRgn: HRGN;
OrgRgn: HRGN;
begin
// Store the original ClipRgn and set a new one
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
ClipRgn := CreateRectRgn(ClipRect.left, ClipRect.Top, ClipRect.Right+1, ClipRect.Bottom+1);
if UseOrgClipRgn then
CombineRgn(ClipRgn, ClipRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, ClipRgn);
DrawAARoundFrame(ACanvas, Rect, Radius, Color);
// Restores previous ClipRgn and removes used regions
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(ClipRgn);
end;
class procedure TGUITools.DrawDisabledImage(ABitmap: TBitmap;
Imagelist: TImageList; ImageIndex: integer; Point: T2DIntVector;
ClipRect: T2DIntRect);
begin
DrawDisabledImage(ABitmap.Canvas, ImageList, ImageIndex, Point, ClipRect);
end;
class procedure TGUITools.DrawDisabledImage(ABitmap: TBitmap;
Imagelist: TImageList; ImageIndex: integer; Point: T2DIntVector);
begin
DrawDisabledImage(ABitmap.Canvas, ImageList, ImageIndex, Point);
end;
class procedure TGUITools.DrawDisabledImage(ACanvas: TCanvas;
Imagelist: TImageList; ImageIndex: integer; Point: T2DIntVector;
ClipRect: T2DIntRect);
var
UseOrgClipRgn: Boolean;
OrgRgn: HRGN;
ClipRgn: HRGN;
DCStackPos : integer;
begin
// Store the original ClipRgn and set a new one
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
ClipRgn := CreateRectRgn(ClipRect.left, ClipRect.Top, ClipRect.Right+1, ClipRect.Bottom+1);
if UseOrgClipRgn then
CombineRgn(ClipRgn, ClipRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, ClipRgn);
// Hack fixes the bug in ImageList.Draw which does not restore the previous one /???
// Font color for canvas
DcStackPos := SaveDC(ACanvas.Handle);
ImageList.Draw(ACanvas, Point.x, Point.y, ImageIndex, false);
RestoreDC(ACanvas.Handle, DcStackPos);
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(ClipRgn);
end;
class procedure TGUITools.DrawDisabledImage(ACanvas: TCanvas;
Imagelist: TImageList; ImageIndex: integer; Point: T2DIntVector);
var
DCStackPos : integer;
begin
//todo: see if is necessary to save the DC
DcStackPos := SaveDC(ACanvas.Handle);
ImageList.Draw(ACanvas, Point.x, Point.y, ImageIndex, false);
RestoreDC(ACanvas.Handle, DcStackPos);
end;
class procedure TGUITools.DrawCheckbox(ACanvas:TCanvas; x,y: Integer;
AState: TCheckboxState; AButtonState:TSpkButtonState;
AStyle: TSpkCheckboxStyle; ClipRect:T2DIntRect);
var
UseOrgClipRgn: Boolean;
OrgRgn: HRGN;
ClipRgn: HRGN;
begin
SaveClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
ClipRgn := CreateRectRgn(ClipRect.left, ClipRect.Top, ClipRect.Right+1, ClipRect.Bottom+1);
if UseOrgClipRgn then
CombineRgn(ClipRgn, ClipRgn, OrgRgn, RGN_AND);
SelectClipRgn(ACanvas.Handle, ClipRgn);
DrawCheckbox(ACanvas, x,y, AState, AButtonState, AStyle);
RestoreClipRgn(ACanvas.Handle, UseOrgClipRgn, OrgRgn);
DeleteObject(ClipRgn);
end;
class procedure TGUITools.DrawCheckbox(ACanvas: TCanvas; x,y: Integer;
AState: TCheckboxState; AButtonState: TSpkButtonState;
AStyle: TSpkCheckboxStyle);
const
NOT_USED = tbCheckboxCheckedNormal;
const
UNTHEMED_FLAGS: array [TSpkCheckboxStyle, TCheckboxState] of Integer = (
(DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED, DFCS_BUTTONCHECK or DFCS_BUTTON3STATE),
(DFCS_BUTTONRADIO, DFCS_BUTTONRADIO or DFCS_CHECKED, DFCS_BUTTONRADIO or DFCS_BUTTON3STATE)
);
THEMED_FLAGS: array [TSpkCheckboxStyle, TCheckboxState, TSpkButtonState] of TThemedButton = (
( (tbCheckboxUncheckedNormal, tbCheckboxUncheckedHot, tbCheckboxUncheckedPressed, tbCheckboxUncheckedDisabled, NOT_USED),
(tbCheckboxCheckedNormal, tbCheckboxCheckedHot, tbCheckboxCheckedPressed, tbCheckboxCheckedDisabled, NOT_USED),
(tbCheckboxMixedNormal, tbCheckboxMixedHot, tbCheckboxMixedPressed, tbCheckboxMixedDisabled, NOT_USED)
),
( (tbRadioButtonUncheckedNormal, tbRadioButtonUncheckedHot, tbRadioButtonUncheckedPressed, tbRadioButtonUncheckedDisabled, NOT_USED),
(tbRadioButtonCheckedNormal, tbRadioButtonCheckedHot, tbRadioButtonCheckedPressed, tbRadioButtonCheckedDisabled, NOT_USED),
(tbRadioButtonCheckedNormal, tbRadioButtonCheckedHot, tbRadioButtonCheckedPressed, tbRadioButtonCheckedDisabled, NOT_USED)
)
);
var
R: TRect;
w: Integer;
sz: TSize;
te: TThemedElementDetails;
begin
if ThemeServices.ThemesEnabled then begin
te := ThemeServices.GetElementDetails(THEMED_FLAGS[AStyle, AState, AButtonState]);
sz := ThemeServices.GetDetailSize(te);
R := Bounds(x, y, sz.cx, sz.cy);
InflateRect(R, 1, 1);
ThemeServices.DrawElement(ACanvas.Handle, te, R);
end else begin
w := GetSystemMetrics(SM_CYMENUCHECK);
R := Bounds(x, y, w, w);
DrawFrameControl(
ACanvas.Handle, R, DFC_BUTTON, UNTHEMED_FLAGS[AStyle, AState]);
end;
end;
end.