2971 lines
80 KiB
ObjectPascal
2971 lines
80 KiB
ObjectPascal
|
{***************************************************}
|
||
|
{ }
|
||
|
{ FastReport v4.0 }
|
||
|
{ Things missing in FMX }
|
||
|
{ }
|
||
|
{ Copyright (c) 1998-2011 }
|
||
|
{ by Alexander Tzyganenko, }
|
||
|
{ Fast Reports Inc. }
|
||
|
{ }
|
||
|
{***************************************************}
|
||
|
|
||
|
unit FMX.frxFMX;
|
||
|
|
||
|
interface
|
||
|
|
||
|
{$I fmx.inc}
|
||
|
{$I frx.inc}
|
||
|
|
||
|
uses
|
||
|
System.SysUtils, System.Classes, System.UITypes, FMX.Types, FMX.Controls,
|
||
|
System.Types, System.UIConsts, FMX.ListBox, FMX.Objects, System.Math,
|
||
|
FMX.TreeView, FMX.Edit, FMX.Forms, FMX.Platform, System.Variants
|
||
|
{$IFDEF DELPHI18}
|
||
|
,FMX.StdCtrls
|
||
|
{$ENDIF}
|
||
|
{$IFDEF DELPHI19}
|
||
|
, FMX.TextLayout , FMX.Graphics
|
||
|
{$ENDIF}
|
||
|
{$IFDEF DELPHI20}
|
||
|
, System.Math.Vectors
|
||
|
{$ENDIF}
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
, Winapi.Windows, Winapi.WinSpool, Winapi.Messages
|
||
|
{$ENDIF}
|
||
|
{$IFDEF LINUX}
|
||
|
,FMUX.Api
|
||
|
{$ENDIF}
|
||
|
{$IFDEF MACOS}
|
||
|
, Macapi.CoreText, Macapi.CoreFoundation, MacApi.CocoaTypes, Macapi.Foundation, FMX.Canvas.Mac, MacApi.CoreGraphics, Macapi.AppKit
|
||
|
{$ENDIF}
|
||
|
{$IFDEF DELPHI28}
|
||
|
, FMX.BaseTypeAliases, FMX.FormTypeAliases
|
||
|
{$ENDIF};
|
||
|
|
||
|
const
|
||
|
DMBIN_AUTO = 7;
|
||
|
{$EXTERNALSYM DMBIN_AUTO}
|
||
|
DMPAPER_A4 = 9;
|
||
|
{$EXTERNALSYM DMPAPER_A4}
|
||
|
DMPAPER_USER = 256;
|
||
|
{$EXTERNALSYM DMPAPER_USER}
|
||
|
VK_F1 = vkF1;
|
||
|
{$EXTERNALSYM VK_F1}
|
||
|
poPortrait = TPrinterOrientation.poPortrait;
|
||
|
poLandscape = TPrinterOrientation.poLandscape;
|
||
|
fsBold = TFontStyle.fsBold;
|
||
|
fsItalic = TFontStyle.fsItalic;
|
||
|
fsUnderline = TFontStyle.fsUnderline;
|
||
|
fsStrikeout = TFontStyle.fsStrikeout;
|
||
|
mbLeft = TMouseButton.mbLeft;
|
||
|
mbRight = TMouseButton.mbRight;
|
||
|
alLeft = TAlignLayout.alLeft;
|
||
|
alClient = TAlignLayout.alClient;
|
||
|
taCenter = TTextAlign.taCenter;
|
||
|
wsMaximized = TWindowState.wsMaximized;
|
||
|
{$IFDEF LINUX}
|
||
|
DefFontName = 'Liberation Sans';
|
||
|
{$ELSE}
|
||
|
DefFontName = 'Arial';
|
||
|
{$ENDIF}
|
||
|
|
||
|
DefFontSize = 10;
|
||
|
frxDefPPIUnits = 72;
|
||
|
frxDefDPIUnits = 96;
|
||
|
|
||
|
{ WIN Paper consts for paper linkage }
|
||
|
FRX_DMPAPER_LETTER = 1;
|
||
|
FRX_DMPAPER_LETTERSMALL = 2;
|
||
|
FRX_DMPAPER_TABLOID = 3;
|
||
|
FRX_DMPAPER_LEDGER = 4;
|
||
|
FRX_DMPAPER_LEGAL = 5;
|
||
|
FRX_DMPAPER_STATEMENT = 6;
|
||
|
FRX_DMPAPER_EXECUTIVE = 7;
|
||
|
FRX_DMPAPER_A3 = 8;
|
||
|
FRX_DMPAPER_A4 = 9;
|
||
|
FRX_DMPAPER_A4SMALL = 10;
|
||
|
FRX_DMPAPER_A5 = 11;
|
||
|
FRX_DMPAPER_B4 = 12;
|
||
|
FRX_DMPAPER_B5 = 13;
|
||
|
FRX_DMPAPER_FOLIO = 14;
|
||
|
FRX_DMPAPER_QUARTO = 15;
|
||
|
FRX_DMPAPER_10X14 = 16;
|
||
|
FRX_DMPAPER_11X17 = 17;
|
||
|
FRX_DMPAPER_NOTE = 18;
|
||
|
FRX_DMPAPER_ENV_9 = 19;
|
||
|
FRX_DMPAPER_ENV_10 = 20;
|
||
|
FRX_DMPAPER_ENV_11 = 21;
|
||
|
FRX_DMPAPER_ENV_12 = 22;
|
||
|
FRX_DMPAPER_ENV_14 = 23;
|
||
|
FRX_DMPAPER_CSHEET = 24;
|
||
|
FRX_DMPAPER_DSHEET = 25;
|
||
|
FRX_DMPAPER_ESHEET = 26;
|
||
|
FRX_DMPAPER_ENV_DL = 27;
|
||
|
FRX_DMPAPER_ENV_C5 = 28;
|
||
|
FRX_DMPAPER_ENV_C3 = 29;
|
||
|
FRX_DMPAPER_ENV_C4 = 30;
|
||
|
FRX_DMPAPER_ENV_C6 = 31;
|
||
|
FRX_DMPAPER_ENV_C65 = 32;
|
||
|
FRX_DMPAPER_ENV_B4 = 33;
|
||
|
FRX_DMPAPER_ENV_B5 = 34;
|
||
|
FRX_DMPAPER_ENV_B6 = 35;
|
||
|
FRX_DMPAPER_ENV_ITALY = 36;
|
||
|
FRX_DMPAPER_ENV_MONARCH = 37;
|
||
|
FRX_DMPAPER_ENV_PERSONAL = 38;
|
||
|
FRX_DMPAPER_FANFOLD_US = 39;
|
||
|
FRX_DMPAPER_FANFOLD_STD_GERMAN = 40;
|
||
|
FRX_DMPAPER_FANFOLD_LGL_GERMAN = 41;
|
||
|
FRX_DMPAPER_ISO_B4 = 42;
|
||
|
FRX_DMPAPER_JAPANESE_POSTCARD = 43;
|
||
|
FRX_DMPAPER_9X11 = 44;
|
||
|
FRX_DMPAPER_10X11 = 45;
|
||
|
FRX_DMPAPER_15X11 = 46;
|
||
|
FRX_DMPAPER_ENV_INVITE = 47;
|
||
|
FRX_DMPAPER_RESERVED_48 = 48;
|
||
|
FRX_DMPAPER_RESERVED_49 = 49;
|
||
|
FRX_DMPAPER_LETTER_EXTRA = 50;
|
||
|
FRX_DMPAPER_LEGAL_EXTRA = 51;
|
||
|
FRX_DMPAPER_TABLOID_EXTRA = 52;
|
||
|
FRX_DMPAPER_A4_EXTRA = 53;
|
||
|
FRX_DMPAPER_LETTER_TRANSVERSE = 54;
|
||
|
FRX_DMPAPER_A4_TRANSVERSE = 55;
|
||
|
FRX_DMPAPER_LETTER_EXTRA_TRANSVERSE = 56;
|
||
|
FRX_DMPAPER_A_PLUS = 57;
|
||
|
FRX_DMPAPER_B_PLUS = 58;
|
||
|
FRX_DMPAPER_LETTER_PLUS = 59;
|
||
|
FRX_DMPAPER_A4_PLUS = 60;
|
||
|
FRX_DMPAPER_A5_TRANSVERSE = 61;
|
||
|
FRX_DMPAPER_B5_TRANSVERSE = 62;
|
||
|
FRX_DMPAPER_A3_EXTRA = 63;
|
||
|
FRX_DMPAPER_A5_EXTRA = 64;
|
||
|
FRX_DMPAPER_B5_EXTRA = 65;
|
||
|
FRX_DMPAPER_A2 = 66;
|
||
|
FRX_DMPAPER_A3_TRANSVERSE = 67;
|
||
|
FRX_DMPAPER_A3_EXTRA_TRANSVERSE = 68;
|
||
|
FRX_DMPAPER_DBL_JAPANESE_POSTCARD = 69;
|
||
|
FRX_DMPAPER_A6 = 70;
|
||
|
FRX_DMPAPER_JENV_KAKU2 = 71;
|
||
|
FRX_DMPAPER_JENV_KAKU3 = 72;
|
||
|
FRX_DMPAPER_JENV_CHOU3 = 73;
|
||
|
FRX_DMPAPER_JENV_CHOU4 = 74;
|
||
|
FRX_DMPAPER_LETTER_ROTATED = 75;
|
||
|
FRX_DMPAPER_A3_ROTATED = 76;
|
||
|
FRX_DMPAPER_A4_ROTATED = 77;
|
||
|
FRX_DMPAPER_A5_ROTATED = 78;
|
||
|
FRX_DMPAPER_B4_JIS_ROTATED = 79;
|
||
|
FRX_DMPAPER_B5_JIS_ROTATED = 80;
|
||
|
FRX_DMPAPER_JAPANESE_POSTCARD_ROTATED = 81;
|
||
|
FRX_DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED = 82;
|
||
|
FRX_DMPAPER_A6_ROTATED = 83;
|
||
|
FRX_DMPAPER_JENV_KAKU2_ROTATED = 84;
|
||
|
FRX_DMPAPER_JENV_KAKU3_ROTATED = 85;
|
||
|
FRX_DMPAPER_JENV_CHOU3_ROTATED = 86;
|
||
|
FRX_DMPAPER_JENV_CHOU4_ROTATED = 87;
|
||
|
FRX_DMPAPER_B6_JIS = 88;
|
||
|
FRX_DMPAPER_B6_JIS_ROTATED = 89;
|
||
|
FRX_DMPAPER_12X11 = 90;
|
||
|
FRX_DMPAPER_JENV_YOU4 = 91;
|
||
|
FRX_DMPAPER_JENV_YOU4_ROTATED = 92;
|
||
|
FRX_DMPAPER_P16K = 93;
|
||
|
FRX_DMPAPER_P32K = 94;
|
||
|
FRX_DMPAPER_P32KBIG = 95;
|
||
|
FRX_DMPAPER_PENV_1 = 96;
|
||
|
FRX_DMPAPER_PENV_2 = 97;
|
||
|
FRX_DMPAPER_PENV_3 = 98;
|
||
|
FRX_DMPAPER_PENV_4 = 99;
|
||
|
FRX_DMPAPER_PENV_5 = 100;
|
||
|
FRX_DMPAPER_PENV_6 = 101;
|
||
|
FRX_DMPAPER_PENV_7 = 102;
|
||
|
FRX_DMPAPER_PENV_8 = 103;
|
||
|
FRX_DMPAPER_PENV_9 = 104;
|
||
|
FRX_DMPAPER_PENV_10 = 105;
|
||
|
FRX_DMPAPER_P16K_ROTATED = 106;
|
||
|
FRX_DMPAPER_P32K_ROTATED = 107;
|
||
|
FRX_DMPAPER_P32KBIG_ROTATED = 108;
|
||
|
FRX_DMPAPER_PENV_1_ROTATED = 109;
|
||
|
FRX_DMPAPER_PENV_2_ROTATED = 110;
|
||
|
FRX_DMPAPER_PENV_3_ROTATED = 111;
|
||
|
FRX_DMPAPER_PENV_4_ROTATED = 112;
|
||
|
FRX_DMPAPER_PENV_5_ROTATED = 113;
|
||
|
FRX_DMPAPER_PENV_6_ROTATED = 114;
|
||
|
FRX_DMPAPER_PENV_7_ROTATED = 115;
|
||
|
FRX_DMPAPER_PENV_8_ROTATED = 116;
|
||
|
FRX_DMPAPER_PENV_9_ROTATED = 117;
|
||
|
FRX_DMPAPER_PENV_10_ROTATED = 118;
|
||
|
|
||
|
FRX_DMBIN_UPPER = 1;
|
||
|
FRX_DMBIN_ONLYONE = 1;
|
||
|
FRX_DMBIN_LOWER = 2;
|
||
|
FRX_DMBIN_MIDDLE = 3;
|
||
|
FRX_DMBIN_MANUAL = 4;
|
||
|
FRX_DMBIN_ENVELOPE = 5;
|
||
|
FRX_DMBIN_ENVMANUAL = 6;
|
||
|
FRX_DMBIN_AUTO = 7;
|
||
|
FRX_DMBIN_TRACTOR = 8;
|
||
|
FRX_DMBIN_SMALLFMT = 9;
|
||
|
FRX_DMBIN_LARGEFMT = 10;
|
||
|
FRX_DMBIN_LARGECAPACITY = 11;
|
||
|
FRX_DMBIN_CASSETTE = 14;
|
||
|
FRX_DMBIN_FORMSOURCE = 15;
|
||
|
|
||
|
type
|
||
|
{$IFDEF DELPHI28}
|
||
|
TStringsChangeOpHelper = record helper for TCustomListBox.TStringsChangeOp
|
||
|
const
|
||
|
tsoAdded = TCustomListBox.TStringsChangeOp.Added deprecated 'Use TCustomListBox.TStringsChangeOp.Added';
|
||
|
tsoDeleted = TCustomListBox.TStringsChangeOp.Deleted deprecated 'Use TCustomListBox.TStringsChangeOp.Deleted';
|
||
|
tsoClear = TCustomListBox.TStringsChangeOp.Clear deprecated 'Use TCustomListBox.TStringsChangeOp.Clear';
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
{ VCL TFont compatibility }
|
||
|
TfrxFont = class(TPersistent)
|
||
|
private
|
||
|
FName: String;
|
||
|
FSize: Single;
|
||
|
FPixelsPerInch: Single;
|
||
|
FStyle: TFontStyles;
|
||
|
FColor: TAlphaColor;
|
||
|
FOnChange: TNotifyEvent;
|
||
|
procedure SetName(const Value: string);
|
||
|
procedure SetSize(Value: Single);
|
||
|
procedure SetStyle(Value: TFontStyles);
|
||
|
procedure SetColor(Value: TAlphaColor);
|
||
|
procedure SetHeight(Value: Single);
|
||
|
procedure DoChange;
|
||
|
protected
|
||
|
function GetHeight: Single; overload;
|
||
|
public
|
||
|
constructor Create;
|
||
|
procedure Assign(Value: TfrxFont); reintroduce;
|
||
|
procedure AssignToFont(Value: TFont);
|
||
|
procedure AssignToCanvas(Canvas: TCanvas);
|
||
|
function GetHeight(Canvas: TCanvas): Single; overload;
|
||
|
function IsEqual(ToFont: TObject): Boolean;
|
||
|
published
|
||
|
property Name: String read FName write SetName;
|
||
|
property Size: Single read FSize write SetSize stored False;
|
||
|
property PixelsPerInch: Single read FPixelsPerInch write FPixelsPerInch;
|
||
|
property Style: TFontStyles read FStyle write SetStyle;
|
||
|
property Color: TAlphaColor read FColor write SetColor;
|
||
|
property Height: Single read GetHeight write SetHeight;
|
||
|
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
||
|
end;
|
||
|
|
||
|
TfrxImageList = class(TComponent)
|
||
|
private
|
||
|
FImages: TList;
|
||
|
FWidth: Integer;
|
||
|
FHeight: Integer;
|
||
|
function GetCount: Integer;
|
||
|
public
|
||
|
constructor Create(AOwner: TComponent); override;
|
||
|
destructor Destroy; override;
|
||
|
procedure Clear;
|
||
|
{$IFDEF DELPHI19}
|
||
|
procedure AddMasked(Bmp: FMX.Graphics.TBitmap; Color: TAlphaColor);
|
||
|
function Get(Index: Integer): FMX.Graphics.TBitmap;
|
||
|
{$ELSE}
|
||
|
procedure AddMasked(Bmp: FMX.Types.TBitmap; Color: TAlphaColor);
|
||
|
function Get(Index: Integer): FMX.Types.TBitmap;
|
||
|
{$ENDIF}
|
||
|
procedure Draw(Canvas: TCanvas; x, y: Single; Index: Integer);
|
||
|
property Width: Integer read FWidth write FWidth;
|
||
|
property Height: Integer read FHeight write FHeight;
|
||
|
property Count: Integer read GetCount;
|
||
|
end;
|
||
|
|
||
|
{$I frxFMX_PlatformsAttribute.inc}
|
||
|
TfrxToolButton = class(TSpeedButton)
|
||
|
private
|
||
|
{$IFDEF DELPHI19}
|
||
|
FBitmap: FMX.Graphics.TBitmap;
|
||
|
{$ELSE}
|
||
|
FBitmap: FMX.Types.TBitmap;
|
||
|
{$ENDIF}
|
||
|
FDown: Boolean;
|
||
|
{$IFDEF DELPHI19}
|
||
|
procedure SetBitmap(const Value: FMX.Graphics.TBitmap);
|
||
|
{$ELSE}
|
||
|
procedure SetBitmap(const Value: FMX.Types.TBitmap);
|
||
|
{$ENDIF}
|
||
|
protected
|
||
|
procedure DoMouseEnter; override;
|
||
|
procedure DoMouseLeave; override;
|
||
|
public
|
||
|
constructor Create(AOwner: TComponent); override;
|
||
|
destructor Destroy; override;
|
||
|
procedure DoPaint; override;
|
||
|
property Down: Boolean read FDown write FDown;
|
||
|
published
|
||
|
{$IFDEF DELPHI19}
|
||
|
property Bitmap: FMX.Graphics.TBitmap read FBitmap write SetBitmap;
|
||
|
{$ELSE}
|
||
|
property Bitmap: FMX.Types.TBitmap read FBitmap write SetBitmap;
|
||
|
{$ENDIF}
|
||
|
property Hint;
|
||
|
{$IFDEF Delphi17}
|
||
|
property TabOrder;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
TfrxToolSeparator = class(TControl)
|
||
|
public
|
||
|
procedure Paint; override;
|
||
|
{$IFDEF Delphi17}
|
||
|
published
|
||
|
property Position;
|
||
|
property Width;
|
||
|
property Height;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
TfrxToolGrip = class(TControl)
|
||
|
public
|
||
|
procedure Paint; override;
|
||
|
{$IFDEF Delphi17}
|
||
|
published
|
||
|
property Position;
|
||
|
property Width;
|
||
|
property Height;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
TfrxTreeViewItem = class(TTreeViewItem)
|
||
|
private
|
||
|
FButton: TCustomButton;
|
||
|
FCloseImageIndex: Integer;
|
||
|
FOpenImageIndex: Integer;
|
||
|
FImgPos: Single;
|
||
|
FData: TObject;
|
||
|
{$IFDEF DELPHI19}
|
||
|
function GetBitmap(): FMX.Graphics.TBitmap;
|
||
|
{$ELSE}
|
||
|
function GetBitmap(): FMX.Types.TBitmap;
|
||
|
{$ENDIF}
|
||
|
|
||
|
protected
|
||
|
procedure ApplyStyle; override;
|
||
|
public
|
||
|
constructor Create(AOwner: TComponent); override;
|
||
|
procedure Paint; override;
|
||
|
property CloseImageIndex: Integer read FCloseImageIndex write FCloseImageIndex;
|
||
|
property OpenImageIndex: Integer read FOpenImageIndex write FOpenImageIndex;
|
||
|
property Data: TObject read FData write FData;
|
||
|
end;
|
||
|
|
||
|
TfrxOnEditedEvent = procedure(Sender: TObject; Node: TfrxTreeViewItem; var S: String) of Object;
|
||
|
TfrxOnBeforeChangeEvent = procedure(Sender: TObject; OldNode: TfrxTreeViewItem; NewNode: TfrxTreeViewItem) of Object;
|
||
|
|
||
|
{$I frxFMX_PlatformsAttribute.inc}
|
||
|
TfrxTreeView = class(TTreeView)
|
||
|
private
|
||
|
{$IFDEF DELPHI19}
|
||
|
FPicBitmap: FMX.Graphics.TBitmap;
|
||
|
{$ELSE}
|
||
|
FPicBitmap: FMX.Types.TBitmap;
|
||
|
{$ENDIF}
|
||
|
FIconWidth: Integer;
|
||
|
FIconHeight: Integer;
|
||
|
FEditBox: TEdit;
|
||
|
FIsEditing: Boolean;
|
||
|
FEditable: Boolean;
|
||
|
FFreePicOnDelete: Boolean;
|
||
|
FOnEdited: TfrxOnEditedEvent;
|
||
|
FOnBeforeChange: TfrxOnBeforeChangeEvent;
|
||
|
FManualDragAndDrop: Boolean;
|
||
|
protected
|
||
|
procedure DoEditKeyDown(Sender: TObject; var Key: Word; var KeyChar: WideChar; Shift: TShiftState);
|
||
|
procedure DoExit; override;
|
||
|
procedure SetSelected(const Value: TTreeViewItem); override;
|
||
|
procedure DblClick; override;
|
||
|
procedure DoExitEdit (Sender: TObject);
|
||
|
procedure BeginAutoDrag; override;
|
||
|
public
|
||
|
constructor Create(AOwner: TComponent); override;
|
||
|
destructor Destroy; override;
|
||
|
procedure DoEdit();
|
||
|
procedure EndEdit(Accept: Boolean);
|
||
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
|
||
|
procedure KeyDown(var Key: Word; var KeyChar: WideChar; Shift: TShiftState); override;
|
||
|
procedure LoadResouces(Stream: TStream; IconWidth, IconHeight: Integer);
|
||
|
{$IFDEF DELPHI19}
|
||
|
property PicPitmap: FMX.Graphics.TBitmap read FPicBitmap write FPicBitmap;
|
||
|
{$ELSE}
|
||
|
property PicPitmap: FMX.Types.TBitmap read FPicBitmap write FPicBitmap;
|
||
|
{$ENDIF}
|
||
|
property IconWidth: Integer read FIconWidth write FIconWidth;
|
||
|
property IconHeight: Integer read FIconHeight write FIconHeight;
|
||
|
function GetBitmapRect(Index: Integer): TRectF;
|
||
|
procedure DragOver(const Data: TDragObject; const Point: TPointF; {$IFNDEF DELPHI20}var Accept: Boolean{$ELSE} var Operation: TDragOperation{$ENDIF}); override;
|
||
|
procedure DragDrop(const Data: TDragObject; const Point: TPointF); override;
|
||
|
function AddItem(Root: TFmxObject; Text: String): TfrxTreeViewItem;
|
||
|
{$IFDEF DELPHI19}
|
||
|
procedure SetImages(Bmp: FMX.Graphics.TBitmap);
|
||
|
{$ELSE}
|
||
|
procedure SetImages(Bmp: FMX.Types.TBitmap);
|
||
|
{$ENDIF}
|
||
|
property IsEditing: Boolean read FIsEditing;
|
||
|
property ManualDragAndDrop: Boolean read FManualDragAndDrop write FManualDragAndDrop;
|
||
|
published
|
||
|
property StyleLookup;
|
||
|
property CanFocus default True;
|
||
|
property DisableFocusEffect;
|
||
|
property TabOrder;
|
||
|
property AllowDrag default False;
|
||
|
property AlternatingRowBackground default False;
|
||
|
property ItemHeight;
|
||
|
{$IFNDEF Delphi17}
|
||
|
property HideSelectionUnfocused default False;
|
||
|
{$ENDIF}
|
||
|
property MultiSelect default False;
|
||
|
property ShowCheckboxes default False;
|
||
|
property Sorted default False;
|
||
|
property OnChange;
|
||
|
property OnChangeCheck;
|
||
|
property OnCompare;
|
||
|
property OnDragChange;
|
||
|
property OnEdited: TfrxOnEditedEvent read FOnEdited write FOnEdited;
|
||
|
property OnBeforeChange: TfrxOnBeforeChangeEvent read FOnBeforeChange write FOnBeforeChange;
|
||
|
property Editable: Boolean read FEditable write FEditable;
|
||
|
end;
|
||
|
|
||
|
TfrxListBoxItem = class(TListBoxItem)
|
||
|
private
|
||
|
FButton: TButton;
|
||
|
FCheck: TCheckBox;
|
||
|
FCheckVisible : Boolean;
|
||
|
function GetCheckVisible: Boolean;
|
||
|
procedure SetCheckVisible(const Value: Boolean);
|
||
|
procedure OnBtnClick(Sender: TObject);
|
||
|
protected
|
||
|
procedure ApplyStyle; override;
|
||
|
procedure FreeStyle; override;
|
||
|
public
|
||
|
constructor Create(AOwner: TComponent); override;
|
||
|
destructor Destroy; override;
|
||
|
property CheckVisible: Boolean read GetCheckVisible write SetCheckVisible;
|
||
|
end;
|
||
|
|
||
|
TfrxOnButtonClick = procedure (Sender: TObject; aButton: TObject; aItem: TfrxListBoxItem) of Object;
|
||
|
|
||
|
{$I frxFMX_PlatformsAttribute.inc}
|
||
|
TfrxListBox = class(TListBox)
|
||
|
private type
|
||
|
TfrxListBoxStrings = class(TStrings)
|
||
|
private
|
||
|
[Weak] FListBox: TCustomListBox;
|
||
|
procedure ReadData(Reader: TReader);
|
||
|
procedure WriteData(Writer: TWriter);
|
||
|
protected
|
||
|
procedure Put(Index: Integer; const S: string); override;
|
||
|
function Get(Index: Integer): string; override;
|
||
|
function GetCount: Integer; override;
|
||
|
function GetObject(Index: Integer): TObject; override;
|
||
|
procedure PutObject(Index: Integer; AObject: TObject); override;
|
||
|
procedure SetUpdateState(Updating: Boolean); override;
|
||
|
procedure DefineProperties(Filer: TFiler); override;
|
||
|
public
|
||
|
function Add(const S: string): Integer; override;
|
||
|
procedure Clear; override;
|
||
|
procedure Delete(Index: Integer); override;
|
||
|
procedure Exchange(Index1, Index2: Integer); override;
|
||
|
function IndexOf(const S: string): Integer; override;
|
||
|
procedure Insert(Index: Integer; const S: string); override;
|
||
|
end;
|
||
|
private
|
||
|
FManualDragAndDrop: Boolean;
|
||
|
FOnButtonClickEvnt: TfrxOnButtonClick;
|
||
|
FItems: TStrings;
|
||
|
FCheckBoxText: String;
|
||
|
FButtonText: String;
|
||
|
FShowButtons: Boolean;
|
||
|
function ItemsStored: Boolean;
|
||
|
procedure SetItems(const Value: TStrings);
|
||
|
protected
|
||
|
procedure BeginAutoDrag; override;
|
||
|
procedure DragEnd; override;
|
||
|
public
|
||
|
constructor Create(AOwner: TComponent); override;
|
||
|
destructor Destroy; override;
|
||
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
|
||
|
procedure DragOver(const Data: TDragObject; const Point: TPointF; {$IFNDEF DELPHI20}var Accept: Boolean{$ELSE} var Operation: TDragOperation{$ENDIF}); override;
|
||
|
procedure DragDrop(const Data: TDragObject; const Point: TPointF); override;
|
||
|
procedure DoButtonClick(aButton: TObject; aItem: TfrxListBoxItem);
|
||
|
procedure Assign(Source: TPersistent); override;
|
||
|
property ManualDragAndDrop: Boolean read FManualDragAndDrop write FManualDragAndDrop;
|
||
|
property Items: TStrings read FItems write SetItems stored ItemsStored;
|
||
|
published
|
||
|
property StyleLookup;
|
||
|
property CanFocus default True;
|
||
|
property DisableFocusEffect;
|
||
|
property TabOrder;
|
||
|
property AllowDrag default False;
|
||
|
property AlternatingRowBackground default False;
|
||
|
property ItemHeight;
|
||
|
property MultiSelect default False;
|
||
|
property ShowCheckboxes default False;
|
||
|
property Sorted default False;
|
||
|
property OnChange;
|
||
|
property OnChangeCheck;
|
||
|
property OnCompare;
|
||
|
property OnDragChange;
|
||
|
property ShowButtons: Boolean read FShowButtons write FShowButtons;
|
||
|
property CheckBoxText: String read FCheckBoxText write FCheckBoxText;
|
||
|
property ButtonText: String read FButtonText write FButtonText;
|
||
|
property OnButtonClick: TfrxOnButtonClick read FOnButtonClickEvnt write FOnButtonClickEvnt;
|
||
|
end;
|
||
|
|
||
|
TfrxStringList = class(TStringList)
|
||
|
private
|
||
|
FUseUnicode: Boolean;
|
||
|
protected
|
||
|
function CompareStrings(const S1, S2: string): Integer; override;
|
||
|
public
|
||
|
constructor Create; overload;
|
||
|
constructor Create(UseUnicode: Boolean); overload;
|
||
|
end;
|
||
|
|
||
|
type
|
||
|
{$IFDEF DELPHI19}
|
||
|
{ fake class - do not use instances of this canvas for Full draw , only Text draw ! }
|
||
|
TfrxFastCanvasLayer = class(TCanvas)
|
||
|
protected
|
||
|
FContext: THandle;
|
||
|
FCanvas: TCanvas;
|
||
|
function GetContext: THandle; virtual;
|
||
|
procedure SetContext(const Value: THandle); virtual;
|
||
|
procedure SetFont(const Value: TFont); virtual;
|
||
|
procedure SetCanvas(const Value: TCanvas); virtual;
|
||
|
function DoBeginScene({$IFNDEF DELPHI28}const{$ENDIF} AClipRects: PClipRects = nil; AContextHandle: THandle = 0): Boolean; override;
|
||
|
procedure DoEndScene; override;
|
||
|
{ empty }
|
||
|
{$IFDEF DELPHI21}
|
||
|
class function DoInitializeBitmap(const Width, Height: Integer; const Scale: Single; var PixelFormat: TPixelFormat): THandle; override;
|
||
|
class procedure DoFinalizeBitmap(var Bitmap: THandle); override;
|
||
|
class function DoMapBitmap(const Bitmap: THandle; const Access: TMapAccess; var Data: TBitmapData): Boolean; override;
|
||
|
class procedure DoUnmapBitmap(const Bitmap: THandle; var Data: TBitmapData); override;
|
||
|
function DoFillPolygon(const Points: TPolygon; const AOpacity: Single; const ABrush: TBrush): Boolean; override;
|
||
|
{$ELSE}
|
||
|
{$IFDEF DELPHI19}
|
||
|
class procedure DoInitializeBitmap(const Bitmap: FMX.Graphics.TBitmap); override;
|
||
|
class procedure DoFinalizeBitmap(const Bitmap: FMX.Graphics.TBitmap); override;
|
||
|
class function DoMapBitmap(const Bitmap: FMX.Graphics.TBitmap; const Access: TMapAccess; var Data: TBitmapData): Boolean; override;
|
||
|
class procedure DoUnmapBitmap(const Bitmap: FMX.Graphics.TBitmap; var Data: TBitmapData); override;
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
|
||
|
procedure DoFillRect(const ARect: TRectF; const AOpacity: Single; const ABrush: TBrush); override;
|
||
|
procedure DoFillPath(const APath: TPathData; const AOpacity: Single; const ABrush: TBrush); override;
|
||
|
procedure DoFillEllipse(const ARect: TRectF; const AOpacity: Single; const ABrush: TBrush); override;
|
||
|
{$IFDEF DELPHI19}
|
||
|
procedure DoDrawBitmap(const ABitmap: FMX.Graphics.TBitmap; const SrcRect, DstRect: TRectF; const AOpacity: Single;
|
||
|
const HighSpeed: Boolean = False); override;
|
||
|
{$ELSE}
|
||
|
procedure DoDrawBitmap(const ABitmap: FMX.Types.TBitmap; const SrcRect, DstRect: TRectF; const AOpacity: Single;
|
||
|
const HighSpeed: Boolean = False); override;
|
||
|
{$ENDIF}
|
||
|
procedure DoDrawLine(const APt1, APt2: TPointF; const AOpacity: Single; const ABrush: TStrokeBrush); override;
|
||
|
procedure DoDrawRect(const ARect: TRectF; const AOpacity: Single; const ABrush: TStrokeBrush); override;
|
||
|
procedure DoDrawPath(const APath: TPathData; const AOpacity: Single; const ABrush: TStrokeBrush); override;
|
||
|
procedure DoDrawEllipse(const ARect: TRectF; const AOpacity: Single; const ABrush: TStrokeBrush); override;
|
||
|
{ empty end }
|
||
|
public
|
||
|
constructor Create; virtual;
|
||
|
destructor Destroy; override;
|
||
|
procedure ClearCache; virtual;
|
||
|
procedure UpdateHandle(AParent: TFmxObject); virtual;
|
||
|
{ empty }
|
||
|
procedure Clear(const Color: TAlphaColor); override;
|
||
|
procedure ClearRect(const ARect: TRectF; const AColor: TAlphaColor = 0); override;
|
||
|
procedure IntersectClipRect(const ARect: TRectF); override;
|
||
|
procedure ExcludeClipRect(const ARect: TRectF); override;
|
||
|
function PtInPath(const APoint: TPointF; const APath: TPathData): Boolean; override;
|
||
|
{ empty end }
|
||
|
procedure FillText(const ARect: TRectF; const AText: string; const WordWrap: Boolean; const AOpacity: Single; const Flags: TFillTextFlags; const ATextAlign, AVTextAlign: TTextAlign); override;
|
||
|
procedure MeasureText(var ARect: TRectF; const AText: string; const WordWrap: Boolean; const Flags: TFillTextFlags; const ATextAlign, AVTextAlign: TTextAlign); override;
|
||
|
function CalcHeight(aText: String): Single; virtual;
|
||
|
function CalcWidth(aText: String): Single; virtual;
|
||
|
property Font: TFont write SetFont;
|
||
|
property Context: THandle read GetContext write SetContext;
|
||
|
property Canvas: TCanvas read FCanvas write SetCanvas;
|
||
|
end;
|
||
|
{$IFDEF MACoS}
|
||
|
TfrxFastCanvas = class(TfrxFastCanvasLayer)
|
||
|
private
|
||
|
FCurentFont: CTFontRef;
|
||
|
FFontCacheList: TStringList;
|
||
|
FFontTransformMatrix: CGAffineTransform;
|
||
|
FColorSpace: CGColorSpaceRef;
|
||
|
FOpacity: Single;
|
||
|
FText: String;
|
||
|
FTextAlign: TTextAlign;
|
||
|
FWordWrap: Boolean;
|
||
|
FFlags: TFillTextFlags;
|
||
|
FPath: CGMutablePathRef;
|
||
|
FTextHeight: Single;
|
||
|
FTextWidth: Single;
|
||
|
function CreateCTFont(const AFont: TFont): CTFontRef;
|
||
|
function GetCTFont(const AFont: TFont): CTFontRef;
|
||
|
function GetFontNameHash(const AFont: TFont): String;
|
||
|
function AddCTFontToList(const aNameFont: String; aFontRef: CTFontRef): Integer;
|
||
|
procedure ClearFontCache;
|
||
|
procedure SetFont(const Value: TFont); reintroduce;
|
||
|
procedure CreateFrame(Canvas: TCanvas; StringRef: CFStringRef; var AttributedS: CFMutableAttributedStringRef; var Frame: CTFrameRef);
|
||
|
procedure AddFontAttribute(AAttribute: CFMutableAttributedStringRef;
|
||
|
AFont: TFont; const AStart, ALength: Integer);
|
||
|
function CalcHeight(Frame: CTFrameRef): Single; reintroduce;
|
||
|
function CalcWidth(Frame: CTFrameRef): Single; reintroduce;
|
||
|
protected
|
||
|
function GetContext: THandle; override;
|
||
|
procedure SetCanvas(const Value: TCanvas); reintroduce;
|
||
|
public
|
||
|
constructor Create; override;
|
||
|
destructor Destroy; override;
|
||
|
procedure FillText(const ARect: TRectF; const AText: string; const WordWrap: Boolean; const AOpacity: Single; const Flags: TFillTextFlags; const ATextAlign, AVTextAlign: TTextAlign); override;
|
||
|
procedure MeasureText(var ARect: TRectF; const AText: string; const WordWrap: Boolean; const Flags: TFillTextFlags; const ATextAlign, AVTextAlign: TTextAlign); override;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
TfrxFastCanvas = class(TfrxFastCanvasLayer)
|
||
|
private
|
||
|
FFontCacheList: TStringList;
|
||
|
|
||
|
function GetFontNameHash(const AFont: TFont; WordWrap: Boolean; const Flags: TFillTextFlags; const ATextAlign: TTextAlign; const VTextAlign: TTextAlign): String;
|
||
|
procedure ClearFontCache;
|
||
|
protected
|
||
|
function GetContext: THandle; override;
|
||
|
public
|
||
|
constructor Create; override;
|
||
|
destructor Destroy; override;
|
||
|
procedure FillText(const ARect: TRectF; const AText: string; const WordWrap: Boolean; const AOpacity: Single; const Flags: TFillTextFlags; const ATextAlign, AVTextAlign: TTextAlign); override;
|
||
|
procedure MeasureText(var ARect: TRectF; const AText: string; const WordWrap: Boolean; const Flags: TFillTextFlags; const ATextAlign, AVTextAlign: TTextAlign); override;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
{$ELSE}
|
||
|
TfrxFastCanvasLayer = class(TCanvas)
|
||
|
protected
|
||
|
FContext: THandle;
|
||
|
FCanvas: TCanvas;
|
||
|
public
|
||
|
procedure ClearCache; virtual; abstract;
|
||
|
procedure UpdateHandle(AParent: TFmxObject); virtual;
|
||
|
property Context: THandle read FContext write FContext;
|
||
|
property Canvas: TCanvas read FCanvas write FCanvas;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
function GetLongHint(const Hint: string): string;
|
||
|
function GetShortHint(const Hint: string): string;
|
||
|
|
||
|
procedure FillFontsList(List: TStrings);
|
||
|
function GetComponentForm(Comp: TFmxObject): TCommonCustomForm;
|
||
|
procedure SetClipboard(const Value: String);
|
||
|
function GetClipboard: String;
|
||
|
{$IFDEF DELPHI19}
|
||
|
function CreateRotationMatrix(const Angle: Single): TMatrix;
|
||
|
function CreateScaleMatrix(const ScaleX, ScaleY: Single): TMatrix;
|
||
|
function CreateTranslateMatrix(const DX, DY: Single): TMatrix;
|
||
|
function MatrixMultiply(const M1, M2: TMatrix): TMatrix;
|
||
|
{$ENDIF}
|
||
|
|
||
|
{$IFDEF MACOS}
|
||
|
procedure ShellExecute(fName: String);
|
||
|
{$ENDIF}
|
||
|
|
||
|
function frxCompareText(s1: String; s2: String): Integer;
|
||
|
// procedure FillText(aLayout: TTextLayout; Canvas: TCanvas; const ARect: TRectF; const AText: string; const WordWrap: Boolean; const AOpacity: Single; const Flags: TFillTextFlags; const ATextAlign, AVTextAlign: TTextAlign);
|
||
|
// procedure MeasureText(aLayout: TTextLayout; Canvas: TCanvas; var ARect: TRectF; const AText: string{;
|
||
|
// const WordWrap: Boolean; const Flags: TFillTextFlags; const ATextAlign,
|
||
|
// AVTextAlign: TTextAlign});
|
||
|
implementation
|
||
|
|
||
|
uses FMX.frxClass, FMX.Consts;
|
||
|
|
||
|
const
|
||
|
IdentityMatrix: TMatrix = (m11: 1.0; m12: 0.0; m13: 0.0; m21: 0.0; m22: 1.0; m23: 0.0; m31: 0.0; m32: 0.0; m33: 1.0);
|
||
|
|
||
|
{$IFDEF MACOS}
|
||
|
const
|
||
|
kUCCollateComposeInsensitiveMask = 1 shl 1;
|
||
|
kUCCollateWidthInsensitiveMask = 1 shl 2;
|
||
|
kUCCollateCaseInsensitiveMask = 1 shl 3;
|
||
|
kUCCollateDiacritInsensitiveMask = 1 shl 4;
|
||
|
kUCCollatePunctuationSignificantMask = 1 shl 15;
|
||
|
kUCCollateDigitsOverrideMask = 1 shl 16;
|
||
|
kUCCollateDigitsAsNumberMask = 1 shl 17;
|
||
|
|
||
|
|
||
|
{$IFDEF UNDERSCOREIMPORTNAME}
|
||
|
_PFX = '_';
|
||
|
{$ELSE}
|
||
|
_PFX = '';
|
||
|
{$ENDIF}
|
||
|
|
||
|
{$EXTERNALSYM _PFX}
|
||
|
|
||
|
const
|
||
|
{$IFDEF MACOS64}
|
||
|
libUnicodeCore = '/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/CarbonCore';
|
||
|
{$ELSE}
|
||
|
libUnicodeCore = '/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/CarbonCore';
|
||
|
{$ENDIF}
|
||
|
|
||
|
|
||
|
var
|
||
|
collatorRef: Pointer;
|
||
|
collatorRefIgnoreCase: Pointer;
|
||
|
|
||
|
|
||
|
function UCCreateCollator(locale: Pointer; opVariant: PUInt32; options: UInt32; collatorRef: Pointer): OSStatus; cdecl; external libUnicodeCore name _PFX + 'UCCreateCollator';
|
||
|
function UCDisposeCollator(collatorRef: Pointer): OSStatus; cdecl; external libUnicodeCore name _PFX + 'UCDisposeCollator';
|
||
|
|
||
|
function UCCompareText(collatorRef: Pointer; text1Ptr: PWideChar; text1Length: UInt32; text2Ptr: PWideChar; text2Length: UInt32; equivalent: PBoolean; order: PInteger): OSStatus; cdecl; external libUnicodeCore name _PFX + 'UCCompareText';
|
||
|
|
||
|
procedure ShellExecute(fName: String);
|
||
|
var
|
||
|
wspace: NSWorkspace;
|
||
|
begin
|
||
|
wspace := TNSWorkspace.Create;
|
||
|
try
|
||
|
if FileExists(fName) then
|
||
|
wspace.openFile(NSSTR(fName));
|
||
|
finally
|
||
|
wspace.release;
|
||
|
end;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
var
|
||
|
frxDefaultPPI: Integer;
|
||
|
{$ENDIF}
|
||
|
|
||
|
function frxCompareText(s1: String; s2: String): Integer;
|
||
|
{$IFDEF MACOS}
|
||
|
begin
|
||
|
Result := -1;
|
||
|
try
|
||
|
UCCompareText(collatorRefIgnoreCase, PWideChar(s1), Length(s1), PWideChar(s2), Length(s2), nil, @Result);
|
||
|
finally
|
||
|
end;
|
||
|
end;
|
||
|
{$ELSE}
|
||
|
begin
|
||
|
Result := AnsiCompareText(s1, s2);
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
function frxCompareStr(const S1, S2: string): Integer;
|
||
|
{$IFDEF MACOS}
|
||
|
begin
|
||
|
Result := -1;
|
||
|
try
|
||
|
UCCompareText(collatorRef, PWideChar(s1), Length(s1), PWideChar(s2), Length(s2), nil, @Result);
|
||
|
finally
|
||
|
end;
|
||
|
end;
|
||
|
{$ELSE}
|
||
|
begin
|
||
|
Result := CompareStr(s1, s2);
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
type
|
||
|
THackCustomListBox = class(TCustomListBox);
|
||
|
function CreateScaleMatrix(const ScaleX, ScaleY: Single): TMatrix;
|
||
|
begin
|
||
|
Result := IdentityMatrix;
|
||
|
Result.m11 := ScaleX;
|
||
|
Result.m22 := ScaleY;
|
||
|
end;
|
||
|
|
||
|
|
||
|
function CreateTranslateMatrix(const DX, DY: Single): TMatrix;
|
||
|
begin
|
||
|
Result := IdentityMatrix;
|
||
|
Result.m31 := DX;
|
||
|
Result.m32 := DY;
|
||
|
end;
|
||
|
|
||
|
function CreateRotationMatrix(const Angle: Single): TMatrix;
|
||
|
var
|
||
|
cosine, sine: Extended;
|
||
|
begin
|
||
|
SinCos(Angle, sine, cosine);
|
||
|
|
||
|
Result.m11 := cosine;
|
||
|
Result.m12 := sine;
|
||
|
Result.m13 := 0;
|
||
|
Result.m21 := -sine;
|
||
|
Result.m22 := cosine;
|
||
|
Result.m23 := 0;
|
||
|
|
||
|
Result.m31 := 0;
|
||
|
Result.m32 := 0;
|
||
|
Result.m33 := 1;
|
||
|
end;
|
||
|
|
||
|
function MatrixMultiply(const M1, M2: TMatrix): TMatrix;
|
||
|
begin
|
||
|
Result.m11 := M1.m11 * M2.m11 + M1.m12 * M2.m21 + M1.m13 * M2.m31;
|
||
|
Result.m12 := M1.m11 * M2.m12 + M1.m12 * M2.m22 + M1.m13 * M2.m32;
|
||
|
Result.m13 := M1.m11 * M2.m13 + M1.m12 * M2.m23 + M1.m13 * M2.m33;
|
||
|
Result.m21 := M1.m21 * M2.m11 + M1.m22 * M2.m21 + M1.m23 * M2.m31;
|
||
|
Result.m22 := M1.m21 * M2.m12 + M1.m22 * M2.m22 + M1.m23 * M2.m32;
|
||
|
Result.m23 := M1.m21 * M2.m13 + M1.m22 * M2.m23 + M1.m23 * M2.m33;
|
||
|
Result.m31 := M1.m31 * M2.m11 + M1.m32 * M2.m21 + M1.m33 * M2.m31;
|
||
|
Result.m32 := M1.m31 * M2.m12 + M1.m32 * M2.m22 + M1.m33 * M2.m32;
|
||
|
Result.m33 := M1.m31 * M2.m13 + M1.m32 * M2.m23 + M1.m33 * M2.m33;
|
||
|
end;
|
||
|
{$IFDEF DELPHI19}
|
||
|
{$ENDIF}
|
||
|
|
||
|
function GetLongHint(const Hint: string): string;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
I := Pos('|', Hint);
|
||
|
if I = 0 then
|
||
|
Result := Hint else
|
||
|
Result := Copy(Hint, I + 1, Maxint);
|
||
|
end;
|
||
|
|
||
|
function GetShortHint(const Hint: string): string;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
I := Pos('|', Hint);
|
||
|
if I = 0 then
|
||
|
Result := Hint else
|
||
|
Result := Copy(Hint, 1, I - 1);
|
||
|
end;
|
||
|
|
||
|
procedure SetClipboard(const Value: String);
|
||
|
{$IFDEF Delphi17}
|
||
|
var
|
||
|
ClipService: IFMXClipboardService;
|
||
|
begin
|
||
|
if TPlatformServices.Current.SupportsPlatformService(IFMXClipboardService, IInterface(ClipService)) then
|
||
|
ClipService.SetClipboard(Value);
|
||
|
end;
|
||
|
{$ELSE}
|
||
|
begin
|
||
|
Platform.SetClipboard(Value);
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
function GetClipboard: String;
|
||
|
{$IFDEF Delphi17}
|
||
|
var
|
||
|
ClipService: IFMXClipboardService;
|
||
|
begin
|
||
|
if TPlatformServices.Current.SupportsPlatformService(IFMXClipboardService, IInterface(ClipService)) then
|
||
|
Result := ClipService.GetClipboard.ToString
|
||
|
else
|
||
|
Result := '';
|
||
|
end;
|
||
|
{$ELSE}
|
||
|
begin
|
||
|
Result := VarToStr(Platform.GetClipboard);
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
function EnumFontsProc(var LogFont: TLogFont; var TextMetric: TTextMetric;
|
||
|
FontType: DWORD; Data: LPARAM): Integer; stdcall;
|
||
|
begin
|
||
|
if(Data <> 0) then
|
||
|
if (TStrings(Data).IndexOf(LogFont.lfFaceName) < 0) then
|
||
|
TStringList(Data).Add(LogFont.lfFaceName);
|
||
|
Result := 1;
|
||
|
end;
|
||
|
|
||
|
procedure FillFontsList(List: TStrings);
|
||
|
var
|
||
|
dc: HDC;
|
||
|
sortedList: TStringList;
|
||
|
LFont: TLogFont;
|
||
|
|
||
|
begin
|
||
|
sortedList := TStringList.Create;
|
||
|
dc := GetDC(0);
|
||
|
try
|
||
|
FillChar(LFont, sizeof(LFont), 0);
|
||
|
LFont.lfCharset := DEFAULT_CHARSET;
|
||
|
EnumFontFamiliesEx(dc, LFont, @EnumFontsProc, LPARAM(sortedList), 0);
|
||
|
finally
|
||
|
ReleaseDC(0, dc);
|
||
|
end;
|
||
|
sortedList.Sort;
|
||
|
|
||
|
List.BeginUpdate;
|
||
|
List.Clear;
|
||
|
List.AddStrings(sortedList);
|
||
|
List.EndUpdate;
|
||
|
sortedList.Free;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
{$IFDEF LINUX}
|
||
|
procedure FillFontsList(List: TStrings);
|
||
|
var
|
||
|
sortedList: TStringList;
|
||
|
i, c: Integer;
|
||
|
begin
|
||
|
sortedList := TStringList.Create;
|
||
|
sortedList.BeginUpdate;
|
||
|
try
|
||
|
sortedList.Clear;
|
||
|
c := FmuxGetFontCount;
|
||
|
for i := 0 to c - 1 do
|
||
|
sortedList.Add(FmuxGetFontName(i));
|
||
|
finally
|
||
|
sortedList.EndUpdate;
|
||
|
end;
|
||
|
|
||
|
sortedList.Sort;
|
||
|
|
||
|
List.BeginUpdate;
|
||
|
List.Clear;
|
||
|
List.AddStrings(sortedList);
|
||
|
List.EndUpdate;
|
||
|
sortedList.Free;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
{$IFDEF MACOS}
|
||
|
var
|
||
|
kCTFontFamilyNameAttribute_: Pointer = nil;
|
||
|
|
||
|
function kCTFontFamilyNameAttribute: Pointer;
|
||
|
var
|
||
|
CTLib: HMODULE;
|
||
|
begin
|
||
|
if kCTFontFamilyNameAttribute_ = nil then
|
||
|
begin
|
||
|
CTLib := LoadLibrary(libCoreText);
|
||
|
kCTFontFamilyNameAttribute_ := Pointer(GetProcAddress(CTLib, PWideChar('kCTFontFamilyNameAttribute'))^);
|
||
|
FreeLibrary(CTLib);
|
||
|
end;
|
||
|
Result := kCTFontFamilyNameAttribute_;
|
||
|
end;
|
||
|
|
||
|
function ConvCFString(const Value: CFStringRef): String;
|
||
|
begin
|
||
|
if Assigned(Value) then
|
||
|
Result := string(TNSString.Wrap(Value).UTF8String)
|
||
|
else
|
||
|
Result := '';
|
||
|
end;
|
||
|
|
||
|
procedure FillFontsList(List: TStrings);
|
||
|
var
|
||
|
collection: CTFontCollectionRef;
|
||
|
arr: CFArrayRef;
|
||
|
fontDescr: CTFontDescriptorRef;
|
||
|
fontName: String;
|
||
|
i, arrnum: Integer;
|
||
|
sortedList: TStringList;
|
||
|
begin
|
||
|
sortedList := TStringList.Create;
|
||
|
sortedList.Sorted := True;
|
||
|
try
|
||
|
collection := CTFontCollectionCreateFromAvailableFonts(nil);
|
||
|
arr := CTFontCollectionCreateMatchingFontDescriptors(collection);
|
||
|
try
|
||
|
arrnum := CFArrayGetCount(arr);
|
||
|
for i := 0 to arrnum - 1 do
|
||
|
begin
|
||
|
fontDescr := CFArrayGetValueAtIndex(arr, i);
|
||
|
fontName := ConvCFString(CTFontDescriptorCopyAttribute(fontDescr, kCTFontFamilyNameAttribute));
|
||
|
if sortedList.IndexOf(fontName) = -1 then
|
||
|
sortedList.Add(fontName);
|
||
|
end;
|
||
|
finally
|
||
|
CFRelease(arr);
|
||
|
CFRelease(collection);
|
||
|
end;
|
||
|
except
|
||
|
sortedList.Add('Unable to retrieve fonts');
|
||
|
end;
|
||
|
|
||
|
List.BeginUpdate;
|
||
|
List.Clear;
|
||
|
List.AddStrings(sortedList);
|
||
|
List.EndUpdate;
|
||
|
sortedList.Free;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
{$IFDEF DELPHI19}
|
||
|
type
|
||
|
TTextLayoutHack = class(TTextLayout);
|
||
|
{$IFDEF MACOS}
|
||
|
TQuartzBitmap = class
|
||
|
private
|
||
|
FData: Pointer;
|
||
|
FContext: CGContextRef;
|
||
|
FImage: CGImageRef;
|
||
|
function GetImage: CGImageRef;
|
||
|
end;
|
||
|
TRGBFloat = packed record
|
||
|
r, g, b, a: single;
|
||
|
end;
|
||
|
|
||
|
function CGColor(const C: TAlphaColor; Opacity: single = 1): TRGBFloat;
|
||
|
var
|
||
|
cc: TAlphaColor;
|
||
|
begin
|
||
|
cc := MakeColor(C, Opacity);
|
||
|
Result.a := TAlphaColorRec(cc).a / $FF;
|
||
|
Result.r := TAlphaColorRec(cc).r / $FF;
|
||
|
Result.g := TAlphaColorRec(cc).g / $FF;
|
||
|
Result.b := TAlphaColorRec(cc).b / $FF;
|
||
|
end;
|
||
|
|
||
|
|
||
|
const
|
||
|
ItalicMatrix: CGAffineTransform = (
|
||
|
a: 1;
|
||
|
b: 0;
|
||
|
c: 0.176326981;
|
||
|
d: 1;
|
||
|
tx: 0;
|
||
|
ty: 0
|
||
|
);
|
||
|
|
||
|
function CreateFont(const AFont: TFont): CTFontRef;
|
||
|
var
|
||
|
FontRefCopy: CTFontRef;
|
||
|
m: PCGAffineTransform;
|
||
|
begin
|
||
|
m := nil;
|
||
|
Result := CTFontCreateWithName(CFSTR(AFont.Family), AFont.Size * 1, nil);
|
||
|
try
|
||
|
if TFontStyle.fsItalic in AFont.Style then
|
||
|
begin
|
||
|
FontRefCopy := CTFontCreateCopyWithSymbolicTraits(Result, 0, nil,
|
||
|
kCTFontItalicTrait, kCTFontItalicTrait);
|
||
|
if Assigned(FontRefCopy) then
|
||
|
begin
|
||
|
CFRelease(Result);
|
||
|
Result := FontRefCopy;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
m := @ItalicMatrix;
|
||
|
|
||
|
FontRefCopy := CTFontCreateWithName(CFSTR(AFont.Family), AFont.Size * 1, @ItalicMatrix);
|
||
|
if Assigned(FontRefCopy) then
|
||
|
begin
|
||
|
CFRelease(Result);
|
||
|
Result := FontRefCopy;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
if TFontStyle.fsBold in AFont.Style then
|
||
|
begin
|
||
|
FontRefCopy := CTFontCreateCopyWithSymbolicTraits(Result, 0, m,
|
||
|
kCTFontBoldTrait, kCTFontBoldTrait);
|
||
|
if Assigned(FontRefCopy) then
|
||
|
begin
|
||
|
CFRelease(Result);
|
||
|
Result := FontRefCopy;
|
||
|
end;
|
||
|
end;
|
||
|
except
|
||
|
CFRelease(Result);
|
||
|
end;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
|
||
|
function GetComponentForm(Comp: TFmxObject): TCommonCustomForm;
|
||
|
begin
|
||
|
Result := nil;
|
||
|
while (Comp.Parent <> nil) do
|
||
|
begin
|
||
|
if (Comp.Parent is TCommonCustomForm) then
|
||
|
begin
|
||
|
Result := Comp.Parent as TCommonCustomForm;
|
||
|
Exit;
|
||
|
end;
|
||
|
Comp := Comp.Parent;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{ TfrxFont }
|
||
|
|
||
|
constructor TfrxFont.Create;
|
||
|
begin
|
||
|
FName := DefFontName;
|
||
|
FSize := DefFontSize;
|
||
|
FColor := claBlack;
|
||
|
FPixelsPerInch := frxDefPPI;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFont.Assign(Value: TfrxFont);
|
||
|
begin
|
||
|
FName := Value.Name;
|
||
|
FSize := Value.Size;
|
||
|
FStyle := Value.Style;
|
||
|
FColor := Value.Color;
|
||
|
DoChange;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFont.AssignToFont(Value: TFont);
|
||
|
{$IFDEF Delphi25}
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
var
|
||
|
NewStyleExt: TFontStyleExt;
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
begin
|
||
|
Value.Family := FName;
|
||
|
Value.Size := FSize;
|
||
|
Value.Style := FStyle;
|
||
|
{$IFDEF Delphi25}
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
{ D2D campatibility with GDI+ name }
|
||
|
if Pos('NARROW', UpperCase(Name)) <> 0 then
|
||
|
begin
|
||
|
NewStyleExt := TFontStyleExt.Create(Value.StyleExt.Weight, Value.StyleExt.Slant, Value.StyleExt.Stretch, Value.Style);
|
||
|
NewStyleExt.Stretch := TFontStretch.Condensed;
|
||
|
Value.StyleExt := NewStyleExt;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
type
|
||
|
THackCanvas = class(TCanvas);
|
||
|
{$ENDIF}
|
||
|
|
||
|
procedure TfrxFont.AssignToCanvas(Canvas: TCanvas);
|
||
|
var
|
||
|
ScaleF: Single;
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
IsD2D: Boolean;
|
||
|
aScaleX: Single;
|
||
|
{$IFDEF Delphi25}
|
||
|
NewStyleExt: TFontStyleExt;
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
begin
|
||
|
Canvas.Font.Family := Name;
|
||
|
ScaleF := FPixelsPerInch / 72;
|
||
|
{ we need increase D2D font height a bit to make it look the same as in GDIp }
|
||
|
{ cause of this code - canvas implimentation hidden inside modules }
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
IsD2D := (CompareText(Canvas.ClassName, 'TCanvasD2D') = 0);
|
||
|
if IsD2D then
|
||
|
ScaleF := ScaleF + 1 / 72 * 5;
|
||
|
aScaleX := frxDefaultPPI / 96;
|
||
|
{$IFNDEF Delphi17}
|
||
|
if not IsD2D and Assigned(THackCanvas(Canvas).FBitmap) and (aScaleX > 1) then
|
||
|
{$ELSE}
|
||
|
if not IsD2D and Assigned(Canvas.Bitmap) and (aScaleX > 1) then
|
||
|
{$ENDIF}
|
||
|
ScaleF := ScaleF * aScaleX;
|
||
|
{$ENDIF}
|
||
|
Canvas.Font.Size := Size * ScaleF;
|
||
|
Canvas.Font.Style := Style;
|
||
|
Canvas.Fill.Color := Color;
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
{$IFDEF Delphi25}
|
||
|
{ D2D campatibility with GDI+ name }
|
||
|
if IsD2D and (Pos('NARROW', UpperCase(Name)) <> 0) then
|
||
|
begin
|
||
|
NewStyleExt := TFontStyleExt.Create(Canvas.Font.StyleExt.Weight, Canvas.Font.StyleExt.Slant, Canvas.Font.StyleExt.Stretch, Canvas.Font.Style);
|
||
|
NewStyleExt.Stretch := TFontStretch.Condensed;
|
||
|
Canvas.Font.StyleExt := NewStyleExt;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFont.DoChange;
|
||
|
begin
|
||
|
if Assigned(FOnChange) then
|
||
|
FOnChange(Self);
|
||
|
end;
|
||
|
|
||
|
function TfrxFont.GetHeight(Canvas: TCanvas): Single;
|
||
|
begin
|
||
|
// todo
|
||
|
Result := Size * FPixelsPerInch / 72;
|
||
|
end;
|
||
|
|
||
|
function TfrxFont.IsEqual(ToFont: TObject): Boolean;
|
||
|
begin
|
||
|
Result := (ToFont is TFont) and SameValue(Size * FPixelsPerInch / 72, TFont(ToFont).Size, 1E-2) and (Name = TFont(ToFont).Family) and
|
||
|
(Style = TFont(ToFont).Style);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFont.SetName(const Value: string);
|
||
|
begin
|
||
|
if FName <> Value then
|
||
|
begin
|
||
|
FName := Value;
|
||
|
DoChange;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFont.SetSize(Value: Single);
|
||
|
begin
|
||
|
if FSize <> Value then
|
||
|
begin
|
||
|
FSize := Value;
|
||
|
DoChange;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFont.SetStyle(Value: TFontStyles);
|
||
|
begin
|
||
|
if FStyle <> Value then
|
||
|
begin
|
||
|
FStyle := Value;
|
||
|
DoChange;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFont.SetColor(Value: TAlphaColor);
|
||
|
begin
|
||
|
if FColor <> Value then
|
||
|
begin
|
||
|
FColor := Value;
|
||
|
DoChange;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFont.SetHeight(Value: Single);
|
||
|
begin
|
||
|
Size := - Value * 72 / FPixelsPerInch;
|
||
|
end;
|
||
|
|
||
|
function TfrxFont.GetHeight: Single;
|
||
|
begin
|
||
|
Result := - Size * FPixelsPerInch / 72;
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ TfrxImageList }
|
||
|
|
||
|
constructor TfrxImageList.Create(AOwner: TComponent);
|
||
|
begin
|
||
|
inherited;
|
||
|
FImages := TList.Create;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxImageList.Destroy;
|
||
|
begin
|
||
|
FImages.Destroy;
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
|
||
|
procedure TfrxImageList.Clear;
|
||
|
begin
|
||
|
FImages.Clear;
|
||
|
end;
|
||
|
|
||
|
{$IFDEF DELPHI19}
|
||
|
procedure TfrxImageList.AddMasked(Bmp: FMX.Graphics.TBitmap; Color: TAlphaColor);
|
||
|
{$ELSE}
|
||
|
procedure TfrxImageList.AddMasked(Bmp: FMX.Types.TBitmap; Color: TAlphaColor);
|
||
|
{$ENDIF}
|
||
|
begin
|
||
|
FImages.Add(Bmp);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxImageList.Draw(Canvas: TCanvas; x, y: Single; Index: Integer);
|
||
|
begin
|
||
|
end;
|
||
|
|
||
|
function TfrxImageList.GetCount: Integer;
|
||
|
begin
|
||
|
Result := FImages.Count;
|
||
|
end;
|
||
|
|
||
|
{$IFDEF DELPHI19}
|
||
|
function TfrxImageList.Get(Index: Integer): FMX.Graphics.TBitmap;
|
||
|
begin
|
||
|
Result := FMX.Graphics.TBitmap(FImages[Index]);
|
||
|
end;
|
||
|
{$ELSE}
|
||
|
function TfrxImageList.Get(Index: Integer): FMX.Types.TBitmap;
|
||
|
begin
|
||
|
Result := FMX.Types.TBitmap(FImages[Index]);
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
{ TfrxToolButton }
|
||
|
|
||
|
constructor TfrxToolButton.Create(AOwner: TComponent);
|
||
|
begin
|
||
|
{$IFDEF DELPHI19}
|
||
|
FBitmap := FMX.Graphics.TBitmap.Create(0,0);
|
||
|
{$ELSE}
|
||
|
FBitmap := FMX.Types.TBitmap.Create(0,0);
|
||
|
{$ENDIF}
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxToolButton.Destroy;
|
||
|
begin
|
||
|
FBitmap.Free;
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxToolButton.DoMouseEnter;
|
||
|
begin
|
||
|
inherited;
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxToolButton.DoMouseLeave;
|
||
|
begin
|
||
|
inherited;
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxToolButton.DoPaint;
|
||
|
var
|
||
|
rect: TRectF;
|
||
|
bmpRect: TRectF;
|
||
|
oldM: TMatrix;
|
||
|
state: TCanvasSaveState;
|
||
|
begin
|
||
|
OldM := Canvas.Matrix;
|
||
|
State := Canvas.SaveState;
|
||
|
|
||
|
try
|
||
|
Canvas.SetMatrix(CreateTranslateMatrix(AbsoluteRect.Left, AbsoluteRect.Top));
|
||
|
rect := RectF(0.5, 0.5, Width - 0.5, Height - 0.5);
|
||
|
|
||
|
bmpRect.Top := Round((Self.Height - FBitmap.Height)/ 2);
|
||
|
bmpRect.Left := Round((Self.Width - FBitmap.Width) / 2);
|
||
|
bmpRect.Bottom := bmpRect.Top + FBitmap.Height;
|
||
|
bmpRect.Right := bmpRect.Left + FBitmap.Width;
|
||
|
|
||
|
if csDesigning in ComponentState then
|
||
|
begin
|
||
|
Canvas.Stroke.Color := claBlack;
|
||
|
Canvas.Stroke.Kind := TBrushKind.bkSolid;
|
||
|
{$IFDEF Delphi25}
|
||
|
Canvas.Stroke.Thickness := 2;
|
||
|
{$ELSE}
|
||
|
Canvas.StrokeThickness := 2;
|
||
|
{$ENDIF}
|
||
|
Canvas.DrawRect(RectF(0, 0, Width, Height), 1, 1, AllCorners, 1, TCornerType.ctBevel);
|
||
|
end;
|
||
|
|
||
|
if Enabled then
|
||
|
Canvas.DrawBitmap(FBitmap, RectF(0, 0, FBitmap.Width, FBitmap.Height), bmpRect, 1 )
|
||
|
else
|
||
|
Canvas.DrawBitmap(FBitmap, RectF(0, 0, FBitmap.Width, FBitmap.Height), bmpRect, 0.2 );
|
||
|
|
||
|
if IsMouseOver or IsPressed then
|
||
|
begin
|
||
|
Canvas.Stroke.Color := claBlack;
|
||
|
Canvas.Stroke.Kind := TBrushKind.bkSolid;
|
||
|
{$IFDEF Delphi25}
|
||
|
Canvas.Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
Canvas.StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
Canvas.Fill.Color := claBlack;
|
||
|
Canvas.Fill.Kind := TBrushKind.bkSolid;
|
||
|
Canvas.FillRect(rect, 1, 1, AllCorners, 0.1, TCornerType.ctInnerRound);
|
||
|
Canvas.DrawRect(rect, 1, 1, AllCorners, 0.3, TCornerType.ctInnerRound);
|
||
|
end;
|
||
|
{$IFNDEF DELPHI18}
|
||
|
if Text <> '' then
|
||
|
Canvas.FillText(RectF(0, 0, Width, Height), Text, False, 1, [], TTextAlign.taCenter);
|
||
|
{$ENDIF}
|
||
|
finally
|
||
|
Canvas.RestoreState(state);
|
||
|
Canvas.SetMatrix(OldM);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxToolSeparator.Paint;
|
||
|
begin
|
||
|
with Canvas do
|
||
|
begin
|
||
|
Stroke.Color := claGray;
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
|
||
|
if Self.Width > Self.Height then
|
||
|
begin
|
||
|
DrawLine(PointF(0, 0.5), PointF(Self.Width, 0.5), 1);
|
||
|
Stroke.Color := claWhite;
|
||
|
DrawLine(PointF(0, 1.5), PointF(Self.Width, 1.5), 1);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
DrawLine(PointF(0.5, 0), PointF(0.5, Self.Height), 1);
|
||
|
Stroke.Color := claWhite;
|
||
|
DrawLine(PointF(1.5, 0), PointF(1.5, Self.Height), 1);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxToolGrip.Paint;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
with Canvas do
|
||
|
begin
|
||
|
Fill.Kind := TBrushKind.bkSolid;
|
||
|
|
||
|
for i := 0 to 3 do
|
||
|
if Self.Width > Self.Height then
|
||
|
begin
|
||
|
Fill.Color := claGray;
|
||
|
FillRect(RectF(i * 4, 0, i * 4 + 2, 2), 0, 0, allCorners, 1);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Fill.Color := claGray;
|
||
|
FillRect(RectF(0, i * 4, 2, i * 4 + 2), 0, 0, allCorners, 1);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{ TfrxTreeViewItem }
|
||
|
|
||
|
procedure TfrxTreeViewItem.ApplyStyle;
|
||
|
var
|
||
|
B: TFmxObject;
|
||
|
Offset: Single;
|
||
|
begin
|
||
|
inherited;
|
||
|
B := FindStyleResource('button');
|
||
|
if (B <> nil) and (B is TCustomButton) then
|
||
|
begin
|
||
|
FButton := TCustomButton(B);
|
||
|
B := FindStyleResource('text');
|
||
|
Offset := 0;
|
||
|
if Self.TreeView is TfrxTreeView then
|
||
|
Offset := TfrxTreeView(Self.TreeView).IconWidth;
|
||
|
|
||
|
if (B <> nil) and (B is TText) then
|
||
|
{$IFDEF DELPHI18}
|
||
|
TText(B).Margins.Left := Offset;
|
||
|
{$ELSE}
|
||
|
TText(B).Padding.Left := Offset;
|
||
|
{$ENDIF}
|
||
|
FImgPos := FButton.Position.X + FButton.Width - 2;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
|
||
|
constructor TfrxTreeViewItem.Create(AOwner: TComponent);
|
||
|
begin
|
||
|
inherited;
|
||
|
FImgPos := 0;
|
||
|
FCloseImageIndex := -1;
|
||
|
FOpenImageIndex := -1;
|
||
|
end;
|
||
|
|
||
|
{$IFDEF DELPHI19}
|
||
|
function TfrxTreeViewItem.GetBitmap: FMX.Graphics.TBitmap;
|
||
|
{$ELSE}
|
||
|
function TfrxTreeViewItem.GetBitmap: FMX.Types.TBitmap;
|
||
|
{$ENDIF}
|
||
|
begin
|
||
|
Result := nil;
|
||
|
if TreeView is TfrxTreeView then
|
||
|
begin
|
||
|
Result := TfrxTreeView(TreeView).FPicBitmap;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeViewItem.Paint;
|
||
|
var
|
||
|
{$IFDEF DELPHI19}
|
||
|
Bmp: FMX.Graphics.TBitmap;
|
||
|
{$ELSE}
|
||
|
Bmp: FMX.Types.TBitmap;
|
||
|
{$ENDIF}
|
||
|
IconRect: TRectF;
|
||
|
Index: Integer;
|
||
|
begin
|
||
|
inherited Paint;
|
||
|
if IsExpanded then
|
||
|
Index := FOpenImageIndex
|
||
|
else
|
||
|
Index := FCloseImageIndex;
|
||
|
|
||
|
if Index = -1 then Exit;
|
||
|
|
||
|
|
||
|
Bmp := GetBitmap;
|
||
|
if TreeView is TfrxTreeView then
|
||
|
begin
|
||
|
IconRect := TfrxTreeView(TreeView).GetBitmapRect(Index);
|
||
|
end;
|
||
|
if (Bmp <> nil) and (FImgPos > 0)then
|
||
|
Canvas.DrawBitmap(Bmp, IconRect, RectF(16, 0, 32, 16), 1 );
|
||
|
end;
|
||
|
|
||
|
{ TfrxTreeView }
|
||
|
|
||
|
function TfrxTreeView.AddItem(Root: TFmxObject; Text: String): TfrxTreeViewItem;
|
||
|
begin
|
||
|
Result := TfrxTreeViewItem.Create(Root);
|
||
|
Result.Text := Text;
|
||
|
Root.AddObject(Result);
|
||
|
end;
|
||
|
|
||
|
constructor TfrxTreeView.Create(AOwner: TComponent);
|
||
|
begin
|
||
|
inherited;
|
||
|
FPicBitmap := nil;
|
||
|
FIconWidth := 16;
|
||
|
FIconHeight := 16;
|
||
|
FEditBox := TEdit.Create(Self);
|
||
|
FEditBox.Parent := Self;
|
||
|
FEditBox.Visible := False;
|
||
|
FEditBox.OnKeyDown := DoEditKeyDown;
|
||
|
FEditBox.OnEnter := DoExitEdit;
|
||
|
FIsEditing := False;
|
||
|
FEditable := False;
|
||
|
FFreePicOnDelete := False;
|
||
|
FManualDragAndDrop := False;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.DblClick;
|
||
|
begin
|
||
|
inherited;
|
||
|
DoEdit;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxTreeView.Destroy;
|
||
|
begin
|
||
|
if (FPicBitmap <> nil) and FFreePicOnDelete then
|
||
|
FPicBitmap.Free;
|
||
|
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.DoEdit;
|
||
|
var
|
||
|
r: TRectF;
|
||
|
begin
|
||
|
if (Selected = nil) or (not FEditable) then exit;
|
||
|
|
||
|
FEditBox.Text := Selected.Text;
|
||
|
r := Self.GetItemRect(Selected);
|
||
|
//p := Selected.LocalToAbsolute(PointF(Selected.Position.X, Selected.Position.Y));
|
||
|
FEditBox.SetBounds(r.Left, r.Top, r.Width, r.Height);
|
||
|
Selected.Visible := False;
|
||
|
FEditBox.Visible := True;
|
||
|
FEditBox.SetFocus;
|
||
|
FIsEditing := True;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.DoEditKeyDown(Sender: TObject; var Key: Word;
|
||
|
var KeyChar: WideChar; Shift: TShiftState);
|
||
|
begin
|
||
|
if Key = vkReturn then
|
||
|
EndEdit(True)
|
||
|
else if Key = vkEscape then
|
||
|
EndEdit(False);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.DoExit;
|
||
|
begin
|
||
|
inherited;
|
||
|
EndEdit(False);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.DoExitEdit(Sender: TObject);
|
||
|
begin
|
||
|
EndEdit(False);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.BeginAutoDrag;
|
||
|
var
|
||
|
{$IFDEF DELPHI19}
|
||
|
S: FMX.Graphics.TBitmap;
|
||
|
{$ELSE}
|
||
|
S: FMX.Types.TBitmap;
|
||
|
{$ENDIF}
|
||
|
|
||
|
begin
|
||
|
if (Selected = nil) or (Root = nil) then
|
||
|
Exit;
|
||
|
S := Selected.MakeScreenshot;
|
||
|
try
|
||
|
{$IFNDEF DELPHI20}
|
||
|
FRoot.BeginInternalDrag(Self, S);
|
||
|
{$ELSE}
|
||
|
Root.BeginInternalDrag(Self, S);
|
||
|
{$ENDIF}
|
||
|
finally
|
||
|
S.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.DragDrop(const Data: TDragObject; const Point: TPointF);
|
||
|
begin
|
||
|
//inherited;
|
||
|
// don't use TTreeView handlers
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.DragOver(const Data: TDragObject; const Point: TPointF;
|
||
|
{$IFNDEF DELPHI20}var Accept: Boolean{$ELSE} var Operation: TDragOperation{$ENDIF});
|
||
|
begin
|
||
|
//inherited;
|
||
|
//don't use TTreeView handlers
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.EndEdit(Accept: Boolean);
|
||
|
var
|
||
|
S: String;
|
||
|
begin
|
||
|
if (Selected = nil) or (FEditBox.Text = '') or not FIsEditing then exit;
|
||
|
FEditBox.Parent := Self;
|
||
|
if Accept then
|
||
|
begin
|
||
|
Selected.Text := FEditBox.Text;
|
||
|
S := Selected.Text;
|
||
|
if Assigned(FOnEdited) then
|
||
|
begin
|
||
|
FOnEdited(Self, TfrxTreeViewItem(Selected), S);
|
||
|
Selected.Text := S;
|
||
|
end;
|
||
|
end;
|
||
|
FEditBox.Visible := False;
|
||
|
Selected.Visible := True;
|
||
|
Self.SetFocus;
|
||
|
FIsEditing := False;
|
||
|
end;
|
||
|
|
||
|
function TfrxTreeView.GetBitmapRect(Index: Integer): TRectF;
|
||
|
var
|
||
|
ColCount, ColId, RowId: Integer;
|
||
|
begin
|
||
|
Result := RectF(0, 0, 0, 0);
|
||
|
if FPicBitmap = nil then Exit;
|
||
|
|
||
|
ColCount := FPicBitmap.Width div FIconWidth;
|
||
|
RowId := Index div ColCount;
|
||
|
ColId := Index mod ColCount;
|
||
|
Result := RectF(FIconWidth * ColId, FIconHeight * RowId, FIconWidth * ColId + FIconWidth, FIconHeight * RowId + FIconHeight);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.KeyDown(var Key: Word; var KeyChar: WideChar;
|
||
|
Shift: TShiftState);
|
||
|
begin
|
||
|
inherited;
|
||
|
if Key = vkReturn then
|
||
|
DoEdit;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.LoadResouces(Stream: TStream; IconWidth,
|
||
|
IconHeight: Integer);
|
||
|
begin
|
||
|
FIconWidth := IconWidth;
|
||
|
FIconHeight := IconHeight;
|
||
|
FFreePicOnDelete := True;
|
||
|
if FPicBitmap = nil then
|
||
|
{$IFDEF DELPHI19}
|
||
|
FPicBitmap := FMX.Graphics.TBitmap.CreateFromStream(Stream)
|
||
|
{$ELSE}
|
||
|
FPicBitmap := FMX.Types.TBitmap.CreateFromStream(Stream)
|
||
|
{$ENDIF}
|
||
|
else
|
||
|
FPicBitmap.LoadFromStream(Stream);
|
||
|
end;
|
||
|
|
||
|
|
||
|
|
||
|
procedure TfrxTreeView.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
|
||
|
Y: Single);
|
||
|
begin
|
||
|
EndEdit(True);
|
||
|
inherited;
|
||
|
{$IFDEF DELPHI18}
|
||
|
if (DragMode = TDragMode.dmManual) and FManualDragAndDrop then
|
||
|
BeginAutoDrag;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
{$IFDEF DELPHI19}
|
||
|
procedure TfrxTreeView.SetImages(Bmp: FMX.Graphics.TBitmap);
|
||
|
{$ELSE}
|
||
|
procedure TfrxTreeView.SetImages(Bmp: FMX.Types.TBitmap);
|
||
|
{$ENDIF}
|
||
|
begin
|
||
|
if (FPicBitmap <> nil) and FFreePicOnDelete then
|
||
|
FPicBitmap.Free;
|
||
|
FFreePicOnDelete := False;
|
||
|
FPicBitmap := Bmp;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxTreeView.SetSelected(const Value: TTreeViewItem);
|
||
|
begin
|
||
|
if Assigned(FOnBeforeChange) then
|
||
|
FOnBeforeChange(Self, TfrxTreeViewItem(Selected), TfrxTreeViewItem(Value));
|
||
|
EndEdit(True);
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
{$IFDEF DELPHI19}
|
||
|
procedure TfrxToolButton.SetBitmap(const Value: FMX.Graphics.TBitmap);
|
||
|
{$ELSE}
|
||
|
procedure TfrxToolButton.SetBitmap(const Value: FMX.Types.TBitmap);
|
||
|
{$ENDIF}
|
||
|
begin
|
||
|
FBitmap.Assign(Value);
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ TfrxListBox }
|
||
|
|
||
|
procedure TfrxListBox.Assign(Source: TPersistent);
|
||
|
var
|
||
|
i: Integer;
|
||
|
Item: TListBoxItem;
|
||
|
begin
|
||
|
if Source is TStrings then
|
||
|
begin
|
||
|
BeginUpdate;
|
||
|
try
|
||
|
Clear;
|
||
|
for i := 0 to TStrings(Source).Count - 1 do
|
||
|
begin
|
||
|
Item := TfrxListBoxItem.Create(Owner);
|
||
|
if i <> TStrings(Source).Count - 1 then
|
||
|
TfrxListBoxItem(Item).CheckVisible := True;
|
||
|
Item.Parent := Self;
|
||
|
Item.Text := TStrings(Source)[i];
|
||
|
end;
|
||
|
finally
|
||
|
EndUpdate;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.BeginAutoDrag;
|
||
|
var
|
||
|
{$IFDEF DELPHI19}
|
||
|
S: FMX.Graphics.TBitmap;
|
||
|
{$ELSE}
|
||
|
S: FMX.Types.TBitmap;
|
||
|
{$ENDIF}
|
||
|
|
||
|
begin
|
||
|
if (Selected = nil) or (Root = nil) then
|
||
|
Exit;
|
||
|
S := Selected.MakeScreenshot;
|
||
|
try
|
||
|
{$IFNDEF DELPHI20}
|
||
|
FRoot.BeginInternalDrag(Self, S);
|
||
|
{$ELSE}
|
||
|
Root.BeginInternalDrag(Self, S);
|
||
|
{$ENDIF}
|
||
|
finally
|
||
|
S.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxListBox.Create(AOwner: TComponent);
|
||
|
begin
|
||
|
inherited;
|
||
|
FManualDragAndDrop := False;
|
||
|
FShowButtons := False;
|
||
|
FItems := TfrxListBoxStrings.Create;
|
||
|
TfrxListBoxStrings(FItems).FListBox := Self;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxListBox.Destroy;
|
||
|
begin
|
||
|
inherited;
|
||
|
FreeAndNil(FItems);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.DoButtonClick(aButton: TObject; aItem: TfrxListBoxItem);
|
||
|
begin
|
||
|
if Assigned(OnButtonClick) then
|
||
|
OnButtonClick(Self, aButton, aItem);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.DragDrop(const Data: TDragObject; const Point: TPointF);
|
||
|
begin
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.DragEnd;
|
||
|
begin
|
||
|
inherited;
|
||
|
DragLeave;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.DragOver(const Data: TDragObject; const Point: TPointF;
|
||
|
{$IFNDEF DELPHI20}var Accept: Boolean{$ELSE} var Operation: TDragOperation{$ENDIF});
|
||
|
begin
|
||
|
if Assigned(OnDragOver) then
|
||
|
OnDragOver(Self, Data, Point, {$IFNDEF DELPHI20}Accept{$ELSE}Operation{$ENDIF});
|
||
|
//don't use TListBox handlers
|
||
|
end;
|
||
|
|
||
|
function TfrxListBox.ItemsStored: Boolean;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
for I := 0 to Count - 1 do
|
||
|
if ListItems[I].Stored then
|
||
|
Exit(False);
|
||
|
Result := True;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
|
||
|
Y: Single);
|
||
|
begin
|
||
|
inherited;
|
||
|
{$IFDEF DELPHI18}
|
||
|
if (DragMode = TDragMode.dmManual) and FManualDragAndDrop then
|
||
|
BeginAutoDrag;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.SetItems(const Value: TStrings);
|
||
|
begin
|
||
|
Items.Assign(Value);
|
||
|
end;
|
||
|
|
||
|
{ TfrxListBox.TfrxListBoxStrings }
|
||
|
|
||
|
function TfrxListBox.TfrxListBoxStrings.Add(const S: string): Integer;
|
||
|
var
|
||
|
Item: TListBoxItem;
|
||
|
begin
|
||
|
Item := TfrxListBoxItem.Create(FListBox);
|
||
|
try
|
||
|
Item.Text := S;
|
||
|
Item.Stored := False;
|
||
|
FListBox.AddObject(Item);
|
||
|
{$IFDEF DELPHI19}
|
||
|
{$IFDEF LINUX}
|
||
|
|
||
|
{$ELSE}
|
||
|
Item.StyleLookup := FListBox.DefaultItemStyles.ItemStyle;
|
||
|
THackCustomListBox(FListBox).DispatchStringsChangeEvent(S, TCustomListBox.TStringsChangeOp.tsoAdded);
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
Result := Item.Index;
|
||
|
except
|
||
|
Item.Free;
|
||
|
raise;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.TfrxListBoxStrings.Clear;
|
||
|
begin
|
||
|
if not (csDestroying in FListBox.ComponentState) then
|
||
|
FListBox.Clear;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.TfrxListBoxStrings.DefineProperties(Filer: TFiler);
|
||
|
function DoWrite: Boolean;
|
||
|
begin
|
||
|
if Filer.Ancestor <> nil then
|
||
|
begin
|
||
|
Result := True;
|
||
|
if Filer.Ancestor is TStrings then
|
||
|
Result := not Equals(TStrings(Filer.Ancestor))
|
||
|
end
|
||
|
else
|
||
|
Result := Count > 0;
|
||
|
end;
|
||
|
begin
|
||
|
Filer.DefineProperty('Strings', ReadData, WriteData, DoWrite);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.TfrxListBoxStrings.Delete(Index: Integer);
|
||
|
var
|
||
|
Item: TListBoxItem;
|
||
|
begin
|
||
|
Item := FListBox.ListItems[Index];
|
||
|
if Assigned(Item) then
|
||
|
begin
|
||
|
{$IFDEF DELPHI19}
|
||
|
if Item = FListBox.ItemDown then
|
||
|
FListBox.ItemDown := nil;
|
||
|
{$ENDIF}
|
||
|
FListBox.RemoveObject(Item);
|
||
|
Item.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.TfrxListBoxStrings.Exchange(Index1, Index2: Integer);
|
||
|
begin
|
||
|
FListBox.Exchange(FListBox.ItemByIndex(Index1), FListBox.ItemByIndex(Index2));
|
||
|
|
||
|
end;
|
||
|
|
||
|
function TfrxListBox.TfrxListBoxStrings.Get(Index: Integer): string;
|
||
|
begin
|
||
|
Result := FListBox.ListItems[Index].Text;
|
||
|
end;
|
||
|
|
||
|
function TfrxListBox.TfrxListBoxStrings.GetCount: Integer;
|
||
|
begin
|
||
|
Result := FListBox.Count;
|
||
|
end;
|
||
|
|
||
|
function TfrxListBox.TfrxListBoxStrings.GetObject(Index: Integer): TObject;
|
||
|
begin
|
||
|
Result := FListBox.ListItems[Index].Data;
|
||
|
end;
|
||
|
|
||
|
function TfrxListBox.TfrxListBoxStrings.IndexOf(const S: string): Integer;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
for I := 0 to FListBox.Count - 1 do
|
||
|
if SameText(FListBox.ListItems[I].Text, S) then
|
||
|
Exit(I);
|
||
|
Result := -1;
|
||
|
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.TfrxListBoxStrings.Insert(Index: Integer;
|
||
|
const S: string);
|
||
|
var
|
||
|
Item: TListBoxItem;
|
||
|
begin
|
||
|
Item := TfrxListBoxItem.Create(FListBox);
|
||
|
try
|
||
|
if Index <> Count - 1 then
|
||
|
TfrxListBoxItem(Item).CheckVisible := True;
|
||
|
Item.Text := S;
|
||
|
Item.Stored := False;
|
||
|
FListBox.InsertObject(Index, Item);
|
||
|
except
|
||
|
Item.Free;
|
||
|
raise;
|
||
|
end;
|
||
|
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.TfrxListBoxStrings.Put(Index: Integer; const S: string);
|
||
|
begin
|
||
|
FListBox.ListItems[Index].Text := S;
|
||
|
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.TfrxListBoxStrings.PutObject(Index: Integer;
|
||
|
AObject: TObject);
|
||
|
begin
|
||
|
FListBox.ListItems[Index].Data := AObject;
|
||
|
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.TfrxListBoxStrings.ReadData(Reader: TReader);
|
||
|
begin
|
||
|
Reader.ReadListBegin;
|
||
|
BeginUpdate;
|
||
|
try
|
||
|
if TfrxListBox(FListBox).ItemsStored then
|
||
|
begin
|
||
|
Clear;
|
||
|
while not Reader.EndOfList do
|
||
|
Add(Reader.ReadString);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
while not Reader.EndOfList do
|
||
|
Reader.ReadString;
|
||
|
end;
|
||
|
finally
|
||
|
EndUpdate;
|
||
|
end;
|
||
|
Reader.ReadListEnd;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.TfrxListBoxStrings.SetUpdateState(Updating: Boolean);
|
||
|
begin
|
||
|
if Updating then
|
||
|
FListBox.BeginUpdate
|
||
|
else
|
||
|
FListBox.EndUpdate;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBox.TfrxListBoxStrings.WriteData(Writer: TWriter);
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Writer.WriteListBegin;
|
||
|
for I := 0 to Count - 1 do
|
||
|
Writer.WriteString(Get(I));
|
||
|
Writer.WriteListEnd;
|
||
|
end;
|
||
|
|
||
|
{ TfrxListBoxItem }
|
||
|
|
||
|
procedure TfrxListBoxItem.ApplyStyle;
|
||
|
var
|
||
|
B: TFmxObject;
|
||
|
begin
|
||
|
inherited;
|
||
|
B := FindStyleResource('check');
|
||
|
if Assigned(B) and (B is TCheckBox) then
|
||
|
begin
|
||
|
FCheck := TCheckBox(B);
|
||
|
FCheck.Align := TAlignLayout.alRight;
|
||
|
if ListBox is TfrxListBox then
|
||
|
begin
|
||
|
if TfrxListBox(ListBox).ShowButtons then
|
||
|
begin
|
||
|
FButton.Parent := FCheck.Parent;
|
||
|
FButton.Visible := True;
|
||
|
FButton.Align := TAlignLayout.alMostRight;
|
||
|
FButton.Position.X := Width;
|
||
|
FButton.Width := 40;
|
||
|
FButton.Height := FCheck.Height;
|
||
|
FButton.Text := TfrxListBox(ListBox).ButtonText;
|
||
|
FButton.OnClick := OnBtnClick;
|
||
|
end;
|
||
|
FCheck.Text := TfrxListBox(ListBox).CheckBoxText;
|
||
|
end;
|
||
|
|
||
|
FCheck.Width := 90;
|
||
|
FCheck.Visible := FCheckVisible;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxListBoxItem.Create(AOwner: TComponent);
|
||
|
begin
|
||
|
inherited;
|
||
|
FButton := TButton.Create(Self);
|
||
|
FCheck := nil;
|
||
|
FCheckVisible := False;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxListBoxItem.Destroy;
|
||
|
begin
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBoxItem.FreeStyle;
|
||
|
begin
|
||
|
inherited;
|
||
|
FCheck := nil;
|
||
|
end;
|
||
|
|
||
|
function TfrxListBoxItem.GetCheckVisible: Boolean;
|
||
|
begin
|
||
|
Result := FCheckVisible;
|
||
|
if FCheck <> nil then
|
||
|
begin
|
||
|
Result := FCheck.Visible;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBoxItem.OnBtnClick(Sender: TObject);
|
||
|
begin
|
||
|
if ListBox is TfrxListBox then
|
||
|
begin
|
||
|
TfrxListBox(ListBox).DoButtonClick(Sender, Self);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxListBoxItem.SetCheckVisible(const Value: Boolean);
|
||
|
begin
|
||
|
if FCheck <> nil then
|
||
|
begin
|
||
|
FCheck.Visible := Value;
|
||
|
end;
|
||
|
FCheckVisible := Value;
|
||
|
end;
|
||
|
|
||
|
{ TfrxStringList }
|
||
|
|
||
|
function TfrxStringList.CompareStrings(const S1, S2: string): Integer;
|
||
|
begin
|
||
|
if FUseUnicode then
|
||
|
begin
|
||
|
if CaseSensitive then
|
||
|
Result := frxCompareStr(S1, S2)
|
||
|
else
|
||
|
Result := frxCompareText(S1, S2);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if CaseSensitive then
|
||
|
Result := CompareStr(S1, S2)
|
||
|
else
|
||
|
Result := CompareText(S1, S2);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxStringList.Create(UseUnicode: Boolean);
|
||
|
begin
|
||
|
Create;
|
||
|
FUseUnicode := UseUnicode;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxStringList.Create;
|
||
|
begin
|
||
|
Inherited Create;
|
||
|
FUseUnicode := False;
|
||
|
end;
|
||
|
{$IFDEF DELPHI19}
|
||
|
{$IFDEF MACOS}
|
||
|
function TQuartzBitmap.GetImage: CGImageRef;
|
||
|
begin
|
||
|
if FImage = nil then
|
||
|
FImage := CGBitmapContextCreateImage(FContext);
|
||
|
Result := FImage;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
{ TfrxFastCanvas }
|
||
|
{$IFDEF MACoS}
|
||
|
function TfrxFastCanvas.AddCTFontToList(const aNameFont: String;
|
||
|
aFontRef: CTFontRef): Integer;
|
||
|
begin
|
||
|
Result := FFontCacheList.AddObject(aNameFont, TObject(aFontRef))
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvas.AddFontAttribute(
|
||
|
AAttribute: CFMutableAttributedStringRef; AFont: TFont; const AStart,
|
||
|
ALength: Integer);
|
||
|
var
|
||
|
LFontRef: CTFontRef;
|
||
|
Underline: CFNumberRef;
|
||
|
LValue: Cardinal;
|
||
|
begin
|
||
|
// Font
|
||
|
LFontRef := GetCTFont(AFont);
|
||
|
if Assigned(LFontRef) then
|
||
|
|
||
|
CFAttributedStringSetAttribute(AAttribute, CFRangeMake(AStart, ALength),
|
||
|
kCTFontAttributeName, LFontRef);
|
||
|
// Underline
|
||
|
if TFontStyle.fsUnderline in AFont.Style then
|
||
|
begin
|
||
|
LValue := kCTUnderlineStyleSingle;
|
||
|
Underline := CFNumberCreate(nil, kCFNumberSInt32Type, @LValue);
|
||
|
CFAttributedStringSetAttribute(AAttribute, CFRangeMake(AStart, ALength),
|
||
|
kCTUnderlineStyleAttributeName, Underline);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvas.CalcHeight(Frame: CTFrameRef): Single;
|
||
|
var
|
||
|
fRect: CGRect;
|
||
|
Lines: CFArrayRef;
|
||
|
Index: CFIndex;
|
||
|
Desc: CGFloat;
|
||
|
Line: CTLineRef;
|
||
|
LineOrigin: CGPoint;
|
||
|
begin
|
||
|
FTextHeight := 0;
|
||
|
if Assigned(Frame) then
|
||
|
begin
|
||
|
fRect := CGPathGetBoundingBox(FPath);
|
||
|
Lines := CTFrameGetLines(Frame);
|
||
|
Index := CFArrayGetCount(Lines) - 1;
|
||
|
Line := CTLineRef(CFArrayGetValueAtIndex(Lines, Index));
|
||
|
CTLineGetTypographicBounds(Line, nil, @Desc, nil);
|
||
|
CTFrameGetLineOrigins(Frame, CFRangeMake(Index, 1), @LineOrigin);
|
||
|
FTextHeight := CGRectGetMaxY(fRect) - LineOrigin.y + Desc;
|
||
|
end;
|
||
|
Result := FTextHeight;
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvas.CalcWidth(Frame: CTFrameRef): Single;
|
||
|
var
|
||
|
LFrameRect: CGRect;
|
||
|
Lines: CFArrayRef;
|
||
|
NumLines: CFIndex;
|
||
|
Index: CFIndex;
|
||
|
aWidth: CGFloat;
|
||
|
Line: CTLineRef;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
if Assigned(Frame) then
|
||
|
begin
|
||
|
LFrameRect := CGPathGetBoundingBox(FPath);
|
||
|
Lines := CTFrameGetLines(Frame);
|
||
|
NumLines := CFArrayGetCount(Lines);
|
||
|
FTextWidth := 0;
|
||
|
if NumLines > 0 then
|
||
|
for Index := 0 to NumLines - 1 do
|
||
|
begin
|
||
|
Line := CTLineRef(CFArrayGetValueAtIndex(Lines, Index));
|
||
|
aWidth := CTLineGetTypographicBounds(Line, nil, nil, nil);
|
||
|
FTextWidth := Max(aWidth, FTextWidth);
|
||
|
end;
|
||
|
Result := FTextWidth;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvas.ClearFontCache;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
for i := 0 to FFontCacheList.Count - 1 do
|
||
|
CFRelease(CTFontRef(FFontCacheList.Objects[i]));
|
||
|
FFontCacheList.Clear;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxFastCanvas.Create;
|
||
|
begin
|
||
|
// use same matrix as in FMX, because we need same output
|
||
|
FFontTransformMatrix.a := 1;
|
||
|
FFontTransformMatrix.b := 0;
|
||
|
FFontTransformMatrix.c := Tan(10);
|
||
|
FFontTransformMatrix.d := 1;
|
||
|
FFontTransformMatrix.tx := 0;
|
||
|
FFontTransformMatrix.ty := 0;
|
||
|
FOpacity := 1;
|
||
|
FCurentFont := nil;
|
||
|
FFontCacheList := TfrxStringList.Create;
|
||
|
FColorSpace := CGColorSpaceCreateDeviceRGB;
|
||
|
FCanvas := nil;
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvas.CreateCTFont(const AFont: TFont): CTFontRef;
|
||
|
var
|
||
|
FontRefCopy: CTFontRef;
|
||
|
m: PCGAffineTransform;
|
||
|
begin
|
||
|
Result := CTFontCreateWithName(CFSTR(AFont.Family), AFont.Size * 1, nil);
|
||
|
m := nil;
|
||
|
try
|
||
|
if TFontStyle.fsItalic in AFont.Style then
|
||
|
begin
|
||
|
FontRefCopy := CTFontCreateCopyWithSymbolicTraits(Result, 0, nil,
|
||
|
kCTFontItalicTrait, kCTFontItalicTrait);
|
||
|
if Assigned(FontRefCopy) then
|
||
|
begin
|
||
|
CFRelease(Result);
|
||
|
Result := FontRefCopy;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
m := @FFontTransformMatrix;
|
||
|
FontRefCopy := CTFontCreateWithName(CFSTR(AFont.Family), AFont.Size * 1, @FFontTransformMatrix);
|
||
|
if Assigned(FontRefCopy) then
|
||
|
begin
|
||
|
CFRelease(Result);
|
||
|
Result := FontRefCopy;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
if TFontStyle.fsBold in AFont.Style then
|
||
|
begin
|
||
|
FontRefCopy := CTFontCreateCopyWithSymbolicTraits(Result, 0, m,
|
||
|
kCTFontBoldTrait, kCTFontBoldTrait);
|
||
|
if Assigned(FontRefCopy) then
|
||
|
begin
|
||
|
CFRelease(Result);
|
||
|
Result := FontRefCopy;
|
||
|
end;
|
||
|
end;
|
||
|
except
|
||
|
CFRelease(Result);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvas.CreateFrame(Canvas: TCanvas; StringRef: CFStringRef;
|
||
|
var AttributedS: CFMutableAttributedStringRef; var Frame: CTFrameRef);
|
||
|
var
|
||
|
Value: Cardinal;
|
||
|
Ligature: CFNumberRef;
|
||
|
FrameSetter: CTFramesetterRef;
|
||
|
AlphaRec: TAlphaColorRec;
|
||
|
rgba: array [0 .. 3] of CGFloat;
|
||
|
TextColor: CGColorRef;
|
||
|
Alignment: Byte;
|
||
|
Direction: Byte;
|
||
|
Wrapping: Byte;
|
||
|
ParaSettings: array [0 .. 2] of CTParagraphStyleSetting;
|
||
|
ParagraphStyle: CTParagraphStyleRef;
|
||
|
begin
|
||
|
AttributedS := CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
|
||
|
CFAttributedStringReplaceString(AttributedS, CFRangeMake(0, 0), StringRef);
|
||
|
CFAttributedStringBeginEditing(AttributedS);
|
||
|
|
||
|
AlphaRec := TAlphaColorRec(MakeColor(Canvas.Fill.Color, FOpacity));
|
||
|
rgba[0] := AlphaRec.r / $FF;
|
||
|
rgba[1] := AlphaRec.g / $FF;
|
||
|
rgba[2] := AlphaRec.b / $FF;
|
||
|
rgba[3] := AlphaRec.a / $FF;
|
||
|
|
||
|
TextColor := CGColorCreate(FColorSpace, @rgba[0]);
|
||
|
CFAttributedStringSetAttribute(AttributedS, CFRangeMake(0, FText.Length),
|
||
|
kCTForegroundColorAttributeName, TextColor);
|
||
|
CFRelease(TextColor);
|
||
|
|
||
|
Value := 0;
|
||
|
Ligature := CFNumberCreate(nil, kCFNumberSInt32Type, @Value);
|
||
|
CFAttributedStringSetAttribute(AttributedS, CFRangeMake(0, FText.Length), kCTLigatureAttributeName, Ligature);
|
||
|
AddFontAttribute(AttributedS, Canvas.Font, 0, FText.Length);
|
||
|
|
||
|
case FTextAlign of
|
||
|
TTextAlign.taCenter:
|
||
|
Alignment := kCTCenterTextAlignment;
|
||
|
TTextAlign.taLeading:
|
||
|
Alignment := kCTLeftTextAlignment;
|
||
|
TTextAlign.taTrailing:
|
||
|
Alignment := kCTRightTextAlignment;
|
||
|
end;
|
||
|
ParaSettings[0].spec := kCTParagraphStyleSpecifierAlignment;
|
||
|
ParaSettings[0].valueSize := sizeof(Alignment);
|
||
|
ParaSettings[0].Value := @Alignment;
|
||
|
|
||
|
if FWordWrap then
|
||
|
Wrapping := kCTLineBreakByWordWrapping
|
||
|
else
|
||
|
Wrapping := kCTLineBreakByClipping;
|
||
|
|
||
|
ParaSettings[1].spec := kCTParagraphStyleSpecifierLineBreakMode;
|
||
|
ParaSettings[1].valueSize := SizeOf(Wrapping);
|
||
|
ParaSettings[1].value := @Wrapping;
|
||
|
|
||
|
if TFillTextFlag.ftRightToLeft in FFlags then
|
||
|
Direction := kCTWritingDirectionRightToLeft
|
||
|
else
|
||
|
Direction := kCTWritingDirectionLeftToRight;
|
||
|
ParaSettings[2].spec := kCTParagraphStyleSpecifierBaseWritingDirection;
|
||
|
ParaSettings[2].valueSize := SizeOf(Direction);
|
||
|
ParaSettings[2].value := @Direction;
|
||
|
ParagraphStyle := CTParagraphStyleCreate(@ParaSettings[0], 3);
|
||
|
|
||
|
CFAttributedStringSetAttribute(AttributedS, CFRangeMake(0, CFStringGetLength(StringRef)), kCTParagraphStyleAttributeName, ParagraphStyle);
|
||
|
CFRelease(ParagraphStyle);
|
||
|
CFAttributedStringEndEditing(AttributedS);
|
||
|
FrameSetter := CTFramesetterCreateWithAttributedString(CFAttributedStringRef(AttributedS));
|
||
|
Frame := CTFramesetterCreateFrame(FrameSetter, CFRangeMake(0, 0), FPath, nil);
|
||
|
end;
|
||
|
|
||
|
destructor TfrxFastCanvas.Destroy;
|
||
|
begin
|
||
|
ClearFontCache;
|
||
|
FreeAndNil(FFontCacheList);
|
||
|
inherited;
|
||
|
end;
|
||
|
type TProc = procedure of object;
|
||
|
|
||
|
procedure TfrxFastCanvas.FillText(
|
||
|
const ARect: TRectF; const AText: string; const WordWrap: Boolean;
|
||
|
const AOpacity: Single; const Flags: TFillTextFlags; const ATextAlign,
|
||
|
AVTextAlign: TTextAlign);
|
||
|
var
|
||
|
cref: CGContextRef;
|
||
|
LStringRef: CFStringRef;
|
||
|
FCTFrame: CTFrameRef;
|
||
|
Bounds: CGRect;
|
||
|
Attr: CFMutableAttributedStringRef;
|
||
|
begin
|
||
|
if AText.Length = 0 then Exit;
|
||
|
FText := AText;
|
||
|
FTextAlign := ATextAlign;
|
||
|
FWordWrap := WordWrap;
|
||
|
FFlags := Flags;
|
||
|
FOpacity := AOpacity;
|
||
|
if (CompareText(Canvas.ClassName, 'TCanvasQuartz') = 0) and (FContext <> 0) then
|
||
|
begin
|
||
|
FPath := CGPathCreateMutable();
|
||
|
Bounds := CGRectMake(0, 0, ARect.Width, $FFFF);
|
||
|
CGPathAddRect(FPath, nil, Bounds);
|
||
|
LStringRef := CFStringCreateWithCharacters(kCFAllocatorDefault, PChar(AText), AText.Length);
|
||
|
CreateFrame(Canvas, LStringRef, Attr, FCTFrame);
|
||
|
|
||
|
cref := Pointer(FContext);
|
||
|
CGContextSaveGState(cref);
|
||
|
CGContextClipToRect(cref, CGRectMake(ARect.Left, ARect.Top, ARect.Width, ARect.Height));
|
||
|
CGContextSetTextMatrix(cref, CGAffineTransformMakeScale(1.0, 1.0));
|
||
|
CGContextTranslateCTM(cref, ARect.Left, ARect.Bottom);
|
||
|
CGContextScaleCTM(cref, 1, -1);
|
||
|
CGContextTranslateCTM(cref, 0, -($FFFF - ARect.Height));
|
||
|
|
||
|
CalcHeight(FCTFrame);
|
||
|
|
||
|
case AVTextAlign of
|
||
|
TTextAlign.taCenter:
|
||
|
CGContextTranslateCTM(cref, 0,
|
||
|
-(ARect.Height - FTextHeight) / 2);
|
||
|
TTextAlign.taLeading:
|
||
|
CGContextTranslateCTM(cref, 0, 0);
|
||
|
TTextAlign.taTrailing:
|
||
|
CGContextTranslateCTM(cref, 0,
|
||
|
-(ARect.Height - FTextHeight));
|
||
|
end;
|
||
|
|
||
|
CTFrameDraw(FCTFrame, cref);
|
||
|
|
||
|
CGContextRestoreGState(cref);
|
||
|
CFRelease(LStringRef);
|
||
|
CFRelease(Attr);
|
||
|
CFRelease(FPath);
|
||
|
CFRelease(FCTFrame);
|
||
|
end
|
||
|
else
|
||
|
Inherited;
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvas.GetContext: THandle;
|
||
|
begin
|
||
|
if Assigned(FCanvas.Bitmap) and (FCanvas.Bitmap.Handle <> 0) then
|
||
|
begin
|
||
|
if (TQuartzBitmap(FCanvas.Bitmap.Handle).FImage <> nil) then
|
||
|
begin
|
||
|
CGImageRelease(TQuartzBitmap(FCanvas.Bitmap.Handle).FImage);
|
||
|
TQuartzBitmap(FCanvas.Bitmap.Handle).FImage := nil;
|
||
|
end;
|
||
|
FContext := THandle(CGBitmapContextCreate(TQuartzBitmap(FCanvas.Bitmap.Handle).FData, FCanvas.Bitmap.Width, FCanvas.Bitmap.Height, 8,
|
||
|
FCanvas.Bitmap.Width * 4, FColorSpace, kCGImageAlphaPremultipliedLast));
|
||
|
end;
|
||
|
Result := FContext;
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvas.GetCTFont(const AFont: TFont): CTFontRef;
|
||
|
var
|
||
|
fName: String;
|
||
|
Index: Integer;
|
||
|
begin
|
||
|
Result := nil;
|
||
|
fName := GetFontNameHash(aFont);
|
||
|
Index := FFontCacheList.IndexOf(fName);
|
||
|
if Index = -1 then
|
||
|
Index := AddCTFontToList(fName, CreateCTFont(aFont));
|
||
|
Result := CTFontRef(FFontCacheList.Objects[Index])
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvas.GetFontNameHash(const AFont: TFont): String;
|
||
|
begin
|
||
|
Result := aFont.Family;
|
||
|
if fsBold in aFont.Style then
|
||
|
Result := Result + 'B';
|
||
|
if fsItalic in aFont.Style then
|
||
|
Result := Result + 'I';
|
||
|
Result := Result + FloatToStr(aFont.Size);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvas.MeasureText(var ARect: TRectF; const AText: string; const WordWrap: Boolean; const Flags: TFillTextFlags; const ATextAlign, AVTextAlign: TTextAlign);
|
||
|
var
|
||
|
cref: CGContextRef;
|
||
|
LStringRef: CFStringRef;
|
||
|
FCTFrame: CTFrameRef;
|
||
|
Bounds: CGRect;
|
||
|
Attr: CFMutableAttributedStringRef;
|
||
|
w, h: Double;
|
||
|
begin
|
||
|
w := 0;
|
||
|
h := 0;
|
||
|
if AText.Length = 0 then
|
||
|
Exit;
|
||
|
FText := AText;
|
||
|
FTextAlign := ATextAlign;
|
||
|
FWordWrap := WordWrap;
|
||
|
FFlags := Flags;
|
||
|
if CompareText(Canvas.ClassName, 'TCanvasQuartz') = 0 then
|
||
|
begin
|
||
|
FPath := CGPathCreateMutable();
|
||
|
Bounds := CGRectMake(0, 0, ARect.Width, $FFFF);
|
||
|
CGPathAddRect(FPath, nil, Bounds);
|
||
|
LStringRef := CFStringCreateWithCharacters(kCFAllocatorDefault, PChar(AText), AText.Length);
|
||
|
CreateFrame(Canvas, LStringRef, Attr, FCTFrame);
|
||
|
cref := Pointer(FContext);
|
||
|
|
||
|
CGContextSaveGState(cref);
|
||
|
CGContextClipToRect(cref, CGRectMake(ARect.Left, ARect.Top, ARect.Width, ARect.Height));
|
||
|
CGContextSetTextMatrix(cref, CGAffineTransformMakeScale(1.0, 1.0));
|
||
|
CGContextTranslateCTM(cref, ARect.Left, ARect.Bottom);
|
||
|
CGContextScaleCTM(cref, 1, -1);
|
||
|
CGContextTranslateCTM(cref, 0, -($FFFF - ARect.Height));
|
||
|
|
||
|
w := CalcWidth(FCTFrame);
|
||
|
h := CalcHeight(FCTFrame);
|
||
|
CGContextRestoreGState(cref);
|
||
|
CFRelease(Attr);
|
||
|
CFRelease(LStringRef);
|
||
|
CFRelease(FPath);
|
||
|
CFRelease(FCTFrame);
|
||
|
end;
|
||
|
|
||
|
ARect.Right := ARect.Left + w;
|
||
|
ARect.Bottom := ARect.Top + h;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvas.SetCanvas(const Value: TCanvas);
|
||
|
begin
|
||
|
FCanvas := Value;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvas.SetFont(const Value: TFont);
|
||
|
begin
|
||
|
FCurentFont := GetCTFont(Value);
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
{ TfrxFastCanvasLayer }
|
||
|
|
||
|
function TfrxFastCanvasLayer.CalcHeight(aText: String): Single;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
if Assigned(Canvas) then
|
||
|
Result := Canvas.TextHeight(aText);
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvasLayer.CalcWidth(aText: String): Single;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
if Assigned(Canvas) then
|
||
|
Result := Canvas.TextWidth(aText);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.Clear(const Color: TAlphaColor);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.ClearCache;
|
||
|
begin
|
||
|
//nothing
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.ClearRect(const ARect: TRectF;
|
||
|
const AColor: TAlphaColor);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
|
||
|
constructor TfrxFastCanvasLayer.Create;
|
||
|
begin
|
||
|
FContext := 0;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxFastCanvasLayer.Destroy;
|
||
|
begin
|
||
|
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvasLayer.DoBeginScene({$IFNDEF DELPHI28}const{$ENDIF} AClipRects: PClipRects;
|
||
|
AContextHandle: THandle): Boolean;
|
||
|
begin
|
||
|
Result := False;
|
||
|
if AContextHandle = 0 then
|
||
|
AContextHandle := THandle(GetContext);
|
||
|
if Assigned(Canvas) then
|
||
|
Result := Canvas.BeginScene(AClipRects, AContextHandle);
|
||
|
end;
|
||
|
|
||
|
|
||
|
{$IFDEF DELPHI19}
|
||
|
procedure TfrxFastCanvasLayer.DoDrawBitmap(const ABitmap: FMX.Graphics.TBitmap;
|
||
|
const SrcRect, DstRect: TRectF; const AOpacity: Single;
|
||
|
const HighSpeed: Boolean);
|
||
|
{$ELSE}
|
||
|
procedure TfrxFastCanvasLayer.DoDrawBitmap(const ABitmap: FMX.Types.TBitmap;
|
||
|
const SrcRect, DstRect: TRectF; const AOpacity: Single;
|
||
|
const HighSpeed: Boolean);
|
||
|
{$ENDIF}
|
||
|
begin
|
||
|
inherited;
|
||
|
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.DoDrawEllipse(const ARect: TRectF;
|
||
|
const AOpacity: Single; const ABrush: TStrokeBrush);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.DoDrawLine(const APt1, APt2: TPointF;
|
||
|
const AOpacity: Single; const ABrush: TStrokeBrush);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.DoDrawPath(const APath: TPathData;
|
||
|
const AOpacity: Single; const ABrush: TStrokeBrush);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.DoDrawRect(const ARect: TRectF;
|
||
|
const AOpacity: Single; const ABrush: TStrokeBrush);
|
||
|
begin
|
||
|
inherited;
|
||
|
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.DoEndScene;
|
||
|
begin
|
||
|
if Assigned(Canvas) then
|
||
|
Canvas.EndScene;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.DoFillEllipse(const ARect: TRectF;
|
||
|
const AOpacity: Single; const ABrush: TBrush);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.DoFillPath(const APath: TPathData;
|
||
|
const AOpacity: Single; const ABrush: TBrush);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.DoFillRect(const ARect: TRectF;
|
||
|
const AOpacity: Single; const ABrush: TBrush);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
|
||
|
{$IFDEF DELPHI21}
|
||
|
|
||
|
function TfrxFastCanvasLayer.DoFillPolygon(const Points: TPolygon;
|
||
|
const AOpacity: Single; const ABrush: TBrush): Boolean;
|
||
|
begin
|
||
|
//fake
|
||
|
Result := False;
|
||
|
end;
|
||
|
|
||
|
class procedure TfrxFastCanvasLayer.DoFinalizeBitmap(var Bitmap: THandle);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
|
||
|
class function TfrxFastCanvasLayer.DoInitializeBitmap(const Width,
|
||
|
Height: Integer; const Scale: Single; var PixelFormat: TPixelFormat): THandle;
|
||
|
begin
|
||
|
//fake
|
||
|
Result := 0;
|
||
|
end;
|
||
|
|
||
|
class function TfrxFastCanvasLayer.DoMapBitmap(const Bitmap: THandle;
|
||
|
const Access: TMapAccess; var Data: TBitmapData): Boolean;
|
||
|
begin
|
||
|
//fake
|
||
|
Result := False;
|
||
|
end;
|
||
|
|
||
|
class procedure TfrxFastCanvasLayer.DoUnmapBitmap(const Bitmap: THandle;
|
||
|
var Data: TBitmapData);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
{$ELSE}
|
||
|
{$IFDEF DELPHI19}
|
||
|
class procedure TfrxFastCanvasLayer.DoInitializeBitmap(const Bitmap: FMX.Graphics.TBitmap);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
class procedure TfrxFastCanvasLayer.DoFinalizeBitmap(const Bitmap: FMX.Graphics.TBitmap);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
class function TfrxFastCanvasLayer.DoMapBitmap(const Bitmap: FMX.Graphics.TBitmap; const Access: TMapAccess; var Data: TBitmapData): Boolean;
|
||
|
begin
|
||
|
Result := False;
|
||
|
//fake
|
||
|
end;
|
||
|
class procedure TfrxFastCanvasLayer.DoUnmapBitmap(const Bitmap: FMX.Graphics.TBitmap; var Data: TBitmapData);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.ExcludeClipRect(const ARect: TRectF);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.FillText(const ARect: TRectF;
|
||
|
const AText: string; const WordWrap: Boolean; const AOpacity: Single;
|
||
|
const Flags: TFillTextFlags; const ATextAlign, AVTextAlign: TTextAlign);
|
||
|
begin
|
||
|
if Assigned(Canvas) then
|
||
|
Canvas.FillText(ARect, AText, WordWrap, AOpacity, Flags, ATextAlign,
|
||
|
AVTextAlign);
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvasLayer.GetContext: THandle;
|
||
|
begin
|
||
|
Result := FContext;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.IntersectClipRect(const ARect: TRectF);
|
||
|
begin
|
||
|
//fake
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.MeasureText(var ARect: TRectF;
|
||
|
const AText: string; const WordWrap: Boolean; const Flags: TFillTextFlags;
|
||
|
const ATextAlign, AVTextAlign: TTextAlign);
|
||
|
begin
|
||
|
if Assigned(Canvas) then
|
||
|
Canvas.MeasureText(ARect, AText, WordWrap, Flags, ATextAlign,
|
||
|
AVTextAlign);
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvasLayer.PtInPath(const APoint: TPointF;
|
||
|
const APath: TPathData): Boolean;
|
||
|
begin
|
||
|
//fake
|
||
|
Result := False;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.SetCanvas(const Value: TCanvas);
|
||
|
begin
|
||
|
if Assigned(Value) then
|
||
|
begin
|
||
|
FWidth := Value.Width;
|
||
|
FHeight := Value.Height;
|
||
|
end;
|
||
|
FCanvas := Value;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.SetContext(const Value: THandle);
|
||
|
begin
|
||
|
FContext := Value;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.SetFont(const Value: TFont);
|
||
|
begin
|
||
|
if Assigned(Canvas) then
|
||
|
Canvas.Font.Assign(Value);
|
||
|
end;
|
||
|
|
||
|
{ TfrxFastCanvas }
|
||
|
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
procedure TfrxFastCanvas.ClearFontCache;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
for i := 0 to FFontCacheList.Count - 1 do
|
||
|
FFontCacheList.Objects[i].Free;
|
||
|
FFontCacheList.Clear;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxFastCanvas.Create;
|
||
|
begin
|
||
|
FFontCacheList := TfrxStringList.Create;
|
||
|
FFontCacheList.Sorted := True;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxFastCanvas.Destroy;
|
||
|
begin
|
||
|
ClearFontCache;
|
||
|
FreeAndNil(FFontCacheList);
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFastCanvas.FillText(const ARect: TRectF; const AText: string;
|
||
|
const WordWrap: Boolean; const AOpacity: Single; const Flags: TFillTextFlags;
|
||
|
const ATextAlign, AVTextAlign: TTextAlign);
|
||
|
var
|
||
|
DLayont: TTextLayout;
|
||
|
Fonthash: String;
|
||
|
Index: Integer;
|
||
|
begin
|
||
|
if Canvas.ClassName <> 'TCanvasGdiPlus' then
|
||
|
begin
|
||
|
Inherited;
|
||
|
Exit;
|
||
|
end;
|
||
|
fonthash := GetFontNameHash(FCanvas.Font, WordWrap, Flags, ATextAlign, AVTextAlign);
|
||
|
Index := FFontCacheList.IndexOf(fonthash);
|
||
|
|
||
|
if Index = -1 then
|
||
|
begin
|
||
|
DLayont := TTextLayoutManager.TextLayoutByCanvas(Canvas.ClassType)
|
||
|
.Create(Canvas);
|
||
|
DLayont.BeginUpdate;
|
||
|
DLayont.Font := Canvas.Font;
|
||
|
DLayont.WordWrap := WordWrap;
|
||
|
DLayont.HorizontalAlign := ATextAlign;
|
||
|
DLayont.VerticalAlign := AVTextAlign;
|
||
|
DLayont.RightToLeft := TFillTextFlag.ftRightToLeft in Flags;
|
||
|
DLayont.EndUpdate;
|
||
|
DLayont.BeginUpdate;
|
||
|
Index := FFontCacheList.AddObject(fonthash, DLayont);
|
||
|
end;
|
||
|
|
||
|
DLayont := TTextLayout(FFontCacheList.Objects[Index]);
|
||
|
DLayont.Color := Canvas.Fill.Color;
|
||
|
DLayont.Opacity := AOpacity;
|
||
|
DLayont.TopLeft := ARect.TopLeft;
|
||
|
DLayont.MaxSize := PointF(ARect.Width, ARect.Height);
|
||
|
DLayont.Text := AText;
|
||
|
TTextLayoutHack(DLayont).DoDrawLayout(Canvas);
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvas.GetContext: THandle;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
end;
|
||
|
|
||
|
function TfrxFastCanvas.GetFontNameHash(const AFont: TFont; WordWrap: Boolean; const Flags: TFillTextFlags; const ATextAlign: TTextAlign; const VTextAlign: TTextAlign): String;
|
||
|
begin
|
||
|
Result := aFont.Family;
|
||
|
if fsBold in aFont.Style then
|
||
|
Result := Result + 'B';
|
||
|
if fsItalic in aFont.Style then
|
||
|
Result := Result + 'I';
|
||
|
if fsUnderline in aFont.Style then
|
||
|
Result := Result + 'U';
|
||
|
if fsStrikeout in aFont.Style then
|
||
|
Result := Result + 'U';
|
||
|
if WordWrap then
|
||
|
Result := Result + 'W';
|
||
|
case ATextAlign of
|
||
|
TTextAlign.taCenter: Result := Result + 'C';
|
||
|
TTextAlign.taLeading: Result := Result + 'L';
|
||
|
TTextAlign.taTrailing: Result := Result + 'T';
|
||
|
end;
|
||
|
case VTextAlign of
|
||
|
TTextAlign.taCenter: Result := Result + 'VC';
|
||
|
TTextAlign.taLeading: Result := Result + 'VL';
|
||
|
TTextAlign.taTrailing: Result := Result + 'VT';
|
||
|
end;
|
||
|
if TFillTextFlag.ftRightToLeft in Flags then
|
||
|
Result := Result + 'R';
|
||
|
Result := Result + FloatToStr(aFont.Size);
|
||
|
end;
|
||
|
|
||
|
|
||
|
procedure TfrxFastCanvas.MeasureText(var ARect: TRectF; const AText: string;
|
||
|
const WordWrap: Boolean; const Flags: TFillTextFlags; const ATextAlign,
|
||
|
AVTextAlign: TTextAlign);
|
||
|
var
|
||
|
DLayont: TTextLayout;
|
||
|
Fonthash: String;
|
||
|
Index: Integer;
|
||
|
tr: TTextRange;
|
||
|
LRegion: TRegion;
|
||
|
i: Integer;
|
||
|
begin
|
||
|
if Canvas.ClassName <> 'TCanvasGdiPlus' then
|
||
|
begin
|
||
|
Inherited;
|
||
|
Exit;
|
||
|
end;
|
||
|
fonthash := GetFontNameHash(FCanvas.Font, WordWrap, Flags, ATextAlign, AVTextAlign);
|
||
|
Index := FFontCacheList.IndexOf(fonthash);
|
||
|
|
||
|
if Index = -1 then
|
||
|
begin
|
||
|
DLayont := TTextLayoutManager.TextLayoutByCanvas(Canvas.ClassType)
|
||
|
.Create(Canvas);
|
||
|
DLayont.BeginUpdate;
|
||
|
DLayont.Font := Canvas.Font;
|
||
|
DLayont.WordWrap := WordWrap;
|
||
|
DLayont.HorizontalAlign := ATextAlign;
|
||
|
DLayont.VerticalAlign := AVTextAlign;
|
||
|
DLayont.RightToLeft := False;
|
||
|
DLayont.EndUpdate;
|
||
|
DLayont.BeginUpdate;
|
||
|
Index := FFontCacheList.AddObject(fonthash, DLayont);
|
||
|
end;
|
||
|
|
||
|
DLayont := TTextLayout(FFontCacheList.Objects[Index]);
|
||
|
DLayont.TopLeft := ARect.TopLeft;
|
||
|
DLayont.MaxSize := PointF(ARect.Width, ARect.Height);
|
||
|
DLayont.Text := AText;
|
||
|
DLayont.TopLeft := ARect.TopLeft;
|
||
|
DLayont.MaxSize := PointF(ARect.Width, ARect.Height);
|
||
|
DLayont.Text := AText;
|
||
|
tr.Pos := 0;
|
||
|
tr.Length := Length(AText);
|
||
|
LRegion := TTextLayoutHack(DLayont).DoRegionForRange(tr);
|
||
|
|
||
|
if Length(LRegion) > 0 then
|
||
|
begin
|
||
|
for i := 1 to High(LRegion) do
|
||
|
LRegion[0].Union(LRegion[i]);
|
||
|
ARect.Left := LRegion[0].Left;
|
||
|
ARect.Top := LRegion[0].Top;
|
||
|
ARect.Width := LRegion[0].Width;
|
||
|
ARect.Height := LRegion[0].Height;
|
||
|
end;
|
||
|
|
||
|
end;
|
||
|
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
|
||
|
{ TfrxFastCanvasLayer }
|
||
|
|
||
|
type
|
||
|
TCommonCustomFormHack = class(TCommonCustomForm);
|
||
|
|
||
|
procedure TfrxFastCanvasLayer.UpdateHandle(AParent: TFmxObject);
|
||
|
var
|
||
|
ParentForm: TFmxObject;
|
||
|
begin
|
||
|
ParentForm := AParent;
|
||
|
while (ParentForm <> nil) and not (ParentForm is TCommonCustomForm) do
|
||
|
ParentForm := ParentForm.Parent;
|
||
|
if (ParentForm is TCommonCustomForm) then
|
||
|
Context := TCommonCustomFormHack(ParentForm).ContextHandle
|
||
|
else
|
||
|
Context := 0;
|
||
|
end;
|
||
|
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
function frxGetDefaultPPI: Integer;
|
||
|
var
|
||
|
dc: HDC;
|
||
|
begin
|
||
|
dc := GetDC(0);
|
||
|
try
|
||
|
Result := GetDeviceCaps(dc, LOGPIXELSX);
|
||
|
finally
|
||
|
ReleaseDC(0, dc);
|
||
|
end;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
initialization
|
||
|
{$IFDEF MSWINDOWS}
|
||
|
frxDefaultPPI := frxGetDefaultPPI;
|
||
|
{$ENDIF}
|
||
|
|
||
|
frxCanvasClass;
|
||
|
|
||
|
StartClassGroup(TFmxObject);
|
||
|
ActivateClassGroup(TFmxObject);
|
||
|
GroupDescendentsWith(TfrxToolButton, TFmxObject);
|
||
|
GroupDescendentsWith(TfrxToolSeparator, TFmxObject);
|
||
|
GroupDescendentsWith(TfrxToolGrip, TFmxObject);
|
||
|
GroupDescendentsWith(TfrxFont, TFmxObject);
|
||
|
GroupDescendentsWith(TfrxTreeView, TFmxObject);
|
||
|
GroupDescendentsWith(TfrxTreeViewItem, TFmxObject);
|
||
|
GroupDescendentsWith(TfrxImageList, TFmxObject);
|
||
|
GroupDescendentsWith(TfrxListBoxItem, TFmxObject);
|
||
|
GroupDescendentsWith(TfrxListBox, TFmxObject);
|
||
|
RegisterFmxClasses([TfrxToolButton, TfrxTreeViewItem, TfrxTreeView, TfrxListBoxItem, TfrxListBox, TfrxToolSeparator, TfrxToolGrip, TfrxFont]);
|
||
|
{$IFDEF MACOS}
|
||
|
UCCreateCollator(nil, nil, kUCCollateCaseInsensitiveMask, @collatorRefIgnoreCase);
|
||
|
UCCreateCollator(nil, nil, 0, @collatorRef);
|
||
|
|
||
|
finalization
|
||
|
UCDisposeCollator(@collatorRefIgnoreCase);
|
||
|
UCDisposeCollator(@collatorRef);
|
||
|
{$ENDIF}
|
||
|
end.
|