406 lines
8.8 KiB
PHP
406 lines
8.8 KiB
PHP
{$ifdef nn}begin end;{$endif}
|
|
|
|
function TATSynEdit.IsLineFolded(ALine: integer; ADetectPartialFold: boolean): boolean;
|
|
var
|
|
Flag: integer;
|
|
begin
|
|
if not Strings.IsIndexValid(ALine) then
|
|
begin
|
|
Result:= false;
|
|
Exit;
|
|
end;
|
|
|
|
Flag:= Strings.LinesHidden[ALine, FEditorIndex];
|
|
Result:= (Flag=-1) or (ADetectPartialFold and (Flag>0));
|
|
end;
|
|
|
|
function TATSynEdit.IsLineFoldedFull(ALine: integer): boolean;
|
|
begin
|
|
Result:= IsLineFolded(ALine, false);
|
|
end;
|
|
|
|
function TATSynEdit.GetFirstUnfoldedLineNumber: integer;
|
|
begin
|
|
Result:= GetNextUnfoldedLineNumber(0, true);
|
|
end;
|
|
|
|
function TATSynEdit.GetLastUnfoldedLineNumber: integer;
|
|
begin
|
|
Result:= GetNextUnfoldedLineNumber(Strings.Count-1, false);
|
|
end;
|
|
|
|
function TATSynEdit.GetNextUnfoldedLineNumber(ALine: integer; ADown: boolean): integer;
|
|
var
|
|
N: integer;
|
|
begin
|
|
Result:= ALine;
|
|
N:= Result;
|
|
while IsLineFolded(N) and Strings.IsIndexValid(N) do
|
|
N:= N+BoolToPlusMinusOne(ADown);
|
|
if Strings.IsIndexValid(N) then Result:= N;
|
|
end;
|
|
|
|
function TATSynEdit.IsPosFolded(AX, AY: integer): boolean;
|
|
begin
|
|
Result:= Strings.IsPosFolded(AX, AY, FEditorIndex);
|
|
end;
|
|
|
|
(*
|
|
example of CPP file which is hard to unfold (if nested ranges folded).
|
|
{
|
|
d1
|
|
{
|
|
d2a
|
|
}
|
|
{
|
|
d2b
|
|
{
|
|
d3a
|
|
}
|
|
{
|
|
d3b
|
|
{
|
|
d4a
|
|
}
|
|
{
|
|
d4b
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
what we do. for each line in range:
|
|
a) if line not in any subrange, show it
|
|
b) for all subranges at top level:
|
|
b1) if subrange marked folded, unfold 1st line "[...]"
|
|
b2) if subrange marked unfolded, recursion
|
|
*)
|
|
procedure TATSynEdit.DoRangeUnfold(ARange: TATSynRange);
|
|
var
|
|
List: TATIntArray;
|
|
R: TATSynRange;
|
|
i, j: integer;
|
|
InSubrange: boolean;
|
|
begin
|
|
ARange.Folded:= false;
|
|
FWrapUpdateNeeded:= true;
|
|
|
|
List:= FFold.FindRangesContainingLines(-1, -1, ARange,
|
|
false{OnlyFolded}, true{TopLevel}, cRngIgnore);
|
|
|
|
//show all lines not in subranges
|
|
for i:= ARange.Y to ARange.Y2 do
|
|
begin
|
|
InSubrange:= false;
|
|
for j:= Low(List) to High(List) do
|
|
if FFold[List[j]].IsLineInside(i) then
|
|
begin
|
|
InSubrange:= true;
|
|
Break
|
|
end;
|
|
|
|
if not InSubrange then
|
|
Strings.LinesHidden[i, FEditorIndex]:= 0;
|
|
end;
|
|
|
|
//unfold subranges, resursion
|
|
for i:= Low(List) to High(List) do
|
|
begin
|
|
R:= FFold[List[i]];
|
|
if R.Folded then
|
|
Strings.LinesHidden[R.Y, FEditorIndex]:= R.X
|
|
else
|
|
DoRangeUnfold(R);
|
|
end;
|
|
end;
|
|
|
|
procedure TATSynEdit.DoRangeFold(ARange: TATSynRange);
|
|
var
|
|
i: integer;
|
|
begin
|
|
ARange.Folded:= true;
|
|
FWrapUpdateNeeded:= true;
|
|
|
|
//partially fold 1st line
|
|
if ARange.Hint<>'' then
|
|
begin
|
|
Strings.LinesHidden[ARange.Y, FEditorIndex]:= ARange.X;
|
|
end
|
|
else
|
|
case FFoldStyle of
|
|
cFoldHereWithDots:
|
|
begin
|
|
Strings.LinesHidden[ARange.Y, FEditorIndex]:= ARange.X;
|
|
end;
|
|
cFoldHereWithTruncatedText:
|
|
begin
|
|
Strings.LinesHidden[ARange.Y, FEditorIndex]:= ARange.X;
|
|
ARange.Hint:= Copy(Strings.Lines[ARange.Y], ARange.X, cFoldedLenOfEmptyHint)+'...';
|
|
end;
|
|
cFoldFromEndOfLine:
|
|
begin
|
|
Strings.LinesHidden[ARange.Y, FEditorIndex]:= Length(Strings.Lines[ARange.Y])+1;
|
|
end;
|
|
cFoldFromNextLine:
|
|
begin
|
|
//don't fold line
|
|
end;
|
|
end;
|
|
|
|
//fully fold next lines
|
|
for i:= ARange.Y+1 to ARange.Y2 do
|
|
Strings.LinesHidden[i, FEditorIndex]:= -1;
|
|
end;
|
|
|
|
|
|
procedure TATSynEdit.DoUnfoldLine(ALine: integer);
|
|
var
|
|
List: TATIntArray;
|
|
i: integer;
|
|
begin
|
|
List:= FFold.FindRangesContainingLines(ALine, ALine, nil,
|
|
true{OnlyFolded}, false{TopLevelOnly}, cRngHasAllLines);
|
|
for i:= Low(List) to High(List) do
|
|
DoRangeUnfold(FFold[List[i]]);
|
|
end;
|
|
|
|
procedure TATSynEdit.DoFoldbarClick(ALine: integer);
|
|
var
|
|
R: TATSynRange;
|
|
begin
|
|
R:= FFold.FindRangeWithPlusAtLine(ALine);
|
|
if Assigned(R) then
|
|
begin
|
|
if R.Folded then
|
|
DoRangeUnfold(R)
|
|
else
|
|
DoRangeFold(R);
|
|
Update;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TATSynEdit.GetFoldedMarkText(ALine: integer): string;
|
|
var
|
|
R: TATSynRange;
|
|
begin
|
|
Result:= '';
|
|
R:= FFold.FindRangeWithPlusAtLine(ALine);
|
|
if Assigned(R) then
|
|
Result:= R.Hint;
|
|
if Result='' then
|
|
Result:= '...';
|
|
end;
|
|
|
|
procedure TATSynEdit.UpdateFoldedFromLinesHidden;
|
|
var
|
|
i, j: integer;
|
|
N: integer;
|
|
R: TATSynRange;
|
|
begin
|
|
for i:= 0 to Strings.Count-1 do
|
|
begin
|
|
N:= Strings.LinesHidden[i, FEditorIndex];
|
|
if N<=0 then Continue;
|
|
|
|
for j:= 0 to Fold.Count-1 do
|
|
begin
|
|
R:= Fold.Items[j];
|
|
if (R.Y>i) then Break;
|
|
if (R.Y=i) and (R.X=N) then
|
|
begin
|
|
DoRangeFold(R); //do not just R.Folded:= true;
|
|
Break
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TATSynEdit.IsFoldLineNeededBeforeWrapitem(N: integer): boolean;
|
|
var
|
|
NLineCur, NLinePrev: integer;
|
|
begin
|
|
if FWrapInfo.IsIndexValid(N) and (N>0) then
|
|
begin
|
|
NLineCur:= FWrapInfo.Items[N].NLineIndex;
|
|
NLinePrev:= FWrapInfo.Items[N-1].NLineIndex;
|
|
//before this line some is skipped
|
|
Result:= NLineCur-NLinePrev > 1;
|
|
//and prev visible line is fully visible
|
|
if Result then
|
|
Result:= Strings.LinesHidden[NLinePrev, FEditorIndex]=0;
|
|
end
|
|
else
|
|
Result:= false;
|
|
end;
|
|
|
|
procedure TATSynEdit.DoMenuGutterFold;
|
|
var
|
|
Menu: TPopupMenu;
|
|
mi, miSub: TMenuItem;
|
|
i: integer;
|
|
begin
|
|
InitResourcesFoldbar;
|
|
if FMenuGutterFoldStd=nil then
|
|
FMenuGutterFoldStd:= TPopupMenu.Create(Self);
|
|
|
|
Menu:= FMenuGutterFoldStd;
|
|
Menu.Images:= FFoldImageList;
|
|
Menu.Items.Clear;
|
|
|
|
//items "fold all", "unfold all"
|
|
mi:= TMenuItem.Create(Self);
|
|
mi.Caption:= cStrMenuItemFoldAll;
|
|
mi.OnClick:= @MenuFoldFoldAllClick;
|
|
mi.Enabled:= Fold.Count>0;
|
|
Menu.Items.Add(mi);
|
|
|
|
mi:= TMenuItem.Create(Self);
|
|
mi.Caption:= cStrMenuItemUnfoldAll;
|
|
mi.OnClick:= @MenuFoldUnfoldAllClick;
|
|
mi.Enabled:= Fold.Count>0;
|
|
Menu.Items.Add(mi);
|
|
|
|
//submenu "fold level"
|
|
miSub:= TMenuItem.Create(Self);
|
|
miSub.Caption:= cStrMenuItemFoldLevel;
|
|
miSub.Enabled:= Fold.Count>0;
|
|
Menu.Items.Add(miSub);
|
|
|
|
for i:= 2 to 9 do
|
|
begin
|
|
mi:= TMenuItem.Create(Self);
|
|
mi.Caption:= Inttostr(i);
|
|
mi.Tag:= i-1;
|
|
mi.OnClick:=@MenuFoldLevelClick;
|
|
miSub.Add(mi);
|
|
end;
|
|
|
|
//dynamic items [+], [-]
|
|
DoMenuGutterFold_AddDynamicItems(Menu);
|
|
|
|
Menu.Popup;
|
|
end;
|
|
|
|
|
|
procedure TATSynEdit.DoMenuGutterFold_AddDynamicItems(Menu: TPopupMenu);
|
|
var
|
|
Pnt: TPoint;
|
|
AtEnd: boolean;
|
|
NLine: integer;
|
|
IntList: TATIntArray;
|
|
Rng: TATSynRange;
|
|
mi: TMenuItem;
|
|
i: integer;
|
|
begin
|
|
//calc ranges for curr line
|
|
Pnt:= ScreenToClient(Mouse.CursorPos);
|
|
Pnt:= ClientPosToCaretPos(Pnt, AtEnd);
|
|
NLine:= Pnt.Y;
|
|
if NLine<0 then Exit;
|
|
|
|
IntList:= Fold.FindRangesContainingLines(NLine, NLine, nil,
|
|
false{OnlyFolded}, false{TopLevel}, cRngHasAllLines);
|
|
if Length(IntList)=0 then Exit;
|
|
|
|
//separator
|
|
mi:= TMenuItem.Create(Self);
|
|
mi.Caption:= '-';
|
|
Menu.Items.Add(mi);
|
|
|
|
//items for ranges for current line
|
|
for i:= 0 to High(IntList) do
|
|
begin
|
|
Rng:= Fold[IntList[i]];
|
|
mi:= TMenuItem.Create(Self);
|
|
mi.Tag:= ptrint(Rng);
|
|
mi.OnClick:= @MenuFoldPlusMinusClick;
|
|
|
|
mi.Caption:=
|
|
cHintScrollPrefix+' '+Inttostr(Rng.Y+1)+': '+
|
|
UTF8Encode(Copy(Strings.Lines[Rng.Y], 1, cFoldedLenOfEmptyHint));
|
|
|
|
if Rng.Folded then
|
|
mi.ImageIndex:= 0
|
|
else
|
|
mi.ImageIndex:= 1;
|
|
|
|
Menu.Items.Add(mi);
|
|
end;
|
|
end;
|
|
|
|
procedure TATSynEdit.InitResourcesFoldbar;
|
|
begin
|
|
if FFoldImageList=nil then
|
|
begin
|
|
FFoldImageList:= TImageList.Create(Self);
|
|
FFoldImageList.Width:= 12;
|
|
FFoldImageList.Height:= 12;
|
|
FFoldImageList.AddResourceName(HInstance, 'FOLDBAR_P');
|
|
FFoldImageList.AddResourceName(HInstance, 'FOLDBAR_M');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TATSynEdit.MenuFoldPlusMinusClick(Sender: TObject);
|
|
var
|
|
Rng: TATSynRange;
|
|
begin
|
|
Rng:= TATSynRange((Sender as TComponent).Tag);
|
|
if Rng.Folded then
|
|
DoRangeUnfold(Rng)
|
|
else
|
|
DoRangeFold(Rng);
|
|
Update;
|
|
end;
|
|
|
|
procedure TATSynEdit.MenuFoldFoldAllClick(Sender: TObject);
|
|
begin
|
|
DoCommand(cCommand_FoldAll);
|
|
end;
|
|
|
|
procedure TATSynEdit.MenuFoldLevelClick(Sender: TObject);
|
|
begin
|
|
DoFoldForLevel((Sender as TComponent).Tag);
|
|
end;
|
|
|
|
procedure TATSynEdit.MenuFoldUnfoldAllClick(Sender: TObject);
|
|
begin
|
|
DoCommand(cCommand_UnfoldAll);
|
|
end;
|
|
|
|
|
|
procedure TATSynEdit.DoFoldForLevelAndLines(ALineFrom, ALineTo: integer;
|
|
ALevel: integer; AForThisRange: TATSynRange);
|
|
var
|
|
List: TATIntArray;
|
|
R: TATSynRange;
|
|
i: integer;
|
|
begin
|
|
//this func recursive. it calls itself with ALevel-1.
|
|
//folds ranges if ALevel=0, else goes to subranges until found ALevel=0.
|
|
if ALevel<0 then exit;
|
|
|
|
List:= Fold.FindRangesContainingLines(ALineFrom, ALineTo, AForThisRange,
|
|
false{OnlyFolded}, true{TopLevel}, cRngExceptThisRange);
|
|
|
|
for i:= Low(List) to High(List) do
|
|
begin
|
|
R:= Fold.Items[List[i]];
|
|
if R.IsSimple then Continue;
|
|
if R.Folded then Continue;
|
|
if ALevel=0 then
|
|
DoRangeFold(R)
|
|
else
|
|
DoFoldForLevelAndLines(R.Y, R.Y2, ALevel-1, R);
|
|
end;
|
|
end;
|
|
|
|
procedure TATSynEdit.DoFoldForLevel(ALevel: integer);
|
|
begin
|
|
DoCommand(cCommand_UnfoldAll);
|
|
DoFoldForLevelAndLines(0, Strings.Count-1, ALevel, nil);
|
|
Update;
|
|
end;
|
|
|