1 {
2 Copyright (C) Alexey Torgashin, uvviewsoft.com
3 License: MPL 2.0 or LGPL
4 }
5 unit ATSynEdit_WrapInfo;
6 
7 {$mode objfpc}{$H+}
8 {$ModeSwitch advancedrecords}
9 {$Z1}
10 
11 interface
12 
13 uses
14   Classes, SysUtils,
15   ATStrings,
16   ATSynEdit_fgl;
17 
18 type
19   TATWrapItemFinal = (
20     cWrapItemFinal,
21     cWrapItemCollapsed,
22     cWrapItemMiddle
23     );
24 
25 type
26   { TATWrapItem }
27 
28   TATWrapItem = packed record
29     NLineIndex: integer;
30     NCharIndex: integer;
31     NLength: integer;
32     NIndent: word;
33     NFinal: TATWrapItemFinal;
34     bInitial: boolean;
35     procedure Init(ALineIndex, ACharIndex, ALength, AIndent: integer; AFinal: TATWrapItemFinal; AInitial: boolean); inline;
ContainsPosnull36     function ContainsPos(AX, AY: integer): boolean;
37     class operator=(const A, B: TATWrapItem): boolean;
38   end;
39 
40 type
41   TATWrapItems = specialize TFPGList<TATWrapItem>;
42 
43 type
44   { TATWrapInfo }
45 
46   TATWrapInfo = class
47   private
48     FList: TATWrapItems;
49     FStrings: TATStrings;
50     FVirtualMode: boolean;
GetDatanull51     function GetData(AIndex: integer): TATWrapItem;
52     procedure SetVirtualMode(AValue: boolean);
IsLineFoldednull53     function IsLineFolded(ALine: integer): boolean;
54   public
55     VisibleColumns: integer;
56     WrapColumn: integer;
57     EditorIndex: integer;
58     constructor Create; virtual;
59     destructor Destroy; override;
60     procedure Clear;
61     property StringsObj: TATStrings read FStrings write FStrings;
62     property VirtualMode: boolean read FVirtualMode write SetVirtualMode;
Countnull63     function Count: integer; inline;
IsIndexValidnull64     function IsIndexValid(N: integer): boolean; inline;
65     property Data[N: integer]: TATWrapItem read GetData; default;
66     procedure Add(const AData: TATWrapItem);
67     procedure Delete(N: integer);
68     procedure Insert(N: integer; const AItem: TATWrapItem);
69     procedure FindIndexesOfLineNumber(ALineNum: integer; out AFrom, ATo: integer);
FindIndexOfCaretPosnull70     function FindIndexOfCaretPos(APos: TPoint): integer;
71     procedure SetCapacity(N: integer);
72     procedure ReplaceItems(AFrom, ATo: integer; AItems: TATWrapItems);
73   end;
74 
75 
76 implementation
77 
78 uses
79   Math, Dialogs, Forms;
80 
81 { TATWrapItem }
82 
83 procedure TATWrapItem.Init(ALineIndex, ACharIndex, ALength, AIndent: integer;
84   AFinal: TATWrapItemFinal; AInitial: boolean);
85 begin
86   NLineIndex:= ALineIndex;
87   NCharIndex:= ACharIndex;
88   NLength:= ALength;
89   NIndent:= AIndent;
90   NFinal:= AFinal;
91   bInitial:= AInitial;
92 end;
93 
TATWrapItem.ContainsPosnull94 function TATWrapItem.ContainsPos(AX, AY: integer): boolean;
95 begin
96   Result:= false;
97   if AY<>NLineIndex then exit;
98   if AX<NCharIndex-1 then exit;
99   if NFinal<>cWrapItemFinal then
100     if AX>=NCharIndex-1+NLength then exit;
101   Result:= true;
102 end;
103 
104 class operator TATWrapItem.=(const A, B: TATWrapItem): boolean;
105 begin
106   Result:= false;
107 end;
108 
109 { TATWrapInfo }
110 
GetDatanull111 function TATWrapInfo.GetData(AIndex: integer): TATWrapItem;
112 begin
113   if FVirtualMode then
114     Result.Init(AIndex, 1, FStrings.LinesLen[AIndex], 0, cWrapItemFinal, true)
115   else
116   begin
117     if AIndex>=0 then
118       Result:= FList[AIndex]
119     else
120       FillChar(Result, SizeOf(Result), 0);
121   end;
122 end;
123 
124 procedure TATWrapInfo.SetVirtualMode(AValue: boolean);
125 begin
126   if FVirtualMode=AValue then Exit;
127   FVirtualMode:= AValue;
128 
129   {
130   don't clear:
131   adapter fills Fold ranges after a pause... this causes nasty empty screen of control
132   }
133   //if FVirtualMode then
134   //  Clear;
135 end;
136 
IsLineFoldednull137 function TATWrapInfo.IsLineFolded(ALine: integer): boolean;
138 begin
139   Result:= false;
140   if not StringsObj.IsIndexValid(ALine) then exit;
141   Result:= StringsObj.LinesHidden[ALine, EditorIndex];
142 end;
143 
144 constructor TATWrapInfo.Create;
145 begin
146   FList:= TATWrapItems.Create;
147   FVirtualMode:= false;
148 end;
149 
150 destructor TATWrapInfo.Destroy;
151 begin
152   Clear;
153   FreeAndNil(FList);
154   inherited;
155 end;
156 
157 procedure TATWrapInfo.Clear; inline;
158 begin
159   FList.Clear;
160 end;
161 
TATWrapInfo.Countnull162 function TATWrapInfo.Count: integer; inline;
163 begin
164   if FVirtualMode then
165     Result:= FStrings.Count
166   else
167     Result:= FList.Count;
168 end;
169 
TATWrapInfo.IsIndexValidnull170 function TATWrapInfo.IsIndexValid(N: integer): boolean; inline;
171 begin
172   Result:= (N>=0) and (N<Count);
173 end;
174 
175 procedure TATWrapInfo.Add(const AData: TATWrapItem); inline;
176 begin
177   if FVirtualMode then exit;
178   FList.Add(AData);
179 end;
180 
181 procedure TATWrapInfo.Delete(N: integer); inline;
182 begin
183   if FVirtualMode then exit;
184   FList.Delete(N);
185 end;
186 
187 procedure TATWrapInfo.Insert(N: integer; const AItem: TATWrapItem); inline;
188 begin
189   if FVirtualMode then exit;
190   if N>=FList.Count then
191     FList.Add(AItem)
192   else
193     FList.Insert(N, AItem);
194 end;
195 
196 procedure TATWrapInfo.FindIndexesOfLineNumber(ALineNum: integer; out AFrom, ATo: integer);
197 var
198   a, b, m, dif: integer;
199 begin
200   AFrom:= -1;
201   ATo:= -1;
202 
203   if IsLineFolded(ALineNum) then Exit;
204 
205   a:= 0;
206   b:= Count-1;
207 
208   repeat
209     if a>b then exit;
210     m:= (a+b+1) div 2;
211 
212     dif:= Data[m].NLineIndex-ALineNum;
213     if dif=0 then
214       Break;
215     if dif>0 then
216       b:= m-1
217     else
218       a:= m+1;
219   until false;
220 
221   AFrom:= m;
222   ATo:= m;
223   while (AFrom>0) and (Data[AFrom-1].NLineIndex=ALineNum) do Dec(AFrom);
224   while (ATo<Count-1) and (Data[ATo+1].NLineIndex=ALineNum) do Inc(ATo);
225 end;
226 
TATWrapInfo.FindIndexOfCaretPosnull227 function TATWrapInfo.FindIndexOfCaretPos(APos: TPoint): integer;
228 var
229   NFrom, NTo, i: integer;
230 begin
231   Result:= -1;
232   FindIndexesOfLineNumber(APos.Y, NFrom, NTo);
233   if NFrom<0 then Exit;
234   for i:= NFrom to NTo do
235   begin
236     Result:= i;
237     if Data[i].NCharIndex + Data[i].NLength > APos.X+1 then // APos.X+1: see CudaText issue 2466
238       Break;
239   end;
240 end;
241 
242 procedure TATWrapInfo.SetCapacity(N: integer); inline;
243 begin
244   FList.Capacity:= Max(1024, N);
245 end;
246 
247 //optimized; don't just del/ins
248 procedure TATWrapInfo.ReplaceItems(AFrom, ATo: integer; AItems: TATWrapItems);
249 var
250   Item: TATWrapItem;
251   Dif, i: integer;
252 begin
253   if FVirtualMode then exit;
254   Dif:= AItems.Count - (ATo-AFrom+1);
255 
256   //adjust count of items
257   if Dif<0 then
258   begin
259     for i:= 1 to Abs(Dif) do
260       Delete(AFrom);
261   end
262   else
263   if Dif>0 then
264   begin
265     for i:= 1 to Dif do
266     begin
267       Item.Init(0, 0, 0, 0, Low(TATWrapItemFinal), true);
268       Insert(AFrom, Item);
269     end;
270   end;
271 
272   //overwrite N items
273   for i:= 0 to AItems.Count-1 do
274     FList[AFrom+i]:= AItems[i];
275 end;
276 
277 
278 end.
279 
280