From 2b1ef5b4399560b162d4b83c03ed4f38c1a97d8d Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Thu, 15 Apr 2021 02:38:33 +0200 Subject: [PATCH] replace the gutter markspart with a simpler equivalent more adapted to multiple and dynamic columns --- CHANGELOG.md | 2 + lazproj/dexed.lpi | 6 +- src/u_synmemo.pas | 40 +++++++-- src/u_synmultiguttermarks.pas | 151 ++++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 src/u_synmultiguttermarks.pas diff --git a/CHANGELOG.md b/CHANGELOG.md index 7373f1fc..7e4a40fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ ## Bugs fixed - 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 - D2 highlighter: remove the keywords `body` (deprecated), `typedef` (deprecated), `macro` (unused). diff --git a/lazproj/dexed.lpi b/lazproj/dexed.lpi index dc73ed7e..e6f23484 100644 --- a/lazproj/dexed.lpi +++ b/lazproj/dexed.lpi @@ -549,7 +549,7 @@ - + @@ -870,6 +870,10 @@ + + + + diff --git a/src/u_synmemo.pas b/src/u_synmemo.pas index 8b3956ca..1136bcf9 100644 --- a/src/u_synmemo.pas +++ b/src/u_synmemo.pas @@ -10,11 +10,12 @@ uses SynHighlighterLFM, SynEditHighlighter, SynEditMouseCmds, SynEditFoldedView, SynEditMarks, SynEditTypes, SynHighlighterJScript, SynBeautifier, dialogs, md5, Spin, LCLIntf, LazFileUtils, LMessages, SynHighlighterCpp, math, + SynGutterMarks, SynGutterBase, //SynEditMarkupFoldColoring, Clipbrd, fpjson, jsonparser, LazUTF8, LazUTF8Classes, Buttons, StdCtrls, u_common, u_writableComponent, u_d2syn, u_txtsyn, u_dialogs, u_sharedres, u_dlang, u_stringrange, u_dbgitf, u_observer, u_diff, - u_processes; + u_processes, u_synmultiguttermarks; type @@ -253,6 +254,7 @@ type fDscannerEnabled: boolean; fScrollPreview: boolean; fDiffDialogWillClose: boolean; + fMultiGutterMarks: TSynMultiGutterMarks; procedure showHintEvent(Sender: TObject; HintInfo: PHintInfo); procedure setGutterTransparent(value: boolean); procedure decCallTipsLvl; @@ -1153,9 +1155,18 @@ begin fModified := false; TextBuffer.AddNotifyHandler(senrUndoRedoAdded, @changeNotify); - Gutter.MarksPart.AutoSize:=false; - Gutter.MarksPart.Width := ScaleX(20,96); + Gutter.MarksPart.Visible:=false; + + fMultiGutterMarks := TSynMultiGutterMarks.Create(Gutter.Parts); + fMultiGutterMarks.columnCount := 2; + fMultiGutterMarks.columnWidth := ScaleX(20,96); + fMultiGutterMarks.AutoSize := true; + fMultiGutterMarks.Index := 1; + fImages := TImageList.Create(self); + + fMultiGutterMarks.images := fImages; + z := GetIconScaledSize; case z of iss16: @@ -3901,7 +3912,7 @@ var p: TPoint; begin p := ScreenToClient(mouse.CursorPos); - if p.x > Gutter.MarksPart.Width then + if p.x > fMultiGutterMarks.Width then exit; p := self.PixelsToRowColumn(p); showWarningForLine(p.y); @@ -3935,6 +3946,19 @@ begin exit(true); 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; begin result := isGutterIconSet(line, giBreakSet); @@ -3963,7 +3987,8 @@ begin begin n := m.Items[i]; s := n.ImageIndex = longint(value); - n.Visible := s; + if s then + n.Visible := true; end; if not s then begin @@ -3972,6 +3997,7 @@ begin n.ImageList := fImages; n.ImageIndex := longint(value); n.Visible := true; + n.Column:= gutterIconKindToColumn(value); Marks.Add(n); end; end; @@ -4001,6 +4027,7 @@ var i: integer; m: TSynEditMark; begin + fMultiGutterMarks.columnCount := 3; fDebugger := debugger; fDebugger.removeBreakPoints(fileName); for i := 0 to marks.count - 1 do @@ -4013,6 +4040,7 @@ end; procedure TDexedMemo.debugStop; begin + fMultiGutterMarks.columnCount := 2; removeDebugTimeMarks; end; @@ -4042,6 +4070,8 @@ begin if fname <> fFilename then exit; showPage; + // newly opened source has not 3 cols yet + fMultiGutterMarks.columnCount := 3; caretY := line; EnsureCursorPosVisible; removeDebugTimeMarks; diff --git a/src/u_synmultiguttermarks.pas b/src/u_synmultiguttermarks.pas new file mode 100644 index 00000000..7d7fd5d7 --- /dev/null +++ b/src/u_synmultiguttermarks.pas @@ -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. +