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;