SynEdit: fixed incorrect line-invalidation / repaint when scrolling (with folded text)

This commit is contained in:
Martin 2022-04-01 15:00:14 +02:00
parent 013e6a61a5
commit 5b23421c5d
5 changed files with 49 additions and 36 deletions

View File

@ -154,7 +154,7 @@ type
constructor Create(AOwner: TWinControl; ATextDrawer: TheTextDrawer); constructor Create(AOwner: TWinControl; ATextDrawer: TheTextDrawer);
destructor Destroy; override; destructor Destroy; override;
procedure Assign(Src: TLazSynSurface); override; procedure Assign(Src: TLazSynSurface); override;
procedure InvalidateLines(FirstTextLine, LastTextLine: TLineIdx); override; procedure InvalidateLines(FirstTextLine, LastTextLine: TLineIdx; AScreenLineOffset: Integer = 0); override;
function ScreenColumnToXValue(Col: integer): integer; // map screen column to screen pixel function ScreenColumnToXValue(Col: integer): integer; // map screen column to screen pixel
function RowColumnToPixels(const RowCol: TPoint): TPoint; function RowColumnToPixels(const RowCol: TPoint): TPoint;
@ -239,9 +239,9 @@ type
procedure BoundsChanged; override; procedure BoundsChanged; override;
public public
constructor Create(AOwner: TWinControl); constructor Create(AOwner: TWinControl);
procedure InvalidateLines(FirstTextLine, LastTextLine: TLineIdx); override; procedure InvalidateLines(FirstTextLine, LastTextLine: TLineIdx; AScreenLineOffset: Integer = 0); override;
procedure InvalidateTextLines(FirstTextLine, LastTextLine: TLineIdx); virtual; procedure InvalidateTextLines(FirstTextLine, LastTextLine: TLineIdx; AScreenLineOffset: Integer = 0); virtual;
procedure InvalidateGutterLines(FirstTextLine, LastTextLine: TLineIdx); virtual; procedure InvalidateGutterLines(FirstTextLine, LastTextLine: TLineIdx; AScreenLineOffset: Integer = 0); virtual;
property LeftGutterArea: TLazSynSurfaceWithText read GetLeftGutterArea write SetLeftGutterArea; property LeftGutterArea: TLazSynSurfaceWithText read GetLeftGutterArea write SetLeftGutterArea;
property RightGutterArea: TLazSynSurfaceWithText read GetRightGutterArea write SetRightGutterArea; property RightGutterArea: TLazSynSurfaceWithText read GetRightGutterArea write SetRightGutterArea;
@ -1160,7 +1160,8 @@ begin
FRightGutterWidth := 0; FRightGutterWidth := 0;
end; end;
procedure TLazSynSurfaceManager.InvalidateLines(FirstTextLine, LastTextLine: TLineIdx); procedure TLazSynSurfaceManager.InvalidateLines(FirstTextLine,
LastTextLine: TLineIdx; AScreenLineOffset: Integer);
var var
rcInval: TRect; rcInval: TRect;
ViewedRange: TLineRange; ViewedRange: TLineRange;
@ -1169,14 +1170,14 @@ begin
if (FirstTextLine >= 0) then begin if (FirstTextLine >= 0) then begin
ViewedRange := DisplayView.TextToViewIndex(FirstTextLine); ViewedRange := DisplayView.TextToViewIndex(FirstTextLine);
rcInval.Top := Max(TextArea.TextBounds.Top, rcInval.Top := Max(TextArea.TextBounds.Top,
TextArea.TextBounds.Top + (ViewedRange.Top TextArea.TextBounds.Top + (ViewedRange.Top + AScreenLineOffset
- TextArea.TopLine + 1) * TextArea.LineHeight); - TextArea.TopLine + 1) * TextArea.LineHeight);
end; end;
if (LastTextLine >= 0) then begin if (LastTextLine >= 0) then begin
if LastTextLine <> FirstTextLine then if LastTextLine <> FirstTextLine then
ViewedRange := DisplayView.TextToViewIndex(LastTextLine); ViewedRange := DisplayView.TextToViewIndex(LastTextLine);
rcInval.Bottom := Min(TextArea.TextBounds.Bottom, rcInval.Bottom := Min(TextArea.TextBounds.Bottom,
TextArea.TextBounds.Top + (ViewedRange.Bottom TextArea.TextBounds.Top + (ViewedRange.Bottom + AScreenLineOffset
- TextArea.TopLine + 2) * TextArea.LineHeight); - TextArea.TopLine + 2) * TextArea.LineHeight);
end; end;
@ -1187,15 +1188,17 @@ begin
InvalidateRect(Handle, @rcInval, FALSE); InvalidateRect(Handle, @rcInval, FALSE);
end; end;
procedure TLazSynSurfaceManager.InvalidateTextLines(FirstTextLine, LastTextLine: TLineIdx); procedure TLazSynSurfaceManager.InvalidateTextLines(FirstTextLine,
LastTextLine: TLineIdx; AScreenLineOffset: Integer);
begin begin
FTextArea.InvalidateLines(FirstTextLine, LastTextLine); FTextArea.InvalidateLines(FirstTextLine, LastTextLine, AScreenLineOffset);
end; end;
procedure TLazSynSurfaceManager.InvalidateGutterLines(FirstTextLine, LastTextLine: TLineIdx); procedure TLazSynSurfaceManager.InvalidateGutterLines(FirstTextLine,
LastTextLine: TLineIdx; AScreenLineOffset: Integer);
begin begin
FLeftGutterArea.InvalidateLines(FirstTextLine, LastTextLine); FLeftGutterArea.InvalidateLines(FirstTextLine, LastTextLine, AScreenLineOffset);
FRightGutterArea.InvalidateLines(FirstTextLine, LastTextLine); FRightGutterArea.InvalidateLines(FirstTextLine, LastTextLine, AScreenLineOffset);
end; end;
{ TLazSynTextArea } { TLazSynTextArea }
@ -1361,7 +1364,8 @@ begin
BoundsChanged; BoundsChanged;
end; end;
procedure TLazSynTextArea.InvalidateLines(FirstTextLine, LastTextLine: TLineIdx); procedure TLazSynTextArea.InvalidateLines(FirstTextLine,
LastTextLine: TLineIdx; AScreenLineOffset: Integer);
var var
rcInval: TRect; rcInval: TRect;
ViewedRange: TLineRange; ViewedRange: TLineRange;
@ -1370,13 +1374,13 @@ begin
if (FirstTextLine >= 0) then begin if (FirstTextLine >= 0) then begin
ViewedRange := DisplayView.TextToViewIndex(FirstTextLine); ViewedRange := DisplayView.TextToViewIndex(FirstTextLine);
rcInval.Top := Max(TextBounds.Top, rcInval.Top := Max(TextBounds.Top,
TextBounds.Top + (ViewedRange.Top - TopLine + 1) * LineHeight); TextBounds.Top + (ViewedRange.Top + AScreenLineOffset - TopLine + 1) * LineHeight);
end; end;
if (LastTextLine >= 0) then begin if (LastTextLine >= 0) then begin
if LastTextLine <> FirstTextLine then if LastTextLine <> FirstTextLine then
ViewedRange := DisplayView.TextToViewIndex(LastTextLine); ViewedRange := DisplayView.TextToViewIndex(LastTextLine);
rcInval.Bottom := Min(TextBounds.Bottom, rcInval.Bottom := Min(TextBounds.Bottom,
TextBounds.Top + (ViewedRange.Bottom - TopLine + 2) * LineHeight); TextBounds.Top + (ViewedRange.Bottom + AScreenLineOffset - TopLine + 2) * LineHeight);
end; end;
{$IFDEF VerboseSynEditInvalidate} {$IFDEF VerboseSynEditInvalidate}

View File

@ -2953,6 +2953,8 @@ begin
end; end;
procedure TCustomSynEdit.InvalidateGutterLines(FirstLine, LastLine: integer); // Todo: move to gutter procedure TCustomSynEdit.InvalidateGutterLines(FirstLine, LastLine: integer); // Todo: move to gutter
var
offs: Integer;
begin begin
if sfPainting in fStateFlags then exit; if sfPainting in fStateFlags then exit;
if Visible and HandleAllocated then begin if Visible and HandleAllocated then begin
@ -2969,12 +2971,12 @@ begin
if (LastLine <> -1) and (LastLine < FirstLine) then if (LastLine <> -1) and (LastLine < FirstLine) then
SwapInt(FirstLine, LastLine); SwapInt(FirstLine, LastLine);
offs := 0;
if FPaintLock > 0 then begin if FPaintLock > 0 then begin
// pretend we haven't scrolled // pretend we haven't scrolled
FirstLine := FirstLine - (FOldTopView - TopView); offs := - (FOldTopView - TopView);
LastLine := LastLine - (FOldTopView - TopView);
end; end;
FPaintArea.InvalidateGutterLines(FirstLine-1, LastLine-1); FPaintArea.InvalidateGutterLines(FirstLine-1, LastLine-1, offs);
end; end;
{$IFDEF VerboseSynEditInvalidate} {$IFDEF VerboseSynEditInvalidate}
DebugLnExit(['TCustomSynEdit.InvalidateGutterLines ',DbgSName(self)]); DebugLnExit(['TCustomSynEdit.InvalidateGutterLines ',DbgSName(self)]);
@ -2984,6 +2986,8 @@ begin
end; end;
procedure TCustomSynEdit.InvalidateLines(FirstLine, LastLine: integer); procedure TCustomSynEdit.InvalidateLines(FirstLine, LastLine: integer);
var
offs: Integer;
begin begin
if sfPainting in fStateFlags then exit; if sfPainting in fStateFlags then exit;
if Visible and HandleAllocated then begin if Visible and HandleAllocated then begin
@ -2996,12 +3000,12 @@ begin
if (LastLine <> -1) and (LastLine < FirstLine) then if (LastLine <> -1) and (LastLine < FirstLine) then
SwapInt(FirstLine, LastLine); SwapInt(FirstLine, LastLine);
offs := 0;
if FPaintLock > 0 then begin if FPaintLock > 0 then begin
// pretend we haven't scrolled // pretend we haven't scrolled
FirstLine := FirstLine - (FOldTopView - TopView); offs := - (FOldTopView - TopView);
LastLine := LastLine - (FOldTopView - TopView);
end; end;
FPaintArea.InvalidateTextLines(FirstLine-1, LastLine-1); FPaintArea.InvalidateTextLines(FirstLine-1, LastLine-1, offs);
end; end;
{$IFDEF VerboseSynEditInvalidate} {$IFDEF VerboseSynEditInvalidate}
DebugLnExit(['TCustomSynEdit.InvalidateTextLines ',DbgSName(self)]); DebugLnExit(['TCustomSynEdit.InvalidateTextLines ',DbgSName(self)]);

View File

@ -593,7 +593,7 @@ type
procedure RemoveBoundsChangeHandler(AHandler: TNotifyEvent); procedure RemoveBoundsChangeHandler(AHandler: TNotifyEvent);
procedure Paint(ACanvas: TCanvas; AClip: TRect); procedure Paint(ACanvas: TCanvas; AClip: TRect);
procedure InvalidateLines(FirstTextLine, LastTextLine: TLineIdx); virtual; procedure InvalidateLines(FirstTextLine, LastTextLine: TLineIdx; AScreenLineOffset: Integer = 0); virtual;
procedure SetBounds(ATop, ALeft, ABottom, ARight: Integer); procedure SetBounds(ATop, ALeft, ABottom, ARight: Integer);
property Left: Integer read FBounds.Left; property Left: Integer read FBounds.Left;
@ -1634,7 +1634,8 @@ begin
DoPaint(ACanvas, AClip); DoPaint(ACanvas, AClip);
end; end;
procedure TLazSynSurface.InvalidateLines(FirstTextLine, LastTextLine: TLineIdx); procedure TLazSynSurface.InvalidateLines(FirstTextLine, LastTextLine: TLineIdx;
AScreenLineOffset: Integer);
begin begin
// //
end; end;

View File

@ -108,7 +108,7 @@ type
protected protected
procedure DoPaint(ACanvas: TCanvas; AClip: TRect); override; procedure DoPaint(ACanvas: TCanvas; AClip: TRect); override;
public public
procedure InvalidateLines(FirstTextLine, LastTextLine: TLineIdx); override; procedure InvalidateLines(FirstTextLine, LastTextLine: TLineIdx; AScreenLineOffset: Integer = 0); override;
procedure Assign(Src: TLazSynSurface); override; procedure Assign(Src: TLazSynSurface); override;
property Gutter: TSynGutter read FGutter write SetGutter; property Gutter: TSynGutter read FGutter write SetGutter;
property TextBounds: TRect read GetTextBounds; property TextBounds: TRect read GetTextBounds;
@ -144,7 +144,8 @@ begin
FGutter.Paint(ACanvas, Self, AClip, ScreenRow1, ScreenRow2); FGutter.Paint(ACanvas, Self, AClip, ScreenRow1, ScreenRow2);
end; end;
procedure TLazSynGutterArea.InvalidateLines(FirstTextLine, LastTextLine: TLineIdx); procedure TLazSynGutterArea.InvalidateLines(FirstTextLine,
LastTextLine: TLineIdx; AScreenLineOffset: Integer);
var var
rcInval: TRect; rcInval: TRect;
begin begin
@ -152,12 +153,12 @@ begin
if (FirstTextLine >= 0) then if (FirstTextLine >= 0) then
rcInval.Top := Max(TextArea.TextBounds.Top, rcInval.Top := Max(TextArea.TextBounds.Top,
TextArea.TextBounds.Top TextArea.TextBounds.Top
+ (DisplayView.TextToViewIndex(FirstTextLine).Top + (DisplayView.TextToViewIndex(FirstTextLine).Top + AScreenLineOffset
- TextArea.TopLine + 1) * TextArea.LineHeight); - TextArea.TopLine + 1) * TextArea.LineHeight);
if (LastTextLine >= 0) then if (LastTextLine >= 0) then
rcInval.Bottom := Min(TextArea.TextBounds.Bottom, rcInval.Bottom := Min(TextArea.TextBounds.Bottom,
TextArea.TextBounds.Top TextArea.TextBounds.Top
+ (DisplayView.TextToViewIndex(LastTextLine).Bottom + (DisplayView.TextToViewIndex(LastTextLine).Bottom + AScreenLineOffset
- TextArea.TopLine + 2) * TextArea.LineHeight); - TextArea.TopLine + 2) * TextArea.LineHeight);
{$IFDEF VerboseSynEditInvalidate} {$IFDEF VerboseSynEditInvalidate}

View File

@ -131,9 +131,9 @@ type
public public
constructor Create(AOwner: TWinControl; AnOriginalManager: TLazSynSurfaceManager); constructor Create(AOwner: TWinControl; AnOriginalManager: TLazSynSurfaceManager);
destructor Destroy; override; destructor Destroy; override;
procedure InvalidateLines(FirstTextLine, LastTextLine: TLineIdx); override; procedure InvalidateLines(FirstTextLine, LastTextLine: TLineIdx; AScreenLineOffset: Integer = 0); override;
procedure InvalidateTextLines(FirstTextLine, LastTextLine: TLineIdx); override; procedure InvalidateTextLines(FirstTextLine, LastTextLine: TLineIdx; AScreenLineOffset: Integer = 0); override;
procedure InvalidateGutterLines(FirstTextLine, LastTextLine: TLineIdx); override; procedure InvalidateGutterLines(FirstTextLine, LastTextLine: TLineIdx; AScreenLineOffset: Integer = 0); override;
property ExtraManager: TLazSynSurfaceManager read FExtraManager write FExtraManager; property ExtraManager: TLazSynSurfaceManager read FExtraManager write FExtraManager;
property OriginalManager: TLazSynSurfaceManager read FOriginalManager write FOriginalManager; property OriginalManager: TLazSynSurfaceManager read FOriginalManager write FOriginalManager;
property TopLineCount: Integer read FTopLineCount write SetTopLineCount; property TopLineCount: Integer read FTopLineCount write SetTopLineCount;
@ -1418,21 +1418,24 @@ begin
FOriginalManager.Free; FOriginalManager.Free;
end; end;
procedure TSourceLazSynSurfaceManager.InvalidateLines(FirstTextLine, LastTextLine: TLineIdx); procedure TSourceLazSynSurfaceManager.InvalidateLines(FirstTextLine,
LastTextLine: TLineIdx; AScreenLineOffset: Integer);
begin begin
FOriginalManager.InvalidateLines(FirstTextLine, LastTextLine); FOriginalManager.InvalidateLines(FirstTextLine, LastTextLine, AScreenLineOffset);
FExtraManager.InvalidateLines(FirstTextLine, LastTextLine); FExtraManager.InvalidateLines(FirstTextLine, LastTextLine);
end; end;
procedure TSourceLazSynSurfaceManager.InvalidateTextLines(FirstTextLine, LastTextLine: TLineIdx); procedure TSourceLazSynSurfaceManager.InvalidateTextLines(FirstTextLine,
LastTextLine: TLineIdx; AScreenLineOffset: Integer);
begin begin
FOriginalManager.InvalidateTextLines(FirstTextLine, LastTextLine); FOriginalManager.InvalidateTextLines(FirstTextLine, LastTextLine, AScreenLineOffset);
FExtraManager.InvalidateTextLines(FirstTextLine, LastTextLine); FExtraManager.InvalidateTextLines(FirstTextLine, LastTextLine);
end; end;
procedure TSourceLazSynSurfaceManager.InvalidateGutterLines(FirstTextLine, LastTextLine: TLineIdx); procedure TSourceLazSynSurfaceManager.InvalidateGutterLines(FirstTextLine,
LastTextLine: TLineIdx; AScreenLineOffset: Integer);
begin begin
FOriginalManager.InvalidateGutterLines(FirstTextLine, LastTextLine); FOriginalManager.InvalidateGutterLines(FirstTextLine, LastTextLine, AScreenLineOffset);
FExtraManager.InvalidateGutterLines(FirstTextLine, LastTextLine); FExtraManager.InvalidateGutterLines(FirstTextLine, LastTextLine);
end; end;