mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-01 18:23:43 +02:00
661 lines
20 KiB
ObjectPascal
661 lines
20 KiB
ObjectPascal
unit SynGutterCodeFolding;
|
|
|
|
{$I synedit.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, Classes, Controls, Graphics, Menus, LCLIntf, SynGutterBase, SynEditMiscProcs,
|
|
SynEditFoldedView, SynEditMouseCmds, SynEditHighlighterFoldBase, LCLProc, ImgList;
|
|
|
|
type
|
|
|
|
{ TSynEditMouseActionsGutterFold }
|
|
|
|
TSynEditMouseActionsGutterFold = class(TSynEditMouseActions)
|
|
public
|
|
procedure ResetDefaults; override;
|
|
end;
|
|
|
|
// Line with [-] => ALL nodes expanded
|
|
|
|
{ TSynEditMouseActionsGutterFoldExpanded }
|
|
|
|
TSynEditMouseActionsGutterFoldExpanded = class(TSynEditMouseActions)
|
|
public
|
|
procedure ResetDefaults; override;
|
|
end;
|
|
|
|
// Line with [+] => at LEAST ONE node collapsed
|
|
|
|
{ TSynEditMouseActionsGutterFoldCollapsed }
|
|
|
|
TSynEditMouseActionsGutterFoldCollapsed = class(TSynEditMouseActions)
|
|
public
|
|
procedure ResetDefaults; override;
|
|
end;
|
|
|
|
{ TSynGutterCodeFolding }
|
|
|
|
TSynGutterCodeFolding = class(TSynGutterPartBase)
|
|
private
|
|
FFoldView: TSynEditFoldedView;
|
|
FMouseActionsCollapsed: TSynEditMouseActions;
|
|
FMouseActionsExpanded: TSynEditMouseActions;
|
|
FPopUp: TPopupMenu;
|
|
FMenuInf: Array of TFoldViewNodeInfo;
|
|
FIsFoldHidePreviousLine: Boolean;
|
|
FPopUpImageList: TImageList;
|
|
FReversePopMenuOrder: Boolean;
|
|
procedure SetMouseActionsCollapsed(const AValue: TSynEditMouseActions);
|
|
procedure SetMouseActionsExpanded(const AValue: TSynEditMouseActions);
|
|
function FoldTypeForLine(AScreenLine: Integer): TSynEditFoldLineCapability;
|
|
function IsFoldHidePreviousLine(AScreenLine: Integer): Boolean;
|
|
function IsSingleLineHide(AScreenLine: Integer): Boolean;
|
|
procedure InitPopUpImageList;
|
|
procedure DrawNodeSymbol(Canvas: TCanvas; Rect: TRect;
|
|
NodeType: TSynEditFoldLineCapability;
|
|
SubType: Integer);
|
|
protected
|
|
procedure DoChange(Sender: TObject); override;
|
|
procedure PopClicked(Sender: TObject);
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
procedure Paint(Canvas: TCanvas; AClip: TRect; FirstLine, LastLine: integer);
|
|
override;
|
|
function RealGutterWidth(CharWidth: integer): integer; override;
|
|
procedure DoOnGutterClick(X, Y: integer); override;
|
|
function MaybeHandleMouseAction(var AnInfo: TSynEditMouseActionInfo;
|
|
HandleActionProc: TSynEditMouseActionHandler): Boolean; override;
|
|
function DoHandleMouseAction(AnAction: TSynEditMouseAction;
|
|
var AnInfo: TSynEditMouseActionInfo): Boolean; override;
|
|
published
|
|
property MarkupInfo;
|
|
property MouseActionsExpanded: TSynEditMouseActions
|
|
read FMouseActionsExpanded write SetMouseActionsExpanded;
|
|
property MouseActionsCollapsed: TSynEditMouseActions
|
|
read FMouseActionsCollapsed write SetMouseActionsCollapsed;
|
|
property ReversePopMenuOrder: Boolean
|
|
read FReversePopMenuOrder write FReversePopMenuOrder default True;
|
|
end;
|
|
|
|
implementation
|
|
uses
|
|
SynEdit;
|
|
|
|
{ TSynGutterCodeFolding }
|
|
|
|
procedure TSynGutterCodeFolding.SetMouseActionsCollapsed(const AValue: TSynEditMouseActions);
|
|
begin
|
|
if AValue = nil then
|
|
FMouseActionsCollapsed.Clear
|
|
else
|
|
FMouseActionsCollapsed.Assign(AValue);
|
|
end;
|
|
|
|
procedure TSynGutterCodeFolding.SetMouseActionsExpanded(const AValue: TSynEditMouseActions);
|
|
begin
|
|
if AValue = nil then
|
|
FMouseActionsExpanded.Clear
|
|
else
|
|
FMouseActionsExpanded.Assign(AValue);
|
|
end;
|
|
|
|
function TSynGutterCodeFolding.FoldTypeForLine(AScreenLine: Integer): TSynEditFoldLineCapability;
|
|
var
|
|
tmp, tmp2: TSynEditFoldLineCapabilities;
|
|
begin
|
|
tmp := FFoldView.FoldType[AScreenLine];
|
|
tmp2 := FFoldView.FoldType[AScreenLine-1];
|
|
FIsFoldHidePreviousLine := False;
|
|
|
|
if (AScreenLine = 0) and (FFoldView.TextIndexToViewPos(FFoldView.TextIndex[0]) = 1) and
|
|
(cfCollapsedHide in tmp2)
|
|
then begin
|
|
Result := cfCollapsedHide;
|
|
FIsFoldHidePreviousLine := True;
|
|
end
|
|
//if tmp * [cfHideStart, cfFoldStart, cfCollapsedFold] = [cfHideStart, cfFoldStart, cfCollapsedFold]
|
|
// then Result := cfHideStart
|
|
else if cfCollapsedFold in tmp then Result := cfCollapsedFold
|
|
else if cfCollapsedHide in tmp then Result := cfCollapsedHide
|
|
else if cfFoldStart in tmp then Result := cfFoldStart
|
|
else if cfHideStart in tmp then Result := cfHideStart
|
|
else if cfFoldEnd in tmp then Result := cfFoldEnd
|
|
else if cfFoldBody in tmp then Result := cfFoldBody
|
|
else
|
|
Result := cfNone;
|
|
|
|
if Result in [cfFoldBody, cfFoldEnd] then begin
|
|
tmp := FFoldView.FoldType[AScreenLine - 1];
|
|
if tmp * [cfHideStart, cfFoldStart, cfCollapsedFold, cfCollapsedHide]
|
|
= [cfHideStart, cfFoldStart]
|
|
then begin
|
|
FIsFoldHidePreviousLine := True;
|
|
Result := cfHideStart // hide for previous line
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSynGutterCodeFolding.IsFoldHidePreviousLine(AScreenLine: Integer): Boolean;
|
|
begin
|
|
FoldTypeForLine(AScreenLine);
|
|
Result := FIsFoldHidePreviousLine;
|
|
end;
|
|
|
|
function TSynGutterCodeFolding.IsSingleLineHide(AScreenLine: Integer): Boolean;
|
|
var
|
|
tmp: TSynEditFoldLineCapabilities;
|
|
begin
|
|
Result := False;
|
|
tmp := FFoldView.FoldType[AScreenLine];
|
|
if tmp * [cfHideStart, cfFoldStart, cfCollapsedFold] =
|
|
[cfHideStart, cfFoldStart, cfCollapsedFold]
|
|
then
|
|
Result := True;
|
|
if cfSingleLineHide in tmp then
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TSynGutterCodeFolding.InitPopUpImageList;
|
|
var
|
|
img: TBitmap;
|
|
procedure NewImg;
|
|
begin
|
|
img := TBitmap.Create;
|
|
img.SetSize(16, 16);
|
|
img.Canvas.Brush.Color := clWhite;
|
|
img.Canvas.FillRect(0,0,16,16);
|
|
img.TransparentColor := clWhite;
|
|
img.Canvas.Pen.Color := clBlack;
|
|
img.Canvas.Pen.Width := 1;
|
|
end;
|
|
begin
|
|
FPopUpImageList.DrawingStyle := dsTransparent;
|
|
|
|
NewImg;
|
|
DrawNodeSymbol(img.Canvas, Rect(3,3,14,14), cfFoldStart, 0); // [-]
|
|
FPopUpImageList.Add(img, nil);
|
|
img.Free;
|
|
|
|
NewImg;
|
|
DrawNodeSymbol(img.Canvas, Rect(3,3,14,14), cfCollapsedFold, 0); // [+]
|
|
FPopUpImageList.Add(img, nil);
|
|
img.Free;
|
|
|
|
NewImg;
|
|
DrawNodeSymbol(img.Canvas, Rect(3,3,14,14), cfHideStart, 0); // [.]
|
|
FPopUpImageList.Add(img, nil);
|
|
img.Free;
|
|
|
|
NewImg;
|
|
DrawNodeSymbol(img.Canvas, Rect(3,3,14,14), cfCollapsedHide, 0); // [v]
|
|
FPopUpImageList.Add(img, nil);
|
|
img.Free;
|
|
|
|
end;
|
|
|
|
procedure TSynGutterCodeFolding.DoChange(Sender: TObject);
|
|
begin
|
|
if AutoSize then
|
|
FWidth := 10;
|
|
inherited DoChange(Sender);
|
|
end;
|
|
|
|
constructor TSynGutterCodeFolding.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FReversePopMenuOrder := true;
|
|
FFoldView := Gutter.FoldView;
|
|
FMouseActions := TSynEditMouseActionsGutterFold.Create(self);
|
|
FMouseActionsExpanded := TSynEditMouseActionsGutterFoldExpanded.Create(self);
|
|
FMouseActionsCollapsed := TSynEditMouseActionsGutterFoldCollapsed.Create(self);
|
|
FMouseActions.ResetDefaults;
|
|
FMouseActionsCollapsed.ResetDefaults;
|
|
FMouseActionsExpanded.ResetDefaults;
|
|
|
|
MarkupInfo.Background := clNone;
|
|
MarkupInfo.Foreground := clDkGray;
|
|
MarkupInfo.FrameColor := clNone;
|
|
|
|
FWidth := 10;
|
|
|
|
FPopUpImageList := TImageList.Create(nil);
|
|
InitPopUpImageList;
|
|
FPopUp := TPopupMenu.Create(nil);
|
|
FPopUp.Images := FPopUpImageList;
|
|
end;
|
|
|
|
destructor TSynGutterCodeFolding.Destroy;
|
|
begin
|
|
FreeAndNil(FMouseActions);
|
|
FreeAndNil(FMouseActionsCollapsed);
|
|
FreeAndNil(FMouseActionsExpanded);
|
|
FreeAndNil(FPopUp);
|
|
FreeAndNil(FPopUpImageList);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TSynGutterCodeFolding.RealGutterWidth(CharWidth : integer) : integer;
|
|
begin
|
|
If Visible then
|
|
Result := Width
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TSynGutterCodeFolding.PopClicked(Sender: TObject);
|
|
var
|
|
inf: TFoldViewNodeInfo;
|
|
begin
|
|
inf := FMenuInf[(Sender as TMenuItem).tag];
|
|
if inf.LineNum < 0 then exit;
|
|
case (Sender as TMenuItem).ImageIndex of
|
|
0: FFoldView.FoldAtTextIndex(inf.LineNum-1, inf.ColIndex, 1, False);
|
|
1: FFoldView.UnFoldAtTextIndex(inf.LineNum-1, inf.ColIndex, 1, False);
|
|
2: FFoldView.FoldAtTextIndex(inf.LineNum-1, inf.ColIndex, 1, False, 0);
|
|
3: FFoldView.UnFoldAtTextIndex(inf.LineNum-1, inf.ColIndex, 1, False, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TSynGutterCodeFolding.DoOnGutterClick(X, Y : integer);
|
|
begin
|
|
// Do Nothing
|
|
end;
|
|
|
|
function TSynGutterCodeFolding.MaybeHandleMouseAction(var AnInfo: TSynEditMouseActionInfo;
|
|
HandleActionProc: TSynEditMouseActionHandler): Boolean;
|
|
var
|
|
tmp: TSynEditFoldLineCapability;
|
|
begin
|
|
Result := False;
|
|
tmp := FoldTypeForLine(FFoldView.TextIndexToScreenLine(AnInfo.NewCaret.LinePos-1));
|
|
case tmp of
|
|
cfCollapsedFold, cfCollapsedHide:
|
|
Result := HandleActionProc(MouseActionsCollapsed, AnInfo);
|
|
cfFoldStart, cfHideStart:
|
|
Result := HandleActionProc(MouseActionsExpanded, AnInfo);
|
|
end;
|
|
|
|
if not Result then
|
|
Result := HandleActionProc(MouseActions, AnInfo);
|
|
end;
|
|
|
|
function TSynGutterCodeFolding.DoHandleMouseAction(AnAction: TSynEditMouseAction;
|
|
var AnInfo: TSynEditMouseActionInfo): Boolean;
|
|
|
|
function AddPopUpItem: TMenuItem;
|
|
begin
|
|
Result := TMenuItem.Create(FPopUp);
|
|
Result.OnClick := {$IFDEF FPC}@{$ENDIF}PopClicked;
|
|
if FReversePopMenuOrder then
|
|
FPopUp.Items.Add(Result)
|
|
else
|
|
FPopUp.Items.Insert(0, Result);
|
|
end;
|
|
var
|
|
c, i, line, ScrLine: Integer;
|
|
inf: TFoldViewNodeInfo;
|
|
m: TMenuItem;
|
|
s, s2: String;
|
|
ACommand: Word;
|
|
KeepVisible: Integer;
|
|
begin
|
|
Result := False;
|
|
if AnAction = nil then exit;
|
|
ACommand := AnAction.Command;
|
|
if (ACommand = emcNone) then exit;
|
|
line := AnInfo.NewCaret.LinePos;
|
|
ScrLine := FFoldView.TextIndexToScreenLine(Line-1);
|
|
KeepVisible := 1;
|
|
if FoldTypeForLine(ScrLine) = cfHideStart then KeepVisible := 0;
|
|
|
|
if (FoldTypeForLine(ScrLine) = cfCollapsedHide) then begin
|
|
if IsFoldHidePreviousLine(ScrLine) then
|
|
line := FFoldView.TextIndex[ScrLine-1] + 1;
|
|
inc(line);
|
|
KeepVisible := 0;
|
|
end
|
|
else
|
|
if IsFoldHidePreviousLine(ScrLine) then dec(line);
|
|
|
|
Result := True;
|
|
case ACommand of
|
|
emcCodeFoldCollaps:
|
|
begin
|
|
case AnAction.Option of
|
|
emcoCodeFoldCollapsOne:
|
|
begin
|
|
FFoldView.FoldAtTextIndex(Line-1, -1, 1, True, KeepVisible);
|
|
end;
|
|
emcoCodeFoldCollapsAll:
|
|
begin
|
|
FFoldView.FoldAtTextIndex(Line-1, -1, 0, False, KeepVisible);
|
|
end;
|
|
emcoCodeFoldCollapsAtCaret:
|
|
// Keyword at mouseclick/caret position
|
|
begin
|
|
i := FFoldView.LogicalPosToNodeIndex(Line-1, AnInfo.NewCaret.BytePos, False);
|
|
if i >= 0 then
|
|
FFoldView.FoldAtTextIndex(Line-1, i, 1, False, KeepVisible)
|
|
else
|
|
Result := False;
|
|
end;
|
|
emcoCodeFoldCollapsPreCaret:
|
|
// mouseclick/caret position anywhere inside the fold
|
|
begin
|
|
i := FFoldView.LogicalPosToNodeIndex(Line-1, AnInfo.NewCaret.BytePos, True);
|
|
if i >= 0 then
|
|
FFoldView.FoldAtTextIndex(Line-1, i, 1, False, KeepVisible)
|
|
else begin
|
|
i := FFoldView.ExpandedLineForBlockAtLine(Line);
|
|
if i > 0 then
|
|
FFoldView.FoldAtTextIndex(i-1, -1, 1, True, KeepVisible);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
emcCodeFoldExpand:
|
|
begin
|
|
case AnAction.Option of
|
|
emcoCodeFoldExpandOne:
|
|
FFoldView.UnFoldAtTextIndex(line-1, 0, 1, True, KeepVisible);
|
|
emcoCodeFoldExpandAll:
|
|
FFoldView.UnFoldAtTextIndex(line-1, -1, 0, False, KeepVisible);
|
|
end;
|
|
end;
|
|
emcCodeFoldContextMenu:
|
|
begin
|
|
FPopUp.Items.Clear;
|
|
c := FFoldView.OpenFoldCount(line-1);
|
|
if c > 0 then begin
|
|
SetLength(FMenuInf,c);
|
|
for i := c-1 downto 0 do begin
|
|
inf := FFoldView.OpenFoldInfo(line-1, i);
|
|
if sfaInvalid in inf.HNode.FoldAction then
|
|
continue;
|
|
FMenuInf[i] := inf;
|
|
if (i < c-1) and (FMenuInf[i+1].LineNum = line) and (inf.LineNum <> line)
|
|
then begin
|
|
m := AddPopUpItem;
|
|
m.Caption := cLineCaption;
|
|
m.Tag := -1;
|
|
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.ColIndex+1, inf.OpenCount]);
|
|
|
|
if inf.FNode.IsInFold then begin
|
|
m := AddPopUpItem;
|
|
m.Caption := format('%4d %-12s '#9'%s', [ inf.LineNum, inf.Keyword+s2+':', s]);
|
|
m.Tag := i;
|
|
if inf.FNode.IsHide then
|
|
m.ImageIndex := 3
|
|
else
|
|
m.ImageIndex := 1;
|
|
end
|
|
else begin
|
|
if sfaFoldFold in inf.HNode.FoldAction then begin
|
|
m := AddPopUpItem;
|
|
m.Caption := format('%4d %-12s '#9'%s', [ inf.LineNum, inf.Keyword+s2+':', s]);
|
|
m.Tag := i;
|
|
m.ImageIndex := 0;
|
|
end;
|
|
if sfaFoldHide in inf.HNode.FoldAction then begin
|
|
m := AddPopUpItem;
|
|
if sfaFoldFold in inf.HNode.FoldAction then
|
|
m.Caption := format('%4d %-12s ', [ inf.LineNum, inf.Keyword+s2 ])
|
|
else
|
|
m.Caption := format('%4d %-12s '#9'%s', [ inf.LineNum, inf.Keyword+s2+':', s]);
|
|
m.Tag := i;
|
|
m.ImageIndex := 2;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
FPopUp.PopUp;
|
|
end;
|
|
end;
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynGutterCodeFolding.DrawNodeSymbol(Canvas: TCanvas; Rect: TRect;
|
|
NodeType: TSynEditFoldLineCapability; SubType: Integer);
|
|
var
|
|
Points: Array [0..3] of TPoint;
|
|
X, Y: Integer;
|
|
begin
|
|
Canvas.Rectangle(Rect);
|
|
X := (Rect.Left - 1 + Rect.Right) div 2;
|
|
Y := (Rect.Top - 1 + Rect.Bottom) div 2;
|
|
|
|
case NodeType of
|
|
cfFoldStart:
|
|
begin
|
|
// [-]
|
|
Canvas.MoveTo(X - 2, Y);
|
|
Canvas.LineTo(X + 3, Y);
|
|
end;
|
|
cfHideStart:
|
|
begin
|
|
// [.]
|
|
Canvas.MoveTo(X, Y);
|
|
Canvas.LineTo(X + 1, Y);
|
|
end;
|
|
cfCollapsedFold:
|
|
begin
|
|
// [+]
|
|
Canvas.MoveTo(X - 2, Y);
|
|
Canvas.LineTo(X + 3, Y);
|
|
Canvas.MoveTo(X, Y - 2);
|
|
Canvas.LineTo(X, Y + 3);
|
|
end;
|
|
cfCollapsedHide:
|
|
begin
|
|
case SubType of
|
|
0: begin
|
|
// [v]
|
|
Points[0].X := X;
|
|
Points[0].y := Y + 2;
|
|
Points[1].X := X - 2;
|
|
Points[1].y := Y;
|
|
Points[2].X := X + 2;
|
|
Points[2].y := Y;
|
|
Points[3].X := X;
|
|
Points[3].y := Y + 2;
|
|
end;
|
|
1: begin
|
|
// [v]
|
|
Points[0].X := X;
|
|
Points[0].y := Y - 2;
|
|
Points[1].X := X - 2;
|
|
Points[1].y := Y;
|
|
Points[2].X := X + 2;
|
|
Points[2].y := Y;
|
|
Points[3].X := X;
|
|
Points[3].y := Y - 2;
|
|
end;
|
|
end;
|
|
Canvas.Polygon(Points);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynGutterCodeFolding.Paint(Canvas : TCanvas; AClip : TRect; FirstLine, LastLine : integer);
|
|
const cNodeOffset = 1;
|
|
var
|
|
iLine: integer;
|
|
rcLine: TRect;
|
|
rcCodeFold: TRect;
|
|
tmp: TSynEditFoldLineCapability;
|
|
LineHeight, LineOffset, BoxSize: Integer;
|
|
|
|
procedure DrawNodeBox(rcCodeFold: TRect; NodeType: TSynEditFoldLineCapability);
|
|
var
|
|
rcNode: TRect;
|
|
ptCenter : TPoint;
|
|
isPrevLine: Boolean;
|
|
i: Integer;
|
|
begin
|
|
isPrevLine := IsFoldHidePreviousLine(iLine);
|
|
LineOffset := 0;
|
|
|
|
//center of the draw area
|
|
ptCenter.X := (rcCodeFold.Left + rcCodeFold.Right) div 2;
|
|
ptCenter.Y := (rcCodeFold.Top + rcCodeFold.Bottom) div 2;
|
|
|
|
// If belongs to line above, draw at very top
|
|
if isPrevLine then
|
|
ptCenter.Y := rcCodeFold.Top + (BoxSize div 2) - 1;
|
|
|
|
//area of drawbox
|
|
rcNode.Left := ptCenter.X - (BoxSize div 2) + 1;
|
|
rcNode.Right := ptCenter.X + (BoxSize div 2);
|
|
rcNode.Top := ptCenter.Y - (BoxSize div 2) + 1;
|
|
rcNode.Bottom := ptCenter.Y + (BoxSize div 2);
|
|
|
|
Canvas.Brush.Style := bsClear;
|
|
|
|
//draw Paragraph end
|
|
if isPrevLine and (cfFoldEnd in FFoldView.FoldType[iLine]) and
|
|
(rcCodeFold.Bottom-1 > rcNode.Bottom)
|
|
then begin
|
|
Canvas.MoveTo(ptCenter.X, rcNode.Bottom);
|
|
Canvas.LineTo(ptCenter.X, rcCodeFold.Bottom-1);
|
|
Canvas.LineTo(rcCodeFold.Right, rcCodeFold.Bottom-1);
|
|
LineOffset := min(2, (rcCodeFold.Top + rcCodeFold.Bottom) div 2);
|
|
end
|
|
else
|
|
//draw bottom handle to paragraph line
|
|
if (cfFoldBody in FFoldView.FoldType[iLine + 1]) and
|
|
(not IsSingleLineHide(iLine))
|
|
then begin
|
|
Canvas.MoveTo(ptCenter.X, rcNode.Bottom);
|
|
Canvas.LineTo(ptCenter.X, rcCodeFold.Bottom);
|
|
end;
|
|
|
|
if (NodeType in [cfCollapsedFold, cfCollapsedHide]) and
|
|
(MarkupInfo.FrameColor <> clNone)
|
|
then
|
|
Canvas.Pen.Color := MarkupInfo.FrameColor;
|
|
|
|
i:= 0;
|
|
if isPrevLine and (NodeType = cfCollapsedHide) then i := 1;
|
|
DrawNodeSymbol(Canvas, rcNode, NodeType, i);
|
|
|
|
Canvas.Pen.Color := MarkupInfo.Foreground;
|
|
Canvas.Brush.Style := bsSolid;
|
|
end;
|
|
|
|
procedure DrawParagraphContinue(rcCodeFold: TRect);
|
|
var
|
|
iCenter : integer;
|
|
begin
|
|
//center of the draw area
|
|
iCenter := (rcCodeFold.Left + rcCodeFold.Right) div 2;
|
|
|
|
Canvas.MoveTo(iCenter, rcCodeFold.Top + LineOffset);
|
|
Canvas.LineTo(iCenter, rcCodeFold.Bottom);
|
|
LineOffset := 0;
|
|
end;
|
|
|
|
procedure DrawParagraphEnd(rcCodeFold: TRect);
|
|
var
|
|
X : Integer;
|
|
begin
|
|
//center of the draw area
|
|
X := (rcCodeFold.Left + rcCodeFold.Right) div 2;
|
|
|
|
Canvas.MoveTo(X, rcCodeFold.Top + LineOffset);
|
|
Canvas.LineTo(X, rcCodeFold.Bottom - 1);
|
|
Canvas.LineTo(rcCodeFold.Right, rcCodeFold.Bottom - 1);
|
|
LineOffset := min(2, (rcCodeFold.Top + rcCodeFold.Bottom) div 2);
|
|
end;
|
|
|
|
begin
|
|
if not Visible then exit;
|
|
LineHeight := TSynEdit(SynEdit).LineHeight;
|
|
LineOffset := 0;
|
|
if (FirstLine > 0) and
|
|
(FFoldView.FoldType[FirstLine-1] - [cfFoldBody] = [cfFoldEnd]) then
|
|
LineOffset := 2;
|
|
BoxSize := Min(Width, LineHeight - cNodeOffset*2);
|
|
|
|
if MarkupInfo.Background <> clNone then
|
|
begin
|
|
Canvas.Brush.Color := MarkupInfo.Background;
|
|
LCLIntf.SetBkColor(Canvas.Handle, Canvas.Brush.Color);
|
|
Canvas.FillRect(AClip);
|
|
end;
|
|
|
|
with Canvas do
|
|
begin
|
|
Pen.Color := MarkupInfo.Foreground;
|
|
Pen.Width := 1;
|
|
|
|
rcLine.Bottom := FirstLine * LineHeight;
|
|
for iLine := FirstLine to LastLine do
|
|
begin
|
|
// next line rect
|
|
rcLine.Top := rcLine.Bottom;
|
|
Inc(rcLine.Bottom, LineHeight);
|
|
|
|
rcCodeFold.Left := AClip.Left;
|
|
rcCodeFold.Right := AClip.Left + self.Width;
|
|
rcCodeFold.Top := rcLine.Top;
|
|
rcCodeFold.Bottom := rcLine.Bottom;
|
|
|
|
tmp := FoldTypeForLine(iLine);
|
|
case tmp of
|
|
cfFoldStart, cfHideStart, cfCollapsedFold, cfCollapsedHide:
|
|
DrawNodeBox(rcCodeFold, tmp);
|
|
cfFoldBody:
|
|
DrawParagraphContinue(rcCodeFold);
|
|
cfFoldEnd:
|
|
DrawParagraphEnd(rcCodeFold);
|
|
else
|
|
LineOffset := 0;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
{ TSynEditMouseActionsGutterFold }
|
|
|
|
procedure TSynEditMouseActionsGutterFold.ResetDefaults;
|
|
begin
|
|
Clear;
|
|
AddCommand(emcCodeFoldContextMenu, False, mbRight, ccSingle, cdUp, [], []);
|
|
AddCommand(emcCodeFoldCollaps, False, mbMiddle, ccAny, cdDown, [], [ssShift], emcoCodeFoldCollapsOne);
|
|
AddCommand(emcCodeFoldCollaps, False, mbMiddle, ccAny, cdDown, [ssShift], [ssShift], emcoCodeFoldCollapsAll);
|
|
AddCommand(emcNone, False, mbLeft, ccAny, cdDown, [], []);
|
|
end;
|
|
|
|
{ TSynEditMouseActionsGutterFoldExpanded }
|
|
|
|
procedure TSynEditMouseActionsGutterFoldExpanded.ResetDefaults;
|
|
begin
|
|
Clear;
|
|
AddCommand(emcCodeFoldCollaps, False, mbLeft, ccAny, cdDown, [], [], emcoCodeFoldCollapsOne);
|
|
end;
|
|
|
|
{ TSynEditMouseActionsGutterFoldCollapsed }
|
|
|
|
procedure TSynEditMouseActionsGutterFoldCollapsed.ResetDefaults;
|
|
begin
|
|
Clear;
|
|
AddCommand(emcCodeFoldExpand, False, mbLeft, ccAny, cdDown, [ssCtrl], [ssCtrl], emcoCodeFoldExpandOne);
|
|
AddCommand(emcCodeFoldExpand, False, mbLeft, ccAny, cdDown, [], [ssCtrl], emcoCodeFoldExpandAll);
|
|
end;
|
|
|
|
end.
|
|
|