Стартовый пул
This commit is contained in:
BIN
bgrabitmap/test/testbiditext2/LiberationSerif-Regular.ttf
Normal file
BIN
bgrabitmap/test/testbiditext2/LiberationSerif-Regular.ttf
Normal file
Binary file not shown.
BIN
bgrabitmap/test/testbiditext2/project1.ico
Normal file
BIN
bgrabitmap/test/testbiditext2/project1.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
86
bgrabitmap/test/testbiditext2/project1.lpi
Normal file
86
bgrabitmap/test/testbiditext2/project1.lpi
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="11"/>
|
||||
<General>
|
||||
<SessionStorage Value="InProjectDir"/>
|
||||
<MainUnit Value="0"/>
|
||||
<Title Value="project1"/>
|
||||
<ResourceType Value="res"/>
|
||||
<UseXPManifest Value="True"/>
|
||||
<Icon Value="0"/>
|
||||
</General>
|
||||
<BuildModes Count="1">
|
||||
<Item1 Name="Default" Default="True"/>
|
||||
</BuildModes>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
</PublishOptions>
|
||||
<RunParams>
|
||||
<FormatVersion Value="2"/>
|
||||
<Modes Count="1">
|
||||
<Mode0 Name="default"/>
|
||||
</Modes>
|
||||
</RunParams>
|
||||
<RequiredPackages Count="2">
|
||||
<Item1>
|
||||
<PackageName Value="bgracontrols"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<PackageName Value="LCL"/>
|
||||
</Item2>
|
||||
</RequiredPackages>
|
||||
<Units Count="2">
|
||||
<Unit0>
|
||||
<Filename Value="project1.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit0>
|
||||
<Unit1>
|
||||
<Filename Value="unit1.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<ComponentName Value="Form1"/>
|
||||
<HasResources Value="True"/>
|
||||
<ResourceBaseClass Value="Form"/>
|
||||
<UnitName Value="Unit1"/>
|
||||
</Unit1>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="11"/>
|
||||
<Target>
|
||||
<Filename Value="project1"/>
|
||||
</Target>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
||||
</SearchPaths>
|
||||
<CodeGeneration>
|
||||
<Optimizations>
|
||||
<OptimizationLevel Value="0"/>
|
||||
</Optimizations>
|
||||
</CodeGeneration>
|
||||
<Linking>
|
||||
<Debugging>
|
||||
<UseHeaptrc Value="True"/>
|
||||
</Debugging>
|
||||
<Options>
|
||||
<Win32>
|
||||
<GraphicApplication Value="True"/>
|
||||
</Win32>
|
||||
</Options>
|
||||
</Linking>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<Exceptions Count="3">
|
||||
<Item1>
|
||||
<Name Value="EAbort"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Name Value="ECodetoolError"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Name Value="EFOpenError"/>
|
||||
</Item3>
|
||||
</Exceptions>
|
||||
</Debugging>
|
||||
</CONFIG>
|
20
bgrabitmap/test/testbiditext2/project1.lpr
Normal file
20
bgrabitmap/test/testbiditext2/project1.lpr
Normal file
@@ -0,0 +1,20 @@
|
||||
program project1;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
uses
|
||||
{$IFDEF UNIX}{$IFDEF UseCThreads}
|
||||
cthreads,
|
||||
{$ENDIF}{$ENDIF}
|
||||
Interfaces, // this includes the LCL widgetset
|
||||
Forms, Unit1;
|
||||
|
||||
{$R *.res}
|
||||
|
||||
begin
|
||||
RequireDerivedFormResource:=True;
|
||||
Application.Initialize;
|
||||
Application.CreateForm(TForm1, Form1);
|
||||
Application.Run;
|
||||
end.
|
||||
|
236
bgrabitmap/test/testbiditext2/unit1.lfm
Normal file
236
bgrabitmap/test/testbiditext2/unit1.lfm
Normal file
@@ -0,0 +1,236 @@
|
||||
object Form1: TForm1
|
||||
Left = 345
|
||||
Height = 415
|
||||
Top = 177
|
||||
Width = 722
|
||||
Caption = 'BGRA Text Editor'
|
||||
ClientHeight = 415
|
||||
ClientWidth = 722
|
||||
OnCreate = FormCreate
|
||||
OnDestroy = FormDestroy
|
||||
LCLVersion = '2.0.8.0'
|
||||
object BGRAVirtualScreen1: TBGRAVirtualScreen
|
||||
Left = 0
|
||||
Height = 383
|
||||
Top = 32
|
||||
Width = 704
|
||||
OnRedraw = BGRAVirtualScreen1Redraw
|
||||
Align = alClient
|
||||
Alignment = taLeftJustify
|
||||
BorderWidth = 1
|
||||
BorderStyle = bsSingle
|
||||
Color = clWhite
|
||||
Font.Height = 12
|
||||
ParentColor = False
|
||||
ParentFont = False
|
||||
TabOrder = 0
|
||||
TabStop = True
|
||||
OnMouseDown = BGRAVirtualScreen1MouseDown
|
||||
OnMouseMove = BGRAVirtualScreen1MouseMove
|
||||
OnMouseWheel = BGRAVirtualScreen1MouseWheel
|
||||
end
|
||||
object Panel1: TPanel
|
||||
Left = 0
|
||||
Height = 32
|
||||
Top = 0
|
||||
Width = 722
|
||||
Align = alTop
|
||||
ClientHeight = 32
|
||||
ClientWidth = 722
|
||||
ParentFont = False
|
||||
TabOrder = 1
|
||||
object SpinEdit_FontSize: TSpinEdit
|
||||
Left = 80
|
||||
Height = 21
|
||||
Top = 5
|
||||
Width = 58
|
||||
MaxValue = 50
|
||||
MinValue = 1
|
||||
OnChange = SpinEdit_FontSizeChange
|
||||
ParentFont = False
|
||||
TabOrder = 0
|
||||
Value = 15
|
||||
end
|
||||
object Label2: TLabel
|
||||
Left = 8
|
||||
Height = 16
|
||||
Top = 7
|
||||
Width = 55
|
||||
Caption = 'Font size'
|
||||
ParentColor = False
|
||||
ParentFont = False
|
||||
end
|
||||
object ToolBar1: TToolBar
|
||||
Left = 144
|
||||
Height = 27
|
||||
Top = 1
|
||||
Width = 80
|
||||
Align = alNone
|
||||
Caption = 'ToolBar1'
|
||||
Images = ImageList1
|
||||
ParentFont = False
|
||||
TabOrder = 1
|
||||
object ToolButtonLeftAlign: TToolButton
|
||||
Left = 1
|
||||
Top = 2
|
||||
Caption = 'Left alignment'
|
||||
ImageIndex = 0
|
||||
OnClick = ToolButtonLeftAlignClick
|
||||
end
|
||||
object ToolButtonCenterAlign: TToolButton
|
||||
Left = 24
|
||||
Top = 2
|
||||
Caption = 'Center'
|
||||
ImageIndex = 1
|
||||
OnClick = ToolButtonCenterAlignClick
|
||||
end
|
||||
object ToolButtonRightAlign: TToolButton
|
||||
Left = 47
|
||||
Top = 2
|
||||
Caption = 'Right alignment'
|
||||
ImageIndex = 2
|
||||
OnClick = ToolButtonRightAlignClick
|
||||
end
|
||||
end
|
||||
object CheckBox_FreeType: TCheckBox
|
||||
Left = 240
|
||||
Height = 18
|
||||
Top = 5
|
||||
Width = 99
|
||||
Caption = 'Use FreeType'
|
||||
OnChange = CheckBox_FreeTypeChange
|
||||
ParentFont = False
|
||||
TabOrder = 2
|
||||
end
|
||||
object CheckBox_ClearType: TCheckBox
|
||||
Left = 352
|
||||
Height = 18
|
||||
Top = 5
|
||||
Width = 120
|
||||
Caption = 'Enable ClearType'
|
||||
OnChange = CheckBox_ClearTypeChange
|
||||
ParentFont = False
|
||||
TabOrder = 3
|
||||
end
|
||||
end
|
||||
object ScrollBar1: TScrollBar
|
||||
Left = 704
|
||||
Height = 383
|
||||
Top = 32
|
||||
Width = 18
|
||||
Align = alRight
|
||||
Kind = sbVertical
|
||||
PageSize = 0
|
||||
TabOrder = 2
|
||||
OnChange = ScrollBar1Change
|
||||
end
|
||||
object TimerBlinkCaret: TTimer
|
||||
Interval = 500
|
||||
OnTimer = TimerBlinkCaretTimer
|
||||
left = 240
|
||||
top = 248
|
||||
end
|
||||
object ImageList1: TImageList
|
||||
left = 344
|
||||
top = 248
|
||||
Bitmap = {
|
||||
4C69030000001000000010000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000010000FF010000FF0100
|
||||
00FF010000FF010000FF010000FF010000FF010000FF010000FF010000FF0100
|
||||
00FF010000FF0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000010000FF010000FF0100
|
||||
00FF010000FF010000FF00000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000010000FF010000FF0100
|
||||
00FF010000FF010000FF010000FF010000FF010000FF00000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000010000FF010000FF0100
|
||||
00FF010000FF010000FF010000FF010000FF010000FF010000FF010000FF0000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000010000FF010000FF0100
|
||||
00FF010000FF010000FF010000FF010000FF010000FF010000FF010000FF0100
|
||||
00FF010000FF0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000010000FF010000FF0100
|
||||
00FF010000FF010000FF00000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000010000FF010000FF0100
|
||||
00FF010000FF010000FF010000FF010000FF010000FF010000FF010000FF0100
|
||||
00FF010000FF0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000010000FF010000FF010000FF010000FF010000FF0100008C000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000100
|
||||
00FF010000FF010000FF010000FF010000FF010000FF010000FF010000FF0000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000010000FF0100
|
||||
00FF010000FF010000FF010000FF010000FF010000FF010000FF010000FF0100
|
||||
00FF000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000010000FF010000FF0100
|
||||
00FF010000FF010000FF010000FF010000FF010000FF010000FF010000FF0100
|
||||
00FF010000FF0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000010000FF010000FF010000FF010000FF010000FF0100008C000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000010000FF010000FF0100
|
||||
00FF010000FF010000FF010000FF010000FF010000FF010000FF010000FF0100
|
||||
00FF010000FF0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000010000FF010000FF010000FF0100
|
||||
00FF010000FF0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
000000000000010000FF010000FF010000FF010000FF010000FF010000FF0100
|
||||
00FF010000FF0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000100
|
||||
00FF010000FF010000FF010000FF010000FF010000FF010000FF010000FF0100
|
||||
00FF010000FF0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000010000FF010000FF0100
|
||||
00FF010000FF010000FF010000FF010000FF010000FF010000FF010000FF0100
|
||||
00FF010000FF0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000010000FF010000FF010000FF0100
|
||||
00FF010000FF0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000
|
||||
}
|
||||
end
|
||||
end
|
792
bgrabitmap/test/testbiditext2/unit1.pas
Normal file
792
bgrabitmap/test/testbiditext2/unit1.pas
Normal file
@@ -0,0 +1,792 @@
|
||||
unit Unit1;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
|
||||
StdCtrls, Spin, ComCtrls, BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes,
|
||||
BGRATextBidi, BGRAFreeType, EasyLazFreeType, LazFreeTypeFontCollection,
|
||||
fgl, Types;
|
||||
|
||||
const
|
||||
CaretBlinkTimeMs = 500;
|
||||
ssShortcut = {$IFDEF DARWIN}ssMeta{$ELSE}ssCtrl{$ENDIF};
|
||||
|
||||
type
|
||||
TRenderedBrokenLineList = specialize TFPGObjectList<TBGRABitmap>;
|
||||
|
||||
{ TForm1 }
|
||||
|
||||
TForm1 = class(TForm)
|
||||
BGRAVirtualScreen1: TBGRAVirtualScreen;
|
||||
CheckBox_ClearType: TCheckBox;
|
||||
CheckBox_FreeType: TCheckBox;
|
||||
ImageList1: TImageList;
|
||||
Label2: TLabel;
|
||||
Panel1: TPanel;
|
||||
ScrollBar1: TScrollBar;
|
||||
SpinEdit_FontSize: TSpinEdit;
|
||||
TimerBlinkCaret: TTimer;
|
||||
ToolBar1: TToolBar;
|
||||
ToolButtonLeftAlign: TToolButton;
|
||||
ToolButtonCenterAlign: TToolButton;
|
||||
ToolButtonRightAlign: TToolButton;
|
||||
procedure BGRAVirtualScreen1MouseDown(Sender: TObject;
|
||||
Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: Integer);
|
||||
procedure BGRAVirtualScreen1MouseMove(Sender: TObject; Shift: TShiftState;
|
||||
X, Y: Integer);
|
||||
procedure BGRAVirtualScreen1MouseWheel(Sender: TObject; Shift: TShiftState;
|
||||
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
|
||||
procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);
|
||||
procedure CheckBox_ClearTypeChange(Sender: TObject);
|
||||
procedure CheckBox_FreeTypeChange(Sender: TObject);
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||||
procedure FormKeyUp(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState);
|
||||
procedure FormKeyPress(Sender: TObject; var Key: char);
|
||||
procedure ScrollBar1Change(Sender: TObject);
|
||||
procedure SpinEdit_FontSizeChange(Sender: TObject);
|
||||
procedure TimerBlinkCaretTimer(Sender: TObject);
|
||||
procedure ToolButtonCenterAlignClick(Sender: TObject);
|
||||
procedure ToolButtonLeftAlignClick(Sender: TObject);
|
||||
procedure ToolButtonRightAlignClick(Sender: TObject);
|
||||
private
|
||||
FFontRenderer: TBGRACustomFontRenderer;
|
||||
FTextLayout: TBidiTextLayout;
|
||||
FRenderedParagraphs: array of TRenderedBrokenLineList;
|
||||
FBlinkCaretTime: TDateTime;
|
||||
FBlinkCaretState: boolean;
|
||||
FSelStart,FSelLength: integer;
|
||||
FSelFirstClick,FSelLastClick: integer;
|
||||
FCurFirstParagraph,FCurLastParagraph: integer;
|
||||
FTestText: string;
|
||||
FInUnicode: boolean;
|
||||
FUnicodeValue: LongWord;
|
||||
function GetLayoutReady: boolean;
|
||||
function GetSelLastClick: integer;
|
||||
procedure LayoutBrokenLinesChanged({%H}ASender: TObject;
|
||||
AParagraphIndex: integer; ASubBrokenStart, ASubBrokenChangedCountBefore,
|
||||
ASubBrokenChangedCountAfter: integer; ASubBrokenTotalCountBefore,
|
||||
{%H}ASubBrokenTotalCountAfter: integer);
|
||||
procedure LayoutParagraphDeleted({%H}ASender: TObject; AParagraphIndex: integer);
|
||||
procedure LayoutParagraphMergedWithNext(ASender: TObject;
|
||||
AParagraphIndex: integer);
|
||||
procedure LayoutParagraphSplit({%H}ASender: TObject; AParagraphIndex: integer;
|
||||
ASubBrokenIndex, {%H-}ACharIndex: integer);
|
||||
procedure SetSelLastClick(AValue: integer);
|
||||
procedure SetSelLength(AValue: integer);
|
||||
procedure SetSelStart(AValue: integer);
|
||||
procedure FlushUnicode;
|
||||
procedure DiscardRenderedBrokenLines;
|
||||
procedure LayoutCompletelyChanged;
|
||||
public
|
||||
procedure UpdateCurrentParagraph;
|
||||
procedure UpdateSelectionFromFirstLastClick;
|
||||
procedure SetCurrentParagraphAlign(AAlign: TAlignment);
|
||||
procedure DeleteSelection;
|
||||
procedure InsertText(AText: string);
|
||||
procedure ShowCaret;
|
||||
property SelStart: integer read FSelStart write SetSelStart;
|
||||
property SelLength: integer read FSelLength write SetSelLength;
|
||||
property SelLastClick: integer read GetSelLastClick write SetSelLastClick;
|
||||
property LayoutReady: boolean read GetLayoutReady;
|
||||
end;
|
||||
|
||||
var
|
||||
Form1: TForm1;
|
||||
|
||||
implementation
|
||||
|
||||
uses BGRAText, LCLType, BGRAUTF8, Clipbrd, LCLIntf, math;
|
||||
|
||||
{$R *.lfm}
|
||||
|
||||
procedure SetClipboardAsText(Value: string);
|
||||
var
|
||||
strStream: TStringStream;
|
||||
begin
|
||||
strStream := TStringStream.Create(Value);
|
||||
Clipboard.SetFormat(PredefinedClipboardFormat(pcfText), strStream);
|
||||
strStream.Free;
|
||||
end;
|
||||
|
||||
{ TForm1 }
|
||||
|
||||
procedure TForm1.FormCreate(Sender: TObject);
|
||||
begin
|
||||
FTextLayout := nil;
|
||||
FFontRenderer := nil;
|
||||
FSelStart:= 0;
|
||||
FSelLength:= 0;
|
||||
FSelFirstClick := -1;
|
||||
FSelLastClick:= -1;
|
||||
TimerBlinkCaret.Interval := CaretBlinkTimeMs;
|
||||
FCurFirstParagraph:= -1;
|
||||
FCurLastParagraph:= -1;
|
||||
|
||||
BGRAVirtualScreen1.OnKeyDown:= @FormKeyDown;
|
||||
BGRAVirtualScreen1.OnKeyUp:= @FormKeyUp;
|
||||
BGRAVirtualScreen1.OnKeyPress:= @FormKeyPress;
|
||||
BGRAVirtualScreen1.Cursor := crIBeam;
|
||||
BGRAVirtualScreen1.BitmapAutoScale:= false;
|
||||
|
||||
FTestText := 'تحتوي العربية على 28 حرفاً مكتوباً. ويرى بعض اللغويين أنه يجب إضافة حرف الهمزة إلى حروف العربية، ليصبح عدد الحروف 29. تُكتب العربية من اليمين إلى اليسار - ومثلها اللغة الفارسية والعبرية على عكس كثير من اللغات العالمية - ومن أعلى الصفحة إلى أسفلها.'+LineEnding+
|
||||
'Arabic reversed "' + UTF8OverrideDirection('صباح الخير',false)+'". Arabic marks: "لاٍُ لٍُإ بًٍّ ةُِ ںْ رُ ٮَ بٔ".'+ LineEnding +
|
||||
#9'Le français est une langue indo-européenne de la famille des langues romanes. Le français s''est formé en France (variété de la « langue d''oïl », qui est la langue de la partie septentrionale du pays).'+LineEnding+
|
||||
'Glorious finds itself reversed as '+ UTF8OverrideDirection('"glorious"',True) + '. ' +
|
||||
'"Hello!" is '+ UTF8EmbedDirection('"مرحبا!"',True) + ' in arabic.' + LineEnding +
|
||||
'देवनागरी एक भारतीय लिपि है जिसमें अनेक भारतीय भाषाएँ तथा कई विदेशी भाषाएँ लिखी जाती हैं। यह बायें से दायें लिखी जाती है।' + LineEnding +
|
||||
'对于汉语的分支语言,学界主要有两种观点,一种观点将汉语定义为语言,并将官话、贛語、闽语、粤语、客家语、吴语、湘语七大语言定义为一级方言.'+LineEnding+
|
||||
'עִבְרִית היא שפה שמית, ממשפחת השפות האפרו-אסיאתיות, הידועה כשפתם של היהודים ושל השומרונים, אשר ניב מודרני שלה (עברית ישראלית) משמש כשפה הרשמית והעיקרית של מדינת ישראל.';
|
||||
|
||||
end;
|
||||
|
||||
procedure TForm1.FormDestroy(Sender: TObject);
|
||||
begin
|
||||
DiscardRenderedBrokenLines;
|
||||
FTextLayout.Free;
|
||||
FFontRenderer.Free;
|
||||
end;
|
||||
|
||||
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||||
|
||||
procedure MoveTo(ANewPos: integer);
|
||||
begin
|
||||
if ssShift in Shift then
|
||||
begin
|
||||
if ANewPos <> -1 then
|
||||
SelLastClick := ANewPos;
|
||||
end else
|
||||
begin
|
||||
if ANewPos <> -1 then
|
||||
SelStart := ANewPos;
|
||||
SelLength:= 0;
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
idxPara, newPos: Integer;
|
||||
begin
|
||||
if not LayoutReady then exit;
|
||||
|
||||
if (Key = VK_U) and ([ssCtrl,ssShift] <= Shift) then
|
||||
begin
|
||||
FlushUnicode;
|
||||
FInUnicode := true;
|
||||
FUnicodeValue:= 0;
|
||||
Key := 0;
|
||||
end else
|
||||
if FInUnicode then
|
||||
begin
|
||||
case Key of
|
||||
VK_DELETE: begin
|
||||
FUnicodeValue := FUnicodeValue shr 4;
|
||||
end;
|
||||
VK_0..VK_9: begin
|
||||
FUnicodeValue := (FUnicodeValue shl 4) + (Key - VK_0);
|
||||
end;
|
||||
VK_NUMPAD0..VK_NUMPAD9: begin
|
||||
FUnicodeValue := (FUnicodeValue shl 4) + (Key - VK_NUMPAD0);
|
||||
end;
|
||||
VK_A..VK_F: begin
|
||||
FUnicodeValue := (FUnicodeValue shl 4) + (Key - VK_A + 10);
|
||||
end;
|
||||
else
|
||||
FlushUnicode;
|
||||
end;
|
||||
if (FUnicodeValue >= $10FFF0) or
|
||||
(FUnicodeValue >= $11000) then
|
||||
FlushUnicode;
|
||||
Key := 0;
|
||||
end else
|
||||
if KEY = VK_DELETE then
|
||||
begin
|
||||
if SelLength > 0 then DeleteSelection
|
||||
else
|
||||
begin
|
||||
FTextLayout.DeleteText(SelStart, 1);
|
||||
SelStart := SelStart + FTextLayout.IncludeNonSpacingChars(SelStart, 0);
|
||||
ShowCaret;
|
||||
end;
|
||||
Key := 0;
|
||||
end else
|
||||
if (Key = VK_LEFT) or (Key = VK_RIGHT) then
|
||||
begin
|
||||
if (Key = VK_LEFT) xor FTextLayout.ParagraphRightToLeft[FTextLayout.GetParagraphAt(SelLastClick)] then
|
||||
begin
|
||||
if SelLastClick > 0 then
|
||||
newPos := SelLastClick - FTextLayout.IncludeNonSpacingCharsBefore(SelLastClick,1)
|
||||
else newPos := -1;
|
||||
|
||||
MoveTo(newPos);
|
||||
end else
|
||||
begin
|
||||
if SelLastClick < FTextLayout.CharCount then
|
||||
newPos := SelLastClick + FTextLayout.IncludeNonSpacingChars(SelLastClick,1)
|
||||
else newPos := -1;
|
||||
|
||||
MoveTo(newPos);
|
||||
end;
|
||||
Key := 0;
|
||||
end else
|
||||
if (Key = VK_UP) or (Key = VK_DOWN) then
|
||||
begin
|
||||
if Key = VK_UP then
|
||||
newPos := FTextLayout.FindTextAbove(SelLastClick)
|
||||
else
|
||||
newPos := FTextLayout.FindTextBelow(SelLastClick);
|
||||
|
||||
MoveTo(newPos);
|
||||
Key := 0;
|
||||
end else
|
||||
if Key = VK_HOME then
|
||||
begin
|
||||
idxPara := FTextLayout.GetParagraphAt(SelLastClick);
|
||||
if ssCtrl in Shift then newPos := 0 else
|
||||
newPos := FTextLayout.ParagraphStartIndex[idxPara];
|
||||
MoveTo(newPos);
|
||||
Key := 0;
|
||||
end else
|
||||
if Key = VK_END then
|
||||
begin
|
||||
idxPara := FTextLayout.GetParagraphAt(SelLastClick);
|
||||
if ssCtrl in Shift then newPos := FTextLayout.CharCount else
|
||||
newPos := FTextLayout.ParagraphEndIndexBeforeParagraphSeparator[idxPara];
|
||||
MoveTo(newPos);
|
||||
Key := 0;
|
||||
end else
|
||||
if Key = VK_RETURN then
|
||||
begin
|
||||
if SelLength > 0 then DeleteSelection;
|
||||
if ssShift in Shift then
|
||||
begin
|
||||
SelStart := SelStart + FTextLayout.InsertLineSeparator(SelStart);
|
||||
end else
|
||||
InsertText(LineEnding);
|
||||
Key := 0;
|
||||
end else
|
||||
if Key = VK_TAB then
|
||||
begin
|
||||
if SelLength > 0 then DeleteSelection;
|
||||
InsertText(#9);
|
||||
Key := 0;
|
||||
end else
|
||||
If (Key = VK_C) and (ssShortcut in Shift) then
|
||||
begin
|
||||
if SelLength> 0 then
|
||||
SetClipboardAsText(FTextLayout.CopyText(SelStart, SelLength));
|
||||
Key := 0;
|
||||
end else
|
||||
If (Key = VK_X) and (ssShortcut in Shift) then
|
||||
begin
|
||||
if SelLength > 0 then
|
||||
begin
|
||||
SetClipboardAsText(FTextLayout.CopyText(SelStart, SelLength));
|
||||
DeleteSelection;
|
||||
end;
|
||||
Key := 0;
|
||||
end else
|
||||
If (Key = VK_V) and (ssShortcut in Shift) then
|
||||
begin
|
||||
InsertText(Clipboard.AsText);
|
||||
Key := 0;
|
||||
end else
|
||||
If (Key = VK_A) and (ssShortcut in Shift) then
|
||||
begin
|
||||
SelStart:= 0;
|
||||
SelLength:= FTextLayout.CharCount;
|
||||
Key := 0;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||||
begin
|
||||
if FInUnicode then
|
||||
begin
|
||||
if (Key = VK_CONTROL) or (Key = VK_SHIFT) then
|
||||
FlushUnicode;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.FormKeyPress(Sender: TObject; var Key: char);
|
||||
var
|
||||
delCount: Integer;
|
||||
begin
|
||||
if not LayoutReady then exit;
|
||||
|
||||
if Key = #8 then
|
||||
begin
|
||||
if SelLength > 0 then DeleteSelection
|
||||
else
|
||||
begin
|
||||
if SelStart > 0 then
|
||||
begin
|
||||
delCount := FTextLayout.DeleteTextBefore(SelStart, 1);
|
||||
SelStart := SelStart - delCount;
|
||||
SelStart := SelStart + FTextLayout.IncludeNonSpacingChars(SelStart, 0);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else
|
||||
if Key = #13 then
|
||||
InsertText(LineEnding)
|
||||
else
|
||||
InsertText(Key);
|
||||
Key := #0
|
||||
end;
|
||||
|
||||
procedure TForm1.ScrollBar1Change(Sender: TObject);
|
||||
begin
|
||||
BGRAVirtualScreen1.DiscardBitmap;
|
||||
end;
|
||||
|
||||
procedure TForm1.SpinEdit_FontSizeChange(Sender: TObject);
|
||||
begin
|
||||
LayoutCompletelyChanged;
|
||||
end;
|
||||
|
||||
procedure TForm1.TimerBlinkCaretTimer(Sender: TObject);
|
||||
begin
|
||||
BGRAVirtualScreen1.DiscardBitmap;
|
||||
end;
|
||||
|
||||
procedure TForm1.ToolButtonCenterAlignClick(Sender: TObject);
|
||||
begin
|
||||
SetCurrentParagraphAlign(taCenter);
|
||||
end;
|
||||
|
||||
procedure TForm1.ToolButtonLeftAlignClick(Sender: TObject);
|
||||
begin
|
||||
SetCurrentParagraphAlign(taLeftJustify);
|
||||
end;
|
||||
|
||||
procedure TForm1.ToolButtonRightAlignClick(Sender: TObject);
|
||||
begin
|
||||
SetCurrentParagraphAlign(taRightJustify);
|
||||
end;
|
||||
|
||||
function TForm1.GetLayoutReady: boolean;
|
||||
begin
|
||||
result := Assigned(FTextLayout) and Assigned(FFontRenderer);
|
||||
end;
|
||||
|
||||
function TForm1.GetSelLastClick: integer;
|
||||
begin
|
||||
if FSelLastClick = -1 then
|
||||
result := FSelStart + FSelLength
|
||||
else
|
||||
result := FSelLastClick;
|
||||
end;
|
||||
|
||||
procedure TForm1.LayoutBrokenLinesChanged(ASender: TObject;
|
||||
AParagraphIndex: integer; ASubBrokenStart, ASubBrokenChangedCountBefore,
|
||||
ASubBrokenChangedCountAfter: integer; ASubBrokenTotalCountBefore,
|
||||
ASubBrokenTotalCountAfter: integer);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
if (AParagraphIndex < 0) or (AParagraphIndex > high(FRenderedParagraphs)) or
|
||||
(FRenderedParagraphs[AParagraphIndex] = nil) then exit;
|
||||
if ASubBrokenTotalCountBefore <> FRenderedParagraphs[AParagraphIndex].Count then
|
||||
FreeAndNil(FRenderedParagraphs[AParagraphIndex])
|
||||
else
|
||||
begin
|
||||
for i := 0 to ASubBrokenChangedCountBefore-1 do
|
||||
FRenderedParagraphs[AParagraphIndex].Delete(ASubBrokenStart);
|
||||
for i := 0 to ASubBrokenChangedCountAfter-1 do
|
||||
FRenderedParagraphs[AParagraphIndex].Insert(ASubBrokenStart, nil);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.DiscardRenderedBrokenLines;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i := 0 to high(FRenderedParagraphs) do
|
||||
FreeAndNil(FRenderedParagraphs[i]);
|
||||
end;
|
||||
|
||||
procedure TForm1.LayoutCompletelyChanged;
|
||||
begin
|
||||
if Assigned(FTextLayout) then FTextLayout.InvalidateLayout;
|
||||
DiscardRenderedBrokenLines;
|
||||
BGRAVirtualScreen1.DiscardBitmap;
|
||||
end;
|
||||
|
||||
procedure TForm1.LayoutParagraphDeleted(ASender: TObject;
|
||||
AParagraphIndex: integer);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
if (AParagraphIndex >= 0) and (AParagraphIndex <= high(FRenderedParagraphs)) then
|
||||
begin
|
||||
FreeAndNil(FRenderedParagraphs[AParagraphIndex]);
|
||||
for i := AParagraphIndex to high(FRenderedParagraphs)-1 do
|
||||
FRenderedParagraphs[i] := FRenderedParagraphs[i+1];
|
||||
setlength(FRenderedParagraphs, length(FRenderedParagraphs)-1);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.LayoutParagraphMergedWithNext(ASender: TObject;
|
||||
AParagraphIndex: integer);
|
||||
var
|
||||
i, insertIndex: Integer;
|
||||
renderedBrokenLine: TBGRABitmap;
|
||||
begin
|
||||
insertIndex := FRenderedParagraphs[AParagraphIndex].Count;
|
||||
for i := FRenderedParagraphs[AParagraphIndex+1].Count-1 downto 0 do
|
||||
begin
|
||||
renderedBrokenLine := FRenderedParagraphs[AParagraphIndex+1].Items[i];
|
||||
FRenderedParagraphs[AParagraphIndex].Insert(insertIndex, renderedBrokenLine);
|
||||
FRenderedParagraphs[AParagraphIndex+1].Extract(renderedBrokenLine);
|
||||
end;
|
||||
LayoutParagraphDeleted(ASender, AParagraphIndex+1);
|
||||
end;
|
||||
|
||||
procedure TForm1.LayoutParagraphSplit(ASender: TObject;
|
||||
AParagraphIndex: integer; ASubBrokenIndex, ACharIndex: integer);
|
||||
var
|
||||
i, j: Integer;
|
||||
renderedBrokenLine: TBGRABitmap;
|
||||
begin
|
||||
if (AParagraphIndex >= 0) and (AParagraphIndex <= high(FRenderedParagraphs)) then
|
||||
begin
|
||||
setlength(FRenderedParagraphs, length(FRenderedParagraphs)+1);
|
||||
for i := high(FRenderedParagraphs) downto AParagraphIndex+2 do
|
||||
FRenderedParagraphs[i] := FRenderedParagraphs[i-1];
|
||||
FRenderedParagraphs[AParagraphIndex+1] := TRenderedBrokenLineList.Create;
|
||||
for j := FRenderedParagraphs[AParagraphIndex].Count-1 downto ASubBrokenIndex+1 do
|
||||
begin
|
||||
renderedBrokenLine := FRenderedParagraphs[AParagraphIndex].Items[j];
|
||||
FRenderedParagraphs[AParagraphIndex+1].Insert(0, renderedBrokenLine);
|
||||
FRenderedParagraphs[AParagraphIndex].Extract(renderedBrokenLine);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.SetSelLastClick(AValue: integer);
|
||||
begin
|
||||
if FSelFirstClick = -1 then
|
||||
FSelFirstClick := FSelStart;
|
||||
FSelLastClick:= AValue;
|
||||
UpdateSelectionFromFirstLastClick;
|
||||
end;
|
||||
|
||||
procedure TForm1.SetSelLength(AValue: integer);
|
||||
begin
|
||||
if FSelLength=AValue then Exit;
|
||||
FSelLength:=AValue;
|
||||
FSelFirstClick:=-1;
|
||||
FSelLastClick:=-1;
|
||||
ShowCaret;
|
||||
end;
|
||||
|
||||
procedure TForm1.SetSelStart(AValue: integer);
|
||||
begin
|
||||
if FSelStart=AValue then Exit;
|
||||
FSelStart:=AValue;
|
||||
if FSelStart + FSelLength > FTextLayout.CharCount then
|
||||
FSelLength := FTextLayout.CharCount - FSelStart;
|
||||
FSelFirstClick:=-1;
|
||||
FSelLastClick:=-1;
|
||||
ShowCaret;
|
||||
end;
|
||||
|
||||
procedure TForm1.FlushUnicode;
|
||||
begin
|
||||
if not FInUnicode then exit;
|
||||
FInUnicode := false;
|
||||
InsertText(UnicodeCharToUTF8(FUnicodeValue));
|
||||
end;
|
||||
|
||||
procedure TForm1.UpdateCurrentParagraph;
|
||||
var curAlign: TAlignment;
|
||||
begin
|
||||
if not LayoutReady then exit;
|
||||
|
||||
FCurFirstParagraph:= FTextLayout.GetParagraphAt(SelStart);
|
||||
FCurLastParagraph:= FTextLayout.GetParagraphAt(SelStart+SelLength);
|
||||
case FTextLayout.ParagraphAlignment[FCurFirstParagraph] of
|
||||
btaCenter: curAlign := taCenter;
|
||||
btaLeftJustify: curAlign := taLeftJustify;
|
||||
btaRightJustify: curAlign:= taRightJustify;
|
||||
btaOpposite: if FTextLayout.ParagraphRightToLeft[FCurFirstParagraph] then
|
||||
curAlign:= taLeftJustify else curAlign:= taRightJustify;
|
||||
else
|
||||
if FTextLayout.ParagraphRightToLeft[FCurFirstParagraph] then
|
||||
curAlign:= taRightJustify else curAlign:= taLeftJustify;
|
||||
end;
|
||||
ToolButtonLeftAlign.Down := curAlign = taLeftJustify;
|
||||
ToolButtonCenterAlign.Down := curAlign = taCenter;
|
||||
ToolButtonRightAlign.Down := curAlign = taRightJustify;
|
||||
end;
|
||||
|
||||
procedure TForm1.UpdateSelectionFromFirstLastClick;
|
||||
begin
|
||||
if FSelLastClick < FSelFirstClick then
|
||||
begin
|
||||
FSelStart := FSelLastClick;
|
||||
FSelLength:= FSelFirstClick-FSelLastClick;
|
||||
end else
|
||||
begin
|
||||
FSelStart:= FSelFirstClick;
|
||||
FSelLength:= FSelLastClick-FSelFirstClick;
|
||||
end;
|
||||
ShowCaret;
|
||||
end;
|
||||
|
||||
procedure TForm1.SetCurrentParagraphAlign(AAlign: TAlignment);
|
||||
var
|
||||
i: Integer;
|
||||
newAlign: TBidiTextAlignment;
|
||||
begin
|
||||
if LayoutReady and (FCurFirstParagraph <> -1) then
|
||||
begin
|
||||
for i := FCurFirstParagraph to FCurLastParagraph do
|
||||
begin
|
||||
case AALign of
|
||||
taLeftJustify: if FTextLayout.ParagraphRightToLeft[i] then
|
||||
newAlign := btaOpposite
|
||||
else newAlign := btaNatural;
|
||||
taRightJustify: if FTextLayout.ParagraphRightToLeft[i] then
|
||||
newAlign := btaNatural
|
||||
else newAlign := btaOpposite;
|
||||
else {taCenter:} newAlign := btaCenter;
|
||||
end;
|
||||
FTextLayout.ParagraphAlignment[i] := newAlign;
|
||||
end;
|
||||
|
||||
BGRAVirtualScreen1.DiscardBitmap;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.DeleteSelection;
|
||||
begin
|
||||
if SelLength <> 0 then
|
||||
begin
|
||||
FTextLayout.DeleteText(SelStart, SelLength);
|
||||
SelStart := SelStart + FTextLayout.IncludeNonSpacingChars(SelStart, 0);
|
||||
SelLength:= 0;
|
||||
ShowCaret;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.InsertText(AText: string);
|
||||
var
|
||||
insertCount: Integer;
|
||||
begin
|
||||
if not LayoutReady then exit;
|
||||
DeleteSelection;
|
||||
insertCount := FTextLayout.InsertText(AText, SelStart);
|
||||
SelStart := SelStart + insertCount;
|
||||
SelStart := SelStart + FTextLayout.IncludeNonSpacingChars(SelStart, 0);
|
||||
ShowCaret;
|
||||
end;
|
||||
|
||||
procedure TForm1.ShowCaret;
|
||||
begin
|
||||
FBlinkCaretState := true;
|
||||
FBlinkCaretTime:= Now;
|
||||
BGRAVirtualScreen1.DiscardBitmap;
|
||||
TimerBlinkCaret.Enabled := false;
|
||||
TimerBlinkCaret.Enabled := true;
|
||||
end;
|
||||
|
||||
procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);
|
||||
var
|
||||
zoom, prevAvailWidth: single;
|
||||
caretColor, selectionColor: TBGRAPixel;
|
||||
newTime: TDateTime;
|
||||
oldTopLeft: TPointF;
|
||||
i: Integer;
|
||||
startBroken, endBroken, j, countBroken: LongInt;
|
||||
renderedBroken: TBGRABitmap;
|
||||
renderRect: TRect;
|
||||
begin
|
||||
zoom := BGRAVirtualScreen1.BitmapScale * Screen.PixelsPerInch / 96;
|
||||
if FFontRenderer = nil then
|
||||
begin
|
||||
if CheckBox_FreeType.Checked then
|
||||
begin
|
||||
FFontRenderer := TBGRAFreeTypeFontRenderer.Create;
|
||||
FFontRenderer.FontName := 'Liberation Serif';
|
||||
end else
|
||||
begin
|
||||
FFontRenderer := TLCLFontRenderer.Create;
|
||||
FFontRenderer.FontName := {$IFDEF LINUX}'Liberation Serif'{$ELSE}'serif'{$ENDIF};
|
||||
End;
|
||||
end;
|
||||
if CheckBox_ClearType.Checked then
|
||||
begin
|
||||
//force ClearType to RGB if disabled on the system
|
||||
if fqFineClearType() = fqFineAntialiasing then
|
||||
FFontRenderer.FontQuality:= fqFineClearTypeRGB
|
||||
else
|
||||
FFontRenderer.FontQuality:= fqSystemClearType;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if CheckBox_FreeType.Checked then
|
||||
FFontRenderer.FontQuality:= fqFineAntialiasing
|
||||
else
|
||||
FFontRenderer.FontQuality:= fqSystem;
|
||||
end;
|
||||
FFontRenderer.FontEmHeightF:= SpinEdit_FontSize.Value * zoom;
|
||||
|
||||
if FTextLayout = nil then
|
||||
begin
|
||||
FTextLayout:= TBidiTextLayout.Create(FFontRenderer, FTestText);
|
||||
FTextLayout.ParagraphSpacingBelow:= 0.25;
|
||||
FTextLayout.ParagraphSpacingAbove:= 0.25;
|
||||
FTextLayout.OnParagraphDeleted:=@LayoutParagraphDeleted;
|
||||
FTextLayout.OnParagraphMergedWithNext:=@LayoutParagraphMergedWithNext;
|
||||
FTextLayout.OnParagraphSplit:=@LayoutParagraphSplit;
|
||||
FTextLayout.OnBrokenLinesChanged:=@LayoutBrokenLinesChanged;
|
||||
end else
|
||||
FTextLayout.FontRenderer := FFontRenderer;
|
||||
|
||||
prevAvailWidth := FTextLayout.AvailableWidth;
|
||||
FTextLayout.AvailableWidth := Bitmap.Width - 8*zoom;
|
||||
FTextLayout.TopLeft := PointF(4*zoom,4*zoom);
|
||||
if prevAvailWidth <> FTextLayout.AvailableWidth then
|
||||
DiscardRenderedBrokenLines;
|
||||
FTextLayout.ComputeLayoutIfNeeded;
|
||||
|
||||
oldTopLeft := FTextLayout.TopLeft;
|
||||
ScrollBar1.Min:= 0;
|
||||
ScrollBar1.Max:= round(FTextLayout.TotalTextHeight + 8*zoom);
|
||||
ScrollBar1.PageSize:= Bitmap.Height;
|
||||
ScrollBar1.LargeChange:= Bitmap.Height*2 div 3;
|
||||
ScrollBar1.SmallChange:= round(FTextLayout.LineHeight);
|
||||
if ScrollBar1.Position > max(0, ScrollBar1.Max - ScrollBar1.PageSize) then
|
||||
ScrollBar1.Position := max(0, ScrollBar1.Max - ScrollBar1.PageSize);
|
||||
|
||||
caretColor := BGRA(0,0,255);
|
||||
selectionColor := BGRA(0,0,255,128);
|
||||
|
||||
newTime := Now;
|
||||
if newTime > FBlinkCaretTime + (CaretBlinkTimeMs/1000/24/60/60) then
|
||||
begin
|
||||
FBlinkCaretTime:= newTime;
|
||||
FBlinkCaretState:= not FBlinkCaretState;
|
||||
end;
|
||||
|
||||
FTextLayout.TopLeft := oldTopLeft + PointF(0, -ScrollBar1.Position);
|
||||
if FBlinkCaretState and (SelLength = 0) and BGRAVirtualScreen1.Focused then
|
||||
FTextLayout.DrawCaret(Bitmap, SelStart, BGRA(caretColor.red,caretColor.green,caretColor.blue,140), BGRA(caretColor.red,caretColor.green,caretColor.blue,100));
|
||||
|
||||
for i := FTextLayout.ParagraphCount to high(FRenderedParagraphs) do
|
||||
FreeAndNil(FRenderedParagraphs[i]);
|
||||
setlength(FRenderedParagraphs, FTextLayout.ParagraphCount);
|
||||
|
||||
for i := 0 to FTextLayout.ParagraphCount-1 do
|
||||
begin
|
||||
if FRenderedParagraphs[i] = nil then
|
||||
FRenderedParagraphs[i] := TRenderedBrokenLineList.Create;
|
||||
startBroken := FTextLayout.ParagraphStartBrokenLine[i];
|
||||
endBroken := FTextLayout.ParagraphEndBrokenLine[i];
|
||||
for j := startBroken to endBroken - 1 do
|
||||
begin
|
||||
if j - startBroken >= FRenderedParagraphs[i].Count then
|
||||
FRenderedParagraphs[i].Add(nil);
|
||||
if j - startBroken < FRenderedParagraphs[i].Count then
|
||||
begin
|
||||
renderRect := RectWithSize(0, round(oldTopLeft.y + FTextLayout.BrokenLineRectF[j].Top) - ScrollBar1.Position,
|
||||
Bitmap.Width, ceil(FTextLayout.BrokenLineRectF[j].Height));
|
||||
if renderRect.IntersectsWith(Bitmap.ClipRect) then
|
||||
begin
|
||||
if FRenderedParagraphs[i].Items[j - startBroken] = nil then
|
||||
begin
|
||||
renderedBroken := TBGRABitmap.Create(Bitmap.Width,
|
||||
ceil(FTextLayout.BrokenLineRectF[j].Height), BGRAVirtualScreen1.Color);
|
||||
FTextLayout.TopLeft := PointF(oldTopLeft.x, -FTextLayout.BrokenLineRectF[j].Top);
|
||||
FTextLayout.DrawBrokenLines(renderedBroken, j, j+1);
|
||||
FRenderedParagraphs[i].Items[j - startBroken] := renderedBroken;
|
||||
end;
|
||||
Bitmap.PutImage(renderRect.Left, renderRect.Top,
|
||||
FRenderedParagraphs[i].Items[j - startBroken], dmSet);
|
||||
end else
|
||||
FRenderedParagraphs[i].Items[j - startBroken] := nil;
|
||||
end;
|
||||
end;
|
||||
countBroken := endBroken - startBroken;
|
||||
while FRenderedParagraphs[i].Count > countBroken do
|
||||
FRenderedParagraphs[i].Delete(countBroken);
|
||||
end;
|
||||
FTextLayout.TopLeft := oldTopLeft + PointF(0, -ScrollBar1.Position);
|
||||
|
||||
FTextLayout.DrawSelection(Bitmap, SelStart, SelStart+SelLength, selectionColor, BGRA(0,0,192),1);
|
||||
|
||||
if FBlinkCaretState and (SelLength = 0) then
|
||||
FTextLayout.DrawCaret(Bitmap, SelStart, BGRA(caretColor.red,caretColor.green,caretColor.blue,140), BGRA(caretColor.red,caretColor.green,caretColor.blue,100));
|
||||
|
||||
UpdateCurrentParagraph;
|
||||
FTextLayout.TopLeft := oldTopLeft;
|
||||
//let some time for events
|
||||
TimerBlinkCaret.Enabled := false;
|
||||
TimerBlinkCaret.Enabled := true;
|
||||
end;
|
||||
|
||||
procedure TForm1.CheckBox_ClearTypeChange(Sender: TObject);
|
||||
begin
|
||||
LayoutCompletelyChanged;
|
||||
end;
|
||||
|
||||
procedure TForm1.CheckBox_FreeTypeChange(Sender: TObject);
|
||||
begin
|
||||
LayoutCompletelyChanged;
|
||||
FreeAndNil(FFontRenderer);
|
||||
end;
|
||||
|
||||
procedure TForm1.BGRAVirtualScreen1MouseDown(Sender: TObject;
|
||||
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
||||
var
|
||||
index: Integer;
|
||||
begin
|
||||
BGRAVirtualScreen1.SetFocus;
|
||||
if Button = mbLeft then
|
||||
begin
|
||||
index := FTextLayout.GetCharIndexAt(PointF(X, Y) * BGRAVirtualScreen1.BitmapScale
|
||||
+ PointF(0,ScrollBar1.Position));
|
||||
FSelFirstClick:= index;
|
||||
FSelLastClick:= index;
|
||||
UpdateSelectionFromFirstLastClick;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.BGRAVirtualScreen1MouseMove(Sender: TObject;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
var
|
||||
index: Integer;
|
||||
begin
|
||||
if (FSelFirstClick <> -1) and (ssLeft in Shift) then
|
||||
begin
|
||||
index := FTextLayout.GetCharIndexAt(PointF(X,Y) * BGRAVirtualScreen1.BitmapScale
|
||||
+ PointF(0,ScrollBar1.Position));
|
||||
FSelLastClick:= index;
|
||||
UpdateSelectionFromFirstLastClick;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.BGRAVirtualScreen1MouseWheel(Sender: TObject;
|
||||
Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
|
||||
var Handled: Boolean);
|
||||
begin
|
||||
ScrollBar1.Position := ScrollBar1.Position - (WheelDelta * ScrollBar1.SmallChange div 120);
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
EasyLazFreeType.FontCollection := TFreeTypeFontCollection.Create;
|
||||
EasyLazFreeType.FontCollection.AddFolder(ExtractFilePath(Application.ExeName)
|
||||
{$IFDEF DARWIN} + '../../../' {$ENDIF});
|
||||
|
||||
finalization
|
||||
|
||||
FreeAndNil(EasyLazFreeType.FontCollection);
|
||||
|
||||
end.
|
||||
|
Reference in New Issue
Block a user