mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-09-04 18:20:34 +02:00
SynEdit Folding: Added Pop-up-Menu to Gutter
git-svn-id: trunk@19499 -
This commit is contained in:
parent
80c266b7c7
commit
d6d2d80d9f
@ -2336,13 +2336,13 @@ begin
|
||||
end;
|
||||
if (X < fGutterWidth) then begin
|
||||
Include(fStateFlags, sfGutterClick);
|
||||
inherited MouseDown(Button, Shift, X, Y);
|
||||
IncPaintLock;
|
||||
try
|
||||
FGutter.MouseDown(Button, Shift, X, Y);
|
||||
finally
|
||||
DecPaintLock;
|
||||
end;
|
||||
inherited MouseDown(Button, Shift, X, Y);
|
||||
LCLIntf.SetFocus(Handle);
|
||||
exit;
|
||||
end;
|
||||
|
@ -170,6 +170,14 @@ const
|
||||
);
|
||||
|
||||
type
|
||||
TFoldViewNodeInfo = record
|
||||
HNode: TSynFoldNodeInfo;
|
||||
Text, Keyword: String;
|
||||
LineNum, ColIndex, OpenIndex: Integer;
|
||||
OpenCount: Integer;
|
||||
Folded: boolean;
|
||||
end;
|
||||
|
||||
{ TSynTextFoldedView
|
||||
*Line = Line (0-based) on Screen (except TopLine which should be TopViewPos)
|
||||
*ViewPos = Line (1-based) in the array of viewable/visible lines
|
||||
@ -282,7 +290,11 @@ type
|
||||
procedure UnfoldAll;
|
||||
procedure FoldAll(StartLevel : Integer = 0; IgnoreNested : Boolean = False);
|
||||
procedure FixFoldingAtTextIndex(AStartIndex: Integer; AMinEndLine: Integer = 0); // Real/All lines
|
||||
|
||||
public
|
||||
function OpenFoldCount(aStartIndex: Integer): Integer;
|
||||
function OpenFoldInfo(aStartIndex, ColIndex: Integer): TFoldViewNodeInfo;
|
||||
|
||||
public
|
||||
// Find the visible first line of the fold at ALine. Returns -1 if Aline is not folded
|
||||
function CollapsedLineForFoldAtLine(ALine : Integer) : Integer;
|
||||
function ExpandedLineForBlockAtLine(ALine : Integer; HalfExpanded: Boolean = True) : Integer;
|
||||
@ -2145,6 +2157,52 @@ begin
|
||||
FixFolding(AStartIndex + 1, AMinEndLine, fFoldTree);
|
||||
end;
|
||||
|
||||
function TSynEditFoldedView.OpenFoldCount(aStartIndex: Integer): Integer;
|
||||
var
|
||||
hl: TSynCustomFoldHighlighter;
|
||||
begin
|
||||
if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter))
|
||||
then exit(-1);
|
||||
hl := TSynCustomFoldHighlighter(FHighLighter);
|
||||
Result := hl.FoldNestCount(AStartIndex-1) + hl.FoldOpenCount(AStartIndex);
|
||||
end;
|
||||
|
||||
function TSynEditFoldedView.OpenFoldInfo(aStartIndex, ColIndex: Integer): TFoldViewNodeInfo;
|
||||
var
|
||||
hl: TSynCustomFoldHighlighter;
|
||||
n, o: Integer;
|
||||
nd: TSynFoldNodeInfo;
|
||||
begin
|
||||
if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter))
|
||||
then exit;
|
||||
hl := TSynCustomFoldHighlighter(FHighLighter);
|
||||
hl.CurrentLines := fLines;
|
||||
n := hl.FoldNestCount(AStartIndex-1);
|
||||
while (ColIndex < n) do begin
|
||||
dec(aStartIndex);
|
||||
n := hl.FoldNestCount(AStartIndex-1);
|
||||
end;
|
||||
ColIndex := ColIndex - n;
|
||||
o := hl.FoldOpenCount(AStartIndex);
|
||||
Result.OpenCount := o;
|
||||
n := hl.FoldNodeInfoCount[aStartIndex] - 1;
|
||||
while (o > ColIndex) and (n >= 0) do begin
|
||||
nd := hl.FoldNodeInfo[aStartIndex, n];
|
||||
if sfaInvalid in nd.FoldAction then break;
|
||||
if sfaClose in nd.FoldAction then inc(o);
|
||||
if sfaOpen in nd.FoldAction then dec(o);
|
||||
dec(n);
|
||||
end;
|
||||
inc(n);
|
||||
Result.HNode := nd;
|
||||
Result.Text := fLines[aStartIndex];
|
||||
Result.Keyword := copy(Result.Text, 1 + nd.LogXStart, nd.LogXEnd-nd.LogXStart);
|
||||
Result.LineNum := aStartIndex + 1;
|
||||
Result.ColIndex := ColIndex; // for FoldAction
|
||||
Result.OpenIndex := ColIndex; // for (2/3)
|
||||
Result.Folded := IsFoldedAtTextIndex(aStartIndex, ColIndex);
|
||||
end;
|
||||
|
||||
function TSynEditFoldedView.ExpandedLineForBlockAtLine(ALine : Integer;
|
||||
HalfExpanded: Boolean = True) : Integer;
|
||||
var
|
||||
|
@ -28,6 +28,7 @@ type
|
||||
FVisible: boolean;
|
||||
FAutoSize: boolean;
|
||||
FOnGutterClick: TGutterClickEvent;
|
||||
FMouseDownPart: Integer;
|
||||
procedure SetAutoSize(const Value: boolean);
|
||||
procedure SetLeftOffset(Value: integer);
|
||||
procedure SetRightOffset(Value: integer);
|
||||
@ -304,19 +305,20 @@ end;
|
||||
|
||||
procedure TSynGutter.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
||||
begin
|
||||
Parts[PixelToPartIndex(X)].MouseDown(Button, Shift, X, Y);
|
||||
FMouseDownPart := PixelToPartIndex(X);
|
||||
Parts[FMouseDownPart].MouseDown(Button, Shift, X, Y);
|
||||
if (Button=mbLeft) then
|
||||
DoOnGutterClick(X, Y);
|
||||
end;
|
||||
|
||||
procedure TSynGutter.MouseMove(Shift: TShiftState; X, Y: Integer);
|
||||
begin
|
||||
Parts[PixelToPartIndex(X)].MouseMove(Shift, X, Y);
|
||||
Parts[FMouseDownPart].MouseMove(Shift, X, Y);
|
||||
end;
|
||||
|
||||
procedure TSynGutter.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
||||
begin
|
||||
Parts[PixelToPartIndex(X)].MouseUp(Button, Shift, X, Y);
|
||||
Parts[FMouseDownPart].MouseUp(Button, Shift, X, Y);
|
||||
end;
|
||||
|
||||
function TSynGutter.LineNumberPart(Index: Integer = 0): TSynGutterLineNumber;
|
||||
|
@ -5,7 +5,7 @@ unit SynGutterCodeFolding;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, Controls, Graphics, LCLIntf, SynGutterBase, SynEditMiscProcs,
|
||||
sysutils, Classes, Controls, Graphics, Menus, LCLIntf, SynGutterBase, SynEditMiscProcs,
|
||||
SynEditFoldedView;
|
||||
|
||||
type
|
||||
@ -37,8 +37,11 @@ type
|
||||
FFoldView: TSynEditFoldedView;
|
||||
FExpandedClickConf,
|
||||
FCollapsedClickConf: TSynGutterFoldClickConfList;
|
||||
FPopUp: TPopupMenu;
|
||||
FMenuInf: Array of TFoldViewNodeInfo;
|
||||
protected
|
||||
procedure DoChange(Sender: TObject); override;
|
||||
procedure PopClicked(Sender: TObject);
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
@ -47,6 +50,7 @@ type
|
||||
override;
|
||||
function RealGutterWidth(CharWidth: integer): integer; override;
|
||||
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
||||
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
||||
procedure DoOnGutterClick(X, Y: integer); override;
|
||||
property ExpandedClickConf: TSynGutterFoldClickConfList read FExpandedClickConf;
|
||||
property CollapsedClickConf: TSynGutterFoldClickConfList read FCollapsedClickConf;
|
||||
@ -80,6 +84,7 @@ begin
|
||||
MarkupInfo.FrameColor := clNone;
|
||||
|
||||
FWidth := 10;
|
||||
FPopUp := TPopupMenu.Create(nil);
|
||||
|
||||
for i := low(TSynGutterFoldClickType) to high(TSynGutterFoldClickType) do begin
|
||||
FExpandedClickConf[i].Enabled := False;
|
||||
@ -124,6 +129,7 @@ end;
|
||||
|
||||
destructor TSynGutterCodeFolding.Destroy;
|
||||
begin
|
||||
FreeAndNil(FPopUp);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
@ -137,18 +143,25 @@ end;
|
||||
|
||||
procedure TSynGutterCodeFolding.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
|
||||
Y: Integer);
|
||||
var
|
||||
ClickDone: Boolean;
|
||||
m: TMenuItem;
|
||||
line, i, c: Integer;
|
||||
inf: TFoldViewNodeInfo;
|
||||
s, s2: String;
|
||||
function isClick(conf : TSynGutterFoldClickConf): Boolean;
|
||||
begin
|
||||
if ClickDone then exit(False);
|
||||
Result := ( conf.Enabled and (Button = conf.Button) and
|
||||
(Shift * conf.ShiftMask = conf.Shift) ) or
|
||||
( conf.Enabled2 and (Button = conf.Button2) and
|
||||
(Shift * conf.ShiftMask2 = conf.Shift2) );
|
||||
ClickDone := Result;
|
||||
end;
|
||||
var
|
||||
line : integer;
|
||||
begin
|
||||
line := TSynEdit(SynEdit).PixelsToRowColumn(Point(X, Y)).Y;
|
||||
if line > SynEdit.Lines.Count then exit;
|
||||
ClickDone := False;;
|
||||
|
||||
case FFoldView.FoldType[FFoldView.TextIndexToScreenLine(Line-1)] of
|
||||
cfCollapsed :
|
||||
@ -170,6 +183,55 @@ begin
|
||||
FFoldView.FoldAtTextIndex(Line-1, -1, 0);
|
||||
end;
|
||||
end;
|
||||
if (Button = mbRight) then begin
|
||||
if not ClickDone then begin
|
||||
FPopUp.Items.Clear;
|
||||
c := FFoldView.OpenFoldCount(line-1);
|
||||
SetLength(FMenuInf,c);
|
||||
for i := c-1 downto 0 do begin
|
||||
inf := FFoldView.OpenFoldInfo(line-1, i);
|
||||
FMenuInf[i] := inf;
|
||||
if (i < c-1) and (FMenuInf[i+1].LineNum = line) and (inf.LineNum <> line)
|
||||
then begin
|
||||
m := TMenuItem.Create(FPopUp);
|
||||
m.Caption := cLineCaption;
|
||||
m.Tag := -1;
|
||||
FPopUp.Items.Add(m);
|
||||
end;
|
||||
s := copy(inf.Text, 1, inf.HNode.LogXStart-1);
|
||||
if length(s) > 30 then s := copy(s,1,15) + '...' + copy(s, inf.HNode.LogXStart-11,10);
|
||||
s := s + copy(inf.Text, inf.HNode.LogXStart, 30 + (30 - length(s)));
|
||||
s2 := '';
|
||||
if inf.OpenCount > 1 then
|
||||
s2 := format(' (%d/%d)', [inf.OpenIndex+1, inf.OpenCount]);
|
||||
m := TMenuItem.Create(FPopUp);
|
||||
m.Caption := format('%4d %-12s %s', [ inf.LineNum, inf.Keyword+s2+':', s]);
|
||||
m.ShowAlwaysCheckable := true;
|
||||
m.Checked := inf.Folded;
|
||||
m.Tag := i;
|
||||
m.OnClick := {$IFDEF FPC}@{$ENDIF}PopClicked;
|
||||
FPopUp.Items.Add(m);
|
||||
end;
|
||||
FPopUp.PopUp;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynGutterCodeFolding.PopClicked(Sender: TObject);
|
||||
var
|
||||
inf: TFoldViewNodeInfo;
|
||||
begin
|
||||
inf := FMenuInf[(Sender as TMenuItem).tag];
|
||||
if inf.Folded then
|
||||
FFoldView.UnFoldAtTextIndex(inf.LineNum-1, inf.ColIndex, 1, False)
|
||||
else
|
||||
FFoldView.FoldAtTextIndex(inf.LineNum-1, inf.ColIndex, 1, False);
|
||||
end;
|
||||
|
||||
procedure TSynGutterCodeFolding.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
|
||||
Y: Integer);
|
||||
begin
|
||||
inherited MouseUp(Button, Shift, X, Y);
|
||||
end;
|
||||
|
||||
procedure TSynGutterCodeFolding.DoOnGutterClick(X, Y : integer);
|
||||
|
Loading…
Reference in New Issue
Block a user