SynEdit Folding: Added Pop-up-Menu to Gutter

git-svn-id: trunk@19499 -
This commit is contained in:
martin 2009-04-19 00:39:59 +00:00
parent 80c266b7c7
commit d6d2d80d9f
4 changed files with 130 additions and 8 deletions

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);