FastReport_FMX_2.8.12/Source/FMX.frxFMX.pas
2024-07-06 22:41:12 +02:00

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.