replace the gutter markspart with a simpler equivalent

more adapted to multiple and dynamic columns
This commit is contained in:
Basile Burg 2021-04-15 02:38:33 +02:00
parent b0da20f068
commit 2b1ef5b439
4 changed files with 193 additions and 6 deletions

View File

@ -7,6 +7,8 @@
## Bugs fixed ## Bugs fixed
- editor, gutter: cases where warnings icons were not always updated. (#80) - editor, gutter: cases where warnings icons were not always updated. (#80)
- editor, gutter: prevent overlap of icons. first column is used for D-Scanner, second and third for debugging.
## Other ## Other
- D2 highlighter: remove the keywords `body` (deprecated), `typedef` (deprecated), `macro` (unused). - D2 highlighter: remove the keywords `body` (deprecated), `typedef` (deprecated), `macro` (unused).

View File

@ -549,7 +549,7 @@
<PackageName Value="LCL"/> <PackageName Value="LCL"/>
</Item8> </Item8>
</RequiredPackages> </RequiredPackages>
<Units Count="61"> <Units Count="62">
<Unit0> <Unit0>
<Filename Value="dexed.lpr"/> <Filename Value="dexed.lpr"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
@ -870,6 +870,10 @@
<Filename Value="..\src\u_dexed_d.pas"/> <Filename Value="..\src\u_dexed_d.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit60> </Unit60>
<Unit61>
<Filename Value="..\src\u_synmultiguttermarks.pas"/>
<IsPartOfProject Value="True"/>
</Unit61>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -10,11 +10,12 @@ uses
SynHighlighterLFM, SynEditHighlighter, SynEditMouseCmds, SynEditFoldedView, SynHighlighterLFM, SynEditHighlighter, SynEditMouseCmds, SynEditFoldedView,
SynEditMarks, SynEditTypes, SynHighlighterJScript, SynBeautifier, dialogs, SynEditMarks, SynEditTypes, SynHighlighterJScript, SynBeautifier, dialogs,
md5, Spin, LCLIntf, LazFileUtils, LMessages, SynHighlighterCpp, math, md5, Spin, LCLIntf, LazFileUtils, LMessages, SynHighlighterCpp, math,
SynGutterMarks, SynGutterBase,
//SynEditMarkupFoldColoring, //SynEditMarkupFoldColoring,
Clipbrd, fpjson, jsonparser, LazUTF8, LazUTF8Classes, Buttons, StdCtrls, Clipbrd, fpjson, jsonparser, LazUTF8, LazUTF8Classes, Buttons, StdCtrls,
u_common, u_writableComponent, u_d2syn, u_txtsyn, u_dialogs, u_common, u_writableComponent, u_d2syn, u_txtsyn, u_dialogs,
u_sharedres, u_dlang, u_stringrange, u_dbgitf, u_observer, u_diff, u_sharedres, u_dlang, u_stringrange, u_dbgitf, u_observer, u_diff,
u_processes; u_processes, u_synmultiguttermarks;
type type
@ -253,6 +254,7 @@ type
fDscannerEnabled: boolean; fDscannerEnabled: boolean;
fScrollPreview: boolean; fScrollPreview: boolean;
fDiffDialogWillClose: boolean; fDiffDialogWillClose: boolean;
fMultiGutterMarks: TSynMultiGutterMarks;
procedure showHintEvent(Sender: TObject; HintInfo: PHintInfo); procedure showHintEvent(Sender: TObject; HintInfo: PHintInfo);
procedure setGutterTransparent(value: boolean); procedure setGutterTransparent(value: boolean);
procedure decCallTipsLvl; procedure decCallTipsLvl;
@ -1153,9 +1155,18 @@ begin
fModified := false; fModified := false;
TextBuffer.AddNotifyHandler(senrUndoRedoAdded, @changeNotify); TextBuffer.AddNotifyHandler(senrUndoRedoAdded, @changeNotify);
Gutter.MarksPart.AutoSize:=false; Gutter.MarksPart.Visible:=false;
Gutter.MarksPart.Width := ScaleX(20,96);
fMultiGutterMarks := TSynMultiGutterMarks.Create(Gutter.Parts);
fMultiGutterMarks.columnCount := 2;
fMultiGutterMarks.columnWidth := ScaleX(20,96);
fMultiGutterMarks.AutoSize := true;
fMultiGutterMarks.Index := 1;
fImages := TImageList.Create(self); fImages := TImageList.Create(self);
fMultiGutterMarks.images := fImages;
z := GetIconScaledSize; z := GetIconScaledSize;
case z of case z of
iss16: iss16:
@ -3901,7 +3912,7 @@ var
p: TPoint; p: TPoint;
begin begin
p := ScreenToClient(mouse.CursorPos); p := ScreenToClient(mouse.CursorPos);
if p.x > Gutter.MarksPart.Width then if p.x > fMultiGutterMarks.Width then
exit; exit;
p := self.PixelsToRowColumn(p); p := self.PixelsToRowColumn(p);
showWarningForLine(p.y); showWarningForLine(p.y);
@ -3935,6 +3946,19 @@ begin
exit(true); exit(true);
end; end;
function gutterIconKindToColumn(value: TGutterIcon): integer;
begin
case value of
giBreakSet : result := 1;
giBulletGreen : result := 2;
giBulletBlack : result := 2;
giBreakReached : result := 2;
giStep : result := 2;
giWatch : result := 2;
giWarn : result := 0;
end;
end;
function TDexedMemo.findBreakPoint(line: integer): boolean; function TDexedMemo.findBreakPoint(line: integer): boolean;
begin begin
result := isGutterIconSet(line, giBreakSet); result := isGutterIconSet(line, giBreakSet);
@ -3963,7 +3987,8 @@ begin
begin begin
n := m.Items[i]; n := m.Items[i];
s := n.ImageIndex = longint(value); s := n.ImageIndex = longint(value);
n.Visible := s; if s then
n.Visible := true;
end; end;
if not s then if not s then
begin begin
@ -3972,6 +3997,7 @@ begin
n.ImageList := fImages; n.ImageList := fImages;
n.ImageIndex := longint(value); n.ImageIndex := longint(value);
n.Visible := true; n.Visible := true;
n.Column:= gutterIconKindToColumn(value);
Marks.Add(n); Marks.Add(n);
end; end;
end; end;
@ -4001,6 +4027,7 @@ var
i: integer; i: integer;
m: TSynEditMark; m: TSynEditMark;
begin begin
fMultiGutterMarks.columnCount := 3;
fDebugger := debugger; fDebugger := debugger;
fDebugger.removeBreakPoints(fileName); fDebugger.removeBreakPoints(fileName);
for i := 0 to marks.count - 1 do for i := 0 to marks.count - 1 do
@ -4013,6 +4040,7 @@ end;
procedure TDexedMemo.debugStop; procedure TDexedMemo.debugStop;
begin begin
fMultiGutterMarks.columnCount := 2;
removeDebugTimeMarks; removeDebugTimeMarks;
end; end;
@ -4042,6 +4070,8 @@ begin
if fname <> fFilename then if fname <> fFilename then
exit; exit;
showPage; showPage;
// newly opened source has not 3 cols yet
fMultiGutterMarks.columnCount := 3;
caretY := line; caretY := line;
EnsureCursorPosVisible; EnsureCursorPosVisible;
removeDebugTimeMarks; removeDebugTimeMarks;

View File

@ -0,0 +1,151 @@
unit u_synmultiguttermarks;
{$I u_defines.inc}
interface
uses
Classes, SysUtils, Graphics, LCLType, LCLIntf, LCLProc, Controls, ImgList,
math, SynGutterBase, SynEditMiscClasses, SynEditMarks;
type
TSynMultiGutterMarks = class(TSynGutterPartBase)
private
fColumnCount: Integer;
fColumnWidth: Integer;
fImages: TCustomImageList;
procedure setColumnCount(value: integer);
procedure setColumnWidth(value: integer);
procedure setImages(value: TCustomImageList);
protected
procedure Init; override;
function PreferedWidth: Integer; override;
// PaintMarks: True, if it has any Mark, that is *not* a bookmark
function PaintMarks(aScreenLine: Integer; Canvas : TCanvas; AClip : TRect;
var aFirstCustomColumnIdx: integer): Boolean;
Procedure PaintLine(aScreenLine: Integer; Canvas : TCanvas; AClip : TRect); virtual;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Paint(Canvas: TCanvas; AClip: TRect; FirstLine, LastLine: integer); override;
property columnWidth: integer read fColumnWidth write SetColumnWidth;
property columnCount: integer read fColumnCount write setColumnCount;
property images: TCustomImageList read fImages write setImages;
end;
implementation
uses
SynEdit;
constructor TSynMultiGutterMarks.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
end;
destructor TSynMultiGutterMarks.Destroy;
begin
inherited Destroy;
end;
procedure TSynMultiGutterMarks.Init;
begin
inherited Init;
end;
function TSynMultiGutterMarks.PreferedWidth: Integer;
begin
Result := ScaleX(20, 96) * fColumnCount;
end;
procedure TSynMultiGutterMarks.setColumnCount(value: integer);
begin
if value = fColumnCount then
exit;
fColumnCount := value;
TCustomSynEdit(SynEdit).Gutter.DoAutoSize();
end;
procedure TSynMultiGutterMarks.setColumnWidth(value: integer);
begin
fColumnWidth := value;
end;
procedure TSynMultiGutterMarks.setImages(value: TCustomImageList);
begin
fImages := value;
end;
function TSynMultiGutterMarks.PaintMarks(aScreenLine: Integer; Canvas : TCanvas;
AClip : TRect; var aFirstCustomColumnIdx: integer): Boolean;
var
markLine: TSynEditMarkLine;
markRect: TRect;
mark : TSynEditMark;
i, h, w : integer;
begin
Result := False;
aFirstCustomColumnIdx := 0;
i := FoldView.TextIndex[aScreenLine];
if (i < 0) or (i >= TCustomSynEdit(SynEdit).Lines.Count) then
exit;
markLine := TCustomSynEdit(SynEdit).Marks.Line[i + 1];
if markLine = nil then
exit;
h := TCustomSynEdit(SynEdit).LineHeight;
w := ScaleX(20, 96);
for i := 0 to markLine.Count - 1 do
begin
mark := markLine[i];
if (not mark.visible) or (mark.ImageIndex = -1) or (mark.ImageList = nil) then
continue;
markRect := Rect(AClip.Left + 2 + mark.Column * w, AClip.Top, AClip.Left + 500, AClip.Top + h);
mark.ImageList.draw(canvas, markRect.Left, markRect.Top, mark.ImageIndex);
Result := true;
end;
end;
procedure TSynMultiGutterMarks.PaintLine(aScreenLine: Integer; Canvas: TCanvas; AClip: TRect);
var
aGutterOffs: Integer;
begin
aGutterOffs := 0;
PaintMarks(aScreenLine, Canvas, AClip, aGutterOffs);
end;
procedure TSynMultiGutterMarks.Paint(Canvas : TCanvas; AClip : TRect; FirstLine, LastLine : integer);
var
i: integer;
LineHeight: Integer;
rcLine: TRect;
begin
if not Visible then exit;
if MarkupInfo.Background <> clNone then
Canvas.Brush.Color := MarkupInfo.Background
else
Canvas.Brush.Color := Gutter.Color;
LCLIntf.SetBkColor(Canvas.Handle, TColorRef(Canvas.Brush.Color));
rcLine := AClip;
rcLine.Bottom := rcLine.Top;
if (LastLine >= FirstLine) then
begin
LineHeight := TCustomSynEdit(SynEdit).LineHeight;
for i := FirstLine to LastLine do begin
rcLine.Top := rcLine.Bottom;
rcLine.Bottom := Min(AClip.Bottom, rcLine.Top + LineHeight);
PaintLine(i, Canvas, rcLine);
end;
end;
end;
end.
end.