mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-09 07:36:06 +02:00
customdrawn: Adds a good Android button implementation
git-svn-id: trunk@34044 -
This commit is contained in:
parent
8603783deb
commit
257af940cd
@ -6,7 +6,7 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
// RTL
|
// RTL
|
||||||
Classes, SysUtils, Types,
|
Classes, SysUtils, Types, Math,
|
||||||
// fpimage
|
// fpimage
|
||||||
fpcanvas, fpimgcanv, fpimage,
|
fpcanvas, fpimgcanv, fpimage,
|
||||||
// LCL -> Use only TForm, TWinControl, TCanvas and TLazIntfImage
|
// LCL -> Use only TForm, TWinControl, TCanvas and TLazIntfImage
|
||||||
@ -21,6 +21,14 @@ type
|
|||||||
TCDDrawerAndroid = class(TCDDrawerCommon)
|
TCDDrawerAndroid = class(TCDDrawerCommon)
|
||||||
private
|
private
|
||||||
bmpCheckbox, bmpCheckboxChecked: TBitmap;
|
bmpCheckbox, bmpCheckboxChecked: TBitmap;
|
||||||
|
// Draws a line alternating between two colors
|
||||||
|
procedure DrawAndroidAlternatedHorzLine(ADest: TCanvas; X1, X2,
|
||||||
|
Y: Integer; AColor1, AColor2: TColor);
|
||||||
|
// Draws 2 mixed gradients which alternate between one another on each pixel
|
||||||
|
procedure DrawAndroidMixedVertGradientFill(ADest: TCanvas; ARect: TRect;
|
||||||
|
AStart1, AStop1, AStart2, AStop2: TColor);
|
||||||
|
// Fills a rectangular area alternating between two pixels
|
||||||
|
procedure DrawAndroidMixedFill(ADest: TCanvas; ARect: TRect; AColor1, AColor2: TColor);
|
||||||
public
|
public
|
||||||
procedure CreateResources; override;
|
procedure CreateResources; override;
|
||||||
procedure LoadResources; override;
|
procedure LoadResources; override;
|
||||||
@ -49,9 +57,9 @@ type
|
|||||||
// Standard Tab
|
// Standard Tab
|
||||||
// ===================================
|
// ===================================
|
||||||
// TCDButton
|
// TCDButton
|
||||||
{ procedure DrawButton(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
|
procedure DrawButton(ADest: TCanvas; ASize: TSize;
|
||||||
AState: TCDControlState; AStateEx: TCDControlStateEx); override;
|
AState: TCDControlState; AStateEx: TCDButtonStateEx); override;
|
||||||
// TCDEdit
|
{ // TCDEdit
|
||||||
procedure DrawEditBackground(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
|
procedure DrawEditBackground(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
|
||||||
AState: TCDControlState; AStateEx: TCDEditStateEx); override;}
|
AState: TCDControlState; AStateEx: TCDEditStateEx); override;}
|
||||||
// TCDCheckBox
|
// TCDCheckBox
|
||||||
@ -64,6 +72,54 @@ implementation
|
|||||||
const
|
const
|
||||||
ANDROID_DPI = 'vldpi';
|
ANDROID_DPI = 'vldpi';
|
||||||
|
|
||||||
|
// Actually Android buttons are much more complex then this,
|
||||||
|
// but this approximation works well
|
||||||
|
ANDROID_BUTTON_CORNERS = $006B696B;
|
||||||
|
|
||||||
|
ANDROID_BUTTON_FIRST_LINE_A = $00F7F3F7;
|
||||||
|
ANDROID_BUTTON_FIRST_LINE_B = $00EFF3EF;
|
||||||
|
ANDROID_BUTTON_SECOND_LINE_A = $00EFF3EF;
|
||||||
|
ANDROID_BUTTON_SECOND_LINE_B = $00F7F3F7;
|
||||||
|
ANDROID_BUTTON_THIRD_LINE_A = $00EFEFEF;
|
||||||
|
ANDROID_BUTTON_THIRD_LINE_B = $00F7F3F7;
|
||||||
|
|
||||||
|
ANDROID_BUTTON_TOP_GRADIENT_A = $00EFEFEF;
|
||||||
|
ANDROID_BUTTON_TOP_GRADIENT_B = $00EFEBEF;
|
||||||
|
ANDROID_BUTTON_MIDDLE_GRADIENT_A = $00CBCECB;
|
||||||
|
ANDROID_BUTTON_MIDDLE_GRADIENT_B = $00CECFCE;
|
||||||
|
ANDROID_BUTTON_BOTTOM_GRADIENT_A = $00BDBABD;
|
||||||
|
ANDROID_BUTTON_BOTTOM_GRADIENT_B = $00BABDBA;
|
||||||
|
|
||||||
|
ANDROID_BUTTON_PREPRELAST_LINE_A = $00C6C3C6;
|
||||||
|
ANDROID_BUTTON_PREPRELAST_LINE_B = $00C6C3C6;
|
||||||
|
ANDROID_BUTTON_PRELAST_LINE_A = $00C6CBC6;
|
||||||
|
ANDROID_BUTTON_PRELAST_LINE_B = $00CECBCE;
|
||||||
|
ANDROID_BUTTON_LAST_LINE_A = $00D6D3D6;
|
||||||
|
ANDROID_BUTTON_LAST_LINE_B = $00D6D7D6;
|
||||||
|
|
||||||
|
// Sunken variants
|
||||||
|
|
||||||
|
ANDROID_BUTTON_SUNKEN_FIRST_LINE_A = $0066F366;
|
||||||
|
ANDROID_BUTTON_SUNKEN_FIRST_LINE_B = $0066F366;
|
||||||
|
ANDROID_BUTTON_SUNKEN_SECOND_LINE_A = $0066F366;
|
||||||
|
ANDROID_BUTTON_SUNKEN_SECOND_LINE_B = $0066F366;
|
||||||
|
ANDROID_BUTTON_SUNKEN_THIRD_LINE_A = $0066EF66;
|
||||||
|
ANDROID_BUTTON_SUNKEN_THIRD_LINE_B = $0066F366;
|
||||||
|
|
||||||
|
ANDROID_BUTTON_SUNKEN_TOP_GRADIENT_A = $0066EF66;
|
||||||
|
ANDROID_BUTTON_SUNKEN_TOP_GRADIENT_B = $0066EB66;
|
||||||
|
ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_A = $0033CE33;
|
||||||
|
ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_B = $0033CF33;
|
||||||
|
ANDROID_BUTTON_SUNKEN_BOTTOM_GRADIENT_A = $0000BA00;
|
||||||
|
ANDROID_BUTTON_SUNKEN_BOTTOM_GRADIENT_B = $0000BD00;
|
||||||
|
|
||||||
|
ANDROID_BUTTON_SUNKEN_PREPRELAST_LINE_A = $0000C300;
|
||||||
|
ANDROID_BUTTON_SUNKEN_PREPRELAST_LINE_B = $0000C300;
|
||||||
|
ANDROID_BUTTON_SUNKEN_PRELAST_LINE_A = $0000CB00;
|
||||||
|
ANDROID_BUTTON_SUNKEN_PRELAST_LINE_B = $0000CB00;
|
||||||
|
ANDROID_BUTTON_SUNKEN_LAST_LINE_A = $0000D300;
|
||||||
|
ANDROID_BUTTON_SUNKEN_LAST_LINE_B = $0000D700;
|
||||||
|
|
||||||
{procedure TCDButtonDrawerAndroid.DrawToIntfImage(ADest: TFPImageCanvas;
|
{procedure TCDButtonDrawerAndroid.DrawToIntfImage(ADest: TFPImageCanvas;
|
||||||
CDButton: TCDButton);
|
CDButton: TCDButton);
|
||||||
begin
|
begin
|
||||||
@ -111,6 +167,83 @@ initialization
|
|||||||
|
|
||||||
{ TCDDrawerAndroid }
|
{ TCDDrawerAndroid }
|
||||||
|
|
||||||
|
procedure TCDDrawerAndroid.DrawAndroidAlternatedHorzLine(ADest: TCanvas;
|
||||||
|
X1, X2, Y: Integer; AColor1, AColor2: TColor);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
for i := X1 to X2-1 do
|
||||||
|
begin
|
||||||
|
if i mod 2 = 0 then ADest.Pixels[i, Y] := AColor1
|
||||||
|
else ADest.Pixels[i, Y] := AColor2;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCDDrawerAndroid.DrawAndroidMixedVertGradientFill(ADest: TCanvas;
|
||||||
|
ARect: TRect; AStart1, AStop1, AStart2, AStop2: TColor);
|
||||||
|
var
|
||||||
|
RStart1, RStop1, RStart2, RStop2: Byte;
|
||||||
|
GStart1, GStop1, GStart2, GStop2: Byte;
|
||||||
|
BStart1, BStop1, BStart2, BStop2: Byte;
|
||||||
|
RDiff1, GDiff1, BDiff1: Integer;
|
||||||
|
RDiff2, GDiff2, BDiff2: Integer;
|
||||||
|
Count, I: Integer;
|
||||||
|
lColor1, lColor2: TColor;
|
||||||
|
begin
|
||||||
|
if IsRectEmpty(ARect) then Exit;
|
||||||
|
|
||||||
|
RedGreenBlue(ColorToRGB(AStart1), RStart1, GStart1, BStart1);
|
||||||
|
RedGreenBlue(ColorToRGB(AStop1), RStop1, GStop1, BStop1);
|
||||||
|
RedGreenBlue(ColorToRGB(AStart2), RStart2, GStart2, BStart2);
|
||||||
|
RedGreenBlue(ColorToRGB(AStop2), RStop2, GStop2, BStop2);
|
||||||
|
|
||||||
|
RDiff1 := RStop1 - RStart1;
|
||||||
|
GDiff1 := GStop1 - GStart1;
|
||||||
|
BDiff1 := BStop1 - BStart1;
|
||||||
|
|
||||||
|
RDiff2 := RStop2 - RStart2;
|
||||||
|
GDiff2 := GStop2 - GStart2;
|
||||||
|
BDiff2 := BStop2 - BStart2;
|
||||||
|
|
||||||
|
Count := ARect.Bottom - ARect.Top;
|
||||||
|
|
||||||
|
for I := 0 to Count-1 do
|
||||||
|
begin
|
||||||
|
lColor1 := RGBToColor(RStart1 + (i * RDiff1) div Count,
|
||||||
|
GStart1 + (i * GDiff1) div Count,
|
||||||
|
BStart1 + (i * BDiff1) div Count);
|
||||||
|
lColor2 := RGBToColor(RStart2 + (i * RDiff2) div Count,
|
||||||
|
GStart2 + (i * GDiff2) div Count,
|
||||||
|
BStart2 + (i * BDiff2) div Count);
|
||||||
|
|
||||||
|
// draw left to right, because LineTo does not draw last pixel
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, ARect.Left, ARect.Right, ARect.Top+I, lColor1, lColor2);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCDDrawerAndroid.DrawAndroidMixedFill(ADest: TCanvas; ARect: TRect;
|
||||||
|
AColor1, AColor2: TColor);
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
lColor1, lColor2: TColor;
|
||||||
|
begin
|
||||||
|
for I := 0 to (ARect.Bottom - ARect.Top)-1 do
|
||||||
|
begin
|
||||||
|
if i mod 2 = 0 then
|
||||||
|
begin
|
||||||
|
lColor1 := AColor1;
|
||||||
|
lColor2 := AColor2;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
lColor1 := AColor2;
|
||||||
|
lColor2 := AColor1;
|
||||||
|
end;
|
||||||
|
// draw left to right, because LineTo does not draw last pixel
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, ARect.Left, ARect.Right, ARect.Top+I, lColor1, lColor2);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TCDDrawerAndroid.CreateResources;
|
procedure TCDDrawerAndroid.CreateResources;
|
||||||
begin
|
begin
|
||||||
bmpCheckbox := TBitmap.Create;
|
bmpCheckbox := TBitmap.Create;
|
||||||
@ -177,6 +310,124 @@ begin
|
|||||||
// Don't draw anything, tickmarks are impressed into the general images
|
// Don't draw anything, tickmarks are impressed into the general images
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TCDDrawerAndroid.DrawButton(ADest: TCanvas; ASize: TSize;
|
||||||
|
AState: TCDControlState; AStateEx: TCDButtonStateEx);
|
||||||
|
var
|
||||||
|
Str: string;
|
||||||
|
lGlyphLeftSpacing: Integer = 0;
|
||||||
|
lTextOutPos: TPoint;
|
||||||
|
lGlyphCaptionHeight: Integer;
|
||||||
|
lColor: TColor;
|
||||||
|
lRect: TRect;
|
||||||
|
begin
|
||||||
|
// Background corners
|
||||||
|
lColor := AStateEx.ParentRGBColor;
|
||||||
|
ADest.Pixels[0, 0] := lColor;
|
||||||
|
ADest.Pixels[1, 0] := lColor;
|
||||||
|
ADest.Pixels[0, 1] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-1, 0] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-2, 0] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-1, 1] := lColor;
|
||||||
|
ADest.Pixels[0, ASize.cy-1] := lColor;
|
||||||
|
ADest.Pixels[1, ASize.cy-1] := lColor;
|
||||||
|
ADest.Pixels[0, ASize.cy-2] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-1, ASize.cy-1] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-2, ASize.cy-1] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-1, ASize.cy-2] := lColor;
|
||||||
|
|
||||||
|
// Darker corners
|
||||||
|
lColor := ANDROID_BUTTON_CORNERS;
|
||||||
|
ADest.Pixels[1, 1] := lColor;
|
||||||
|
ADest.Pixels[2, 0] := lColor;
|
||||||
|
ADest.Pixels[0, 2] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-3, 0] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-2, 1] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-1, 2] := lColor;
|
||||||
|
ADest.Pixels[0, ASize.cy-3] := lColor;
|
||||||
|
ADest.Pixels[1, ASize.cy-2] := lColor;
|
||||||
|
ADest.Pixels[2, ASize.cy-1] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-1, ASize.cy-3] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-2, ASize.cy-2] := lColor;
|
||||||
|
ADest.Pixels[ASize.cx-3, ASize.cy-1] := lColor;
|
||||||
|
|
||||||
|
// Button image
|
||||||
|
if csfSunken in AState then
|
||||||
|
begin
|
||||||
|
// Top lines
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 3, ASize.cx-3, 0, ANDROID_BUTTON_SUNKEN_FIRST_LINE_A, ANDROID_BUTTON_SUNKEN_FIRST_LINE_B);
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 2, ASize.cx-2, 1, ANDROID_BUTTON_SUNKEN_SECOND_LINE_A, ANDROID_BUTTON_SUNKEN_SECOND_LINE_B);
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 1, ASize.cx-1, 2, ANDROID_BUTTON_SUNKEN_THIRD_LINE_A, ANDROID_BUTTON_SUNKEN_THIRD_LINE_B);
|
||||||
|
|
||||||
|
// The central gradient
|
||||||
|
lRect := Bounds(0, 3, ASize.cx, (ASize.cy-6) div 3);
|
||||||
|
DrawAndroidMixedVertGradientFill(ADest, lRect, ANDROID_BUTTON_SUNKEN_TOP_GRADIENT_A,
|
||||||
|
ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_A, ANDROID_BUTTON_SUNKEN_TOP_GRADIENT_B, ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_B);
|
||||||
|
lRect := Bounds(0, 3+(ASize.cy-6) div 3, ASize.cx, (ASize.cy-6) div 3);
|
||||||
|
DrawAndroidMixedFill(ADest, lRect, ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_A, ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_B);
|
||||||
|
lRect := Bounds(0, 3+2*(ASize.cy-6) div 3, ASize.cx, (ASize.cy-6) div 3);
|
||||||
|
DrawAndroidMixedVertGradientFill(ADest, lRect, ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_A,
|
||||||
|
ANDROID_BUTTON_SUNKEN_BOTTOM_GRADIENT_A, ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_B, ANDROID_BUTTON_SUNKEN_BOTTOM_GRADIENT_B);
|
||||||
|
|
||||||
|
// Bottom lines
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 1, ASize.cx-1, ASize.cy-3, ANDROID_BUTTON_SUNKEN_PREPRELAST_LINE_A, ANDROID_BUTTON_SUNKEN_PREPRELAST_LINE_B);
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 2, ASize.cx-2, ASize.cy-2, ANDROID_BUTTON_SUNKEN_PRELAST_LINE_A, ANDROID_BUTTON_SUNKEN_PRELAST_LINE_B);
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 3, ASize.cx-3, ASize.cy-1, ANDROID_BUTTON_SUNKEN_LAST_LINE_A, ANDROID_BUTTON_SUNKEN_LAST_LINE_B);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// Top lines
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 3, ASize.cx-3, 0, ANDROID_BUTTON_FIRST_LINE_A, ANDROID_BUTTON_FIRST_LINE_B);
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 2, ASize.cx-2, 1, ANDROID_BUTTON_SECOND_LINE_A, ANDROID_BUTTON_SECOND_LINE_B);
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 1, ASize.cx-1, 2, ANDROID_BUTTON_THIRD_LINE_A, ANDROID_BUTTON_THIRD_LINE_B);
|
||||||
|
|
||||||
|
// The central gradient
|
||||||
|
lRect := Bounds(0, 3, ASize.cx, (ASize.cy-6) div 3);
|
||||||
|
DrawAndroidMixedVertGradientFill(ADest, lRect, ANDROID_BUTTON_TOP_GRADIENT_A,
|
||||||
|
ANDROID_BUTTON_MIDDLE_GRADIENT_A, ANDROID_BUTTON_TOP_GRADIENT_B, ANDROID_BUTTON_MIDDLE_GRADIENT_B);
|
||||||
|
lRect := Bounds(0, 3+(ASize.cy-6) div 3, ASize.cx, (ASize.cy-6) div 3);
|
||||||
|
DrawAndroidMixedFill(ADest, lRect, ANDROID_BUTTON_MIDDLE_GRADIENT_A, ANDROID_BUTTON_MIDDLE_GRADIENT_B);
|
||||||
|
lRect := Bounds(0, 3+2*(ASize.cy-6) div 3, ASize.cx, (ASize.cy-6) div 3);
|
||||||
|
DrawAndroidMixedVertGradientFill(ADest, lRect, ANDROID_BUTTON_MIDDLE_GRADIENT_A,
|
||||||
|
ANDROID_BUTTON_BOTTOM_GRADIENT_A, ANDROID_BUTTON_MIDDLE_GRADIENT_B, ANDROID_BUTTON_BOTTOM_GRADIENT_B);
|
||||||
|
|
||||||
|
// Bottom lines
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 1, ASize.cx-1, ASize.cy-3, ANDROID_BUTTON_PREPRELAST_LINE_A, ANDROID_BUTTON_PREPRELAST_LINE_B);
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 2, ASize.cx-2, ASize.cy-2, ANDROID_BUTTON_PRELAST_LINE_A, ANDROID_BUTTON_PRELAST_LINE_B);
|
||||||
|
DrawAndroidAlternatedHorzLine(ADest, 3, ASize.cx-3, ASize.cy-1, ANDROID_BUTTON_LAST_LINE_A, ANDROID_BUTTON_LAST_LINE_B);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if csfHasFocus in AState then
|
||||||
|
DrawFocusRect(ADest, Point(5, 5), Size(ASize.cx-10, ASize.cy-10));
|
||||||
|
|
||||||
|
// Position calculations
|
||||||
|
ADest.Font.Assign(AStateEx.Font);
|
||||||
|
Str := AStateEx.Caption;
|
||||||
|
lGlyphCaptionHeight := Max(ADest.TextHeight(Str), AStateEx.Glyph.Height);
|
||||||
|
lTextOutPos.X := (ASize.cx - ADest.TextWidth(Str) - AStateEx.Glyph.Width) div 2;
|
||||||
|
lTextOutPos.Y := (ASize.cy - lGlyphCaptionHeight) div 2;
|
||||||
|
lTextOutPos.X := Max(lTextOutPos.X, 5);
|
||||||
|
lTextOutPos.Y := Max(lTextOutPos.Y, 5);
|
||||||
|
|
||||||
|
// Button glyph
|
||||||
|
if not AStateEx.Glyph.Empty then
|
||||||
|
begin
|
||||||
|
ADest.Draw(lTextOutPos.X, lTextOutPos.Y, AStateEx.Glyph);
|
||||||
|
lGlyphLeftSpacing := AStateEx.Glyph.Width+5;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Button text
|
||||||
|
lTextOutPos.X := lTextOutPos.X + lGlyphLeftSpacing;
|
||||||
|
lTextOutPos.Y := (ASize.cy - ADest.TextHeight(Str)) div 2;
|
||||||
|
ADest.Brush.Style := bsClear;
|
||||||
|
ADest.Pen.Style := psSolid;
|
||||||
|
if csfSunken in AState then
|
||||||
|
begin
|
||||||
|
Inc(lTextOutPos.X);
|
||||||
|
Inc(lTextOutPos.Y);
|
||||||
|
end;
|
||||||
|
ADest.TextOut(lTextOutPos.X, lTextOutPos.Y, Str)
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TCDDrawerAndroid.DrawCheckBoxSquare(ADest: TCanvas; ADestPos: TPoint;
|
procedure TCDDrawerAndroid.DrawCheckBoxSquare(ADest: TCanvas; ADestPos: TPoint;
|
||||||
ASize: TSize; AState: TCDControlState; AStateEx: TCDControlStateEx);
|
ASize: TSize; AState: TCDControlState; AStateEx: TCDControlStateEx);
|
||||||
begin
|
begin
|
||||||
|
Loading…
Reference in New Issue
Block a user