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