SynEdit: start refactor gutter painting

git-svn-id: trunk@34829 -
This commit is contained in:
martin 2012-01-21 03:16:05 +00:00
parent e588d500e4
commit bd8a968767
7 changed files with 195 additions and 67 deletions

View File

@ -14,7 +14,7 @@ type
{ TLazSynTextArea }
TLazSynTextArea = class(TPersistent)
TLazSynTextArea = class(TLazSynSurface)
private
FCharsInWindow: Integer;
FCharWidth: integer;
@ -32,7 +32,7 @@ type
FBackgroundColor: TColor;
FRightEdgeColor: TColor;
FBounds, FTextBounds: TRect;
FTextBounds: TRect;
FPadding: array [TLazSynBorderSide] of Integer;
FExtraCharSpacing: integer;
FExtraLineSpacing: integer;
@ -51,6 +51,8 @@ type
procedure SetTopLine(AValue: TLinePos);
procedure DoDrawerFontChanged(Sender: TObject);
protected
procedure BoundsChanged; override;
procedure DoPaint(ACanvas: TCanvas; AClip: TRect); override;
procedure PaintTextLines(AClip: TRect; FirstLine, LastLine,
FirstCol, LastCol: integer); virtual;
property Canvas: TCanvas read FCanvas;
@ -63,11 +65,9 @@ type
function RowColumnToPixels(const RowCol: TPoint): TPoint;
function PixelsToRowColumn(Pixels: TPoint; aFlags: TSynCoordinateMappingFlags): TPoint; // ignores scmLimitToLines
procedure FontChanged; // must be called by owner of shared tetdrawer
procedure Paint(ACanvas: TCanvas; AClip: TRect);
procedure FontChanged;
// Settings controlled by SynEdit
procedure SetBounds(ATop, ALeft, ABottom, ARight: Integer);
property Padding[Side: TLazSynBorderSide]: integer read GetPadding write SetPadding;
property ForegroundColor: TColor read FForegroundColor write FForegroundColor;
property BackgroundColor: TColor read FBackgroundColor write FBackgroundColor;
@ -86,11 +86,6 @@ type
property Highlighter: TSynCustomHighlighter read FHighlighter write FHighlighter;
property MarkupManager: TSynEditMarkupManager read FMarkupManager write FMarkupManager;
public
property Left: Integer read FBounds.Left;
property Top: Integer read FBounds.Top;
property Right:Integer read FBounds.Right;
property Bottom: integer read FBounds.Bottom;
property Bounds: TRect read FBounds;
property TextBounds: TRect read FTextBounds;
property LineHeight: integer read FTextHeight;
@ -99,24 +94,74 @@ type
property CharsInWindow: Integer read FCharsInWindow;
end;
{ TLazSynSurfaceManager }
TLazSynSurfaceManager = class(TLazSynSurface)
private
FLeftGutterArea: TLazSynSurface;
FLeftGutterWidth: integer;
FRightGutterArea: TLazSynSurface;
FRightGutterWidth: integer;
FTextArea: TLazSynTextArea;
procedure SetLeftGutterWidth(AValue: integer);
procedure SetRightGutterWidth(AValue: integer);
protected
procedure DoPaint(ACanvas: TCanvas; AClip: TRect); override;
procedure BoundsChanged; override;
public
constructor Create;
property TextArea: TLazSynTextArea read FTextArea write FTextArea;
property LeftGutterArea: TLazSynSurface read FLeftGutterArea write FLeftGutterArea;
property RightGutterArea: TLazSynSurface read FRightGutterArea write FRightGutterArea;
property LeftGutterWidth: integer read FLeftGutterWidth write SetLeftGutterWidth;
property RightGutterWidth: integer read FRightGutterWidth write SetRightGutterWidth;
end;
implementation
{ TLazSynTextArea }
{ TLazSynSurfaceManager }
procedure TLazSynTextArea.SetBounds(ATop, ALeft, ABottom, ARight: Integer);
procedure TLazSynSurfaceManager.SetLeftGutterWidth(AValue: integer);
begin
FBounds.Left := ALeft;
FBounds.Top := ATop;
FBounds.Right := ARight;
FBounds.Bottom := ABottom;
FTextBounds.Left := Left + FPadding[bsLeft];
FTextBounds.Top := Top + FPadding[bsTop];
FTextBounds.Right := Right - FPadding[bsRight];
FTextBounds.Bottom := Bottom - FPadding[bsBottom];
FontChanged;
if FLeftGutterWidth = AValue then Exit;
FLeftGutterWidth := AValue;
BoundsChanged;
end;
procedure TLazSynSurfaceManager.SetRightGutterWidth(AValue: integer);
begin
if FRightGutterWidth = AValue then Exit;
FRightGutterWidth := AValue;
BoundsChanged;
end;
procedure TLazSynSurfaceManager.DoPaint(ACanvas: TCanvas; AClip: TRect);
begin
FLeftGutterArea.Paint(ACanvas, AClip);
FTextArea.Paint(ACanvas, AClip);
FRightGutterArea.Paint(ACanvas, AClip);
end;
procedure TLazSynSurfaceManager.BoundsChanged;
var
l, r: Integer;
begin
r := Max(Left, Right - RightGutterWidth);
l := Min(r, Left + LeftGutterWidth);
FLeftGutterArea.SetBounds(Top, Left, Bottom, l);
FTextArea.SetBounds(Top, l, Bottom, r);
FRightGutterArea.SetBounds(Top, r, Bottom, Right);
end;
constructor TLazSynSurfaceManager.Create;
begin
FLeftGutterWidth := 0;
FRightGutterWidth := 0;
end;
{ TLazSynTextArea }
function TLazSynTextArea.GetPadding(Side: TLazSynBorderSide): integer;
begin
Result := FPadding[Side];
@ -167,6 +212,15 @@ begin
FontChanged;
end;
procedure TLazSynTextArea.BoundsChanged;
begin
FTextBounds.Left := Left + FPadding[bsLeft];
FTextBounds.Top := Top + FPadding[bsTop];
FTextBounds.Right := Right - FPadding[bsRight];
FTextBounds.Bottom := Bottom - FPadding[bsBottom];
FontChanged;
end;
function TLazSynTextArea.ScreenColumnToXValue(Col: integer): integer;
begin
Result := FTextBounds.Left + (Col - LeftChar) * fCharWidth;
@ -239,18 +293,12 @@ begin
FLinesInWindow := Max(0, (FTextBounds.Bottom - FTextBounds.Top) div FTextHeight);
end;
procedure TLazSynTextArea.Paint(ACanvas: TCanvas; AClip: TRect);
procedure TLazSynTextArea.DoPaint(ACanvas: TCanvas; AClip: TRect);
var
PadRect, PadRect2: TRect;
ScreenRow1, ScreenRow2, TextColumn1, TextColumn2: integer;
dc: HDC;
begin
if (AClip.Left >= FBounds.Right) or
(AClip.Right <= FBounds.Left) or
(AClip.Top >= FBounds.Bottom) or
(AClip.Bottom <= FBounds.Top)
then
exit;
// paint padding
FCanvas := ACanvas;
@ -258,25 +306,25 @@ begin
SetBkColor(dc, ColorToRGB(BackgroundColor));
if (AClip.Top < FTextBounds.Top) then begin
PadRect2 := FBounds;
PadRect2 := Bounds;
PadRect2.Bottom := FTextBounds.Top;
IntersectRect(PadRect, AClip, PadRect2);
InternalFillRect(dc, PadRect);
end;
if (AClip.Bottom > FTextBounds.Bottom) then begin
PadRect2 := FBounds;
PadRect2 := Bounds;
PadRect2.Top := FTextBounds.Bottom;
IntersectRect(PadRect, AClip, PadRect2);
InternalFillRect(dc, PadRect);
end;
if (AClip.Left < FTextBounds.Left) then begin
PadRect2 := FBounds;
PadRect2 := Bounds;
PadRect2.Right := FTextBounds.Left;
IntersectRect(PadRect, AClip, PadRect2);
InternalFillRect(dc, PadRect);
end;
if (AClip.Right > FTextBounds.Right) then begin
PadRect2 := FBounds;
PadRect2 := Bounds;
PadRect2.Left := FTextBounds.Right;
IntersectRect(PadRect, AClip, PadRect2);
InternalFillRect(dc, PadRect);

View File

@ -433,6 +433,8 @@ type
FTopLinesView: TSynEditStrings; // The linesview that holds the real line-buffer/FLines
FDisplayView: TLazSynDisplayView;
FTextArea: TLazSynTextArea;
FLeftGutterArea, FRightGutterArea: TLazSynGutterArea;
FPaintArea: TLazSynSurfaceManager;
fExtraCharSpacing: integer;
fMaxLeftChar: Integer; // 1024
@ -1910,6 +1912,18 @@ begin
FTextArea.DisplayView := FDisplayView;
FTextArea.Highlighter := nil;
FLeftGutterArea := TLazSynGutterArea.Create;
FLeftGutterArea.TextArea := FTextArea;
FLeftGutterArea.Gutter := FLeftGutter;
FRightGutterArea := TLazSynGutterArea.Create;
FRightGutterArea.TextArea := FTextArea;
FRightGutterArea.Gutter := FRightGutter;
FPaintArea := TLazSynSurfaceManager.Create;
FPaintArea.TextArea := FTextArea;
FPaintArea.LeftGutterArea := FLeftGutterArea;
FPaintArea.RightGutterArea := FRightGutterArea;
Color := clWhite;
Font.Assign(fFontDummy);
Font.OnChange := {$IFDEF FPC}@{$ENDIF}FontChanged;
@ -2161,6 +2175,9 @@ begin
FCaret.Lines := nil;
FInternalCaret.Lines := nil;
FMarkList.UnRegisterChangeHandler({$IFDEF FPC}@{$ENDIF}MarkListChange);
FreeAndNil(FPaintArea);
FreeAndNil(FLeftGutterArea);
FreeAndNil(FRightGutterArea);
FreeAndNil(FTextArea);
FreeAndNil(fTSearch);
FreeAndNil(fMarkupManager);
@ -3083,8 +3100,6 @@ begin
end;
procedure TCustomSynEdit.MouseMove(Shift: TShiftState; X, Y: Integer);
var
Z: integer;
begin
Exclude(FStateFlags, sfHideCursor);
inherited MouseMove(Shift, x, y);
@ -3173,7 +3188,6 @@ procedure TCustomSynEdit.ScrollTimerHandler(Sender: TObject);
var
C: TPoint;
CurMousePos: TPoint;
Z: integer;
X, Y: Integer;
begin
// changes to line / column in one go
@ -3315,8 +3329,7 @@ end;
procedure TCustomSynEdit.Paint;
var
rcClip, rcDraw: TRect;
nL1, nL2: integer;
rcClip: TRect;
begin
// Get the invalidated rect. Compute the invalid area in lines / columns.
rcClip := Canvas.ClipRect;
@ -3349,32 +3362,10 @@ begin
Include(fStateFlags,sfPainting);
Exclude(fStateFlags, sfHasScrolled);
// columns
nL1 := Max(rcClip.Top div LineHeight, 0);
nL2 := Min((rcClip.Bottom-1) div LineHeight,
FFoldedLinesView.Count - FFoldedLinesView.TopLine);
{$IFDEF SYNSCROLLDEBUG}
debugln(['PAINT ',DbgSName(self),' rect=',dbgs(rcClip), ' L1=',nL1, ' Nl2=',nL2]);
{$ENDIF}
//DebugLn('TCustomSynEdit.Paint LinesInWindow=',dbgs(LinesInWindow),' nL1=',dbgs(nL1),' nL2=',dbgs(nL2));
// Now paint everything while the caret is hidden.
FScreenCaret.Hide;
try
// First paint the gutter area if it was (partly) invalidated.
if FLeftGutter.Visible and (rcClip.Left < FLeftGutter.Width) then begin
rcDraw := rcClip;
rcDraw.Right := FLeftGutter.Width;
FLeftGutter.Paint(Canvas, rcDraw, nL1, nL2);
end;
// Then paint the text area if it was (partly) invalidated.
FTextArea.Paint(Canvas, rcClip);
// right gutter
if FRightGutter.Visible and (rcClip.Right > ClientWidth - FRightGutter.Width - ScrollBarWidth) then begin
rcDraw := rcClip;
rcDraw.Left := ClientWidth - FRightGutter.Width - ScrollBarWidth;
FRightGutter.Paint(Canvas, rcDraw, nL1, nL2);
end;
// If there is a custom paint handler call it.
FPaintArea.Paint(Canvas, rcClip);
DoOnPaint;
finally
{$IFDEF EnableDoubleBuf}
@ -7027,8 +7018,11 @@ begin
else r := 0;
OldLinesInWindow := FTextArea.LinesInWindow;
// TODO: lock FTextArea, so size re-calc is done once only
FTextArea.SetBounds(0, l, ClientHeight - ScrollBarWidth, ClientWidth - r - ScrollBarWidth);
FPaintArea.SetBounds(0, 0, ClientHeight - ScrollBarWidth, ClientWidth - ScrollBarWidth);
FPaintArea.LeftGutterWidth := l;
FPaintArea.RightGutterWidth := r;
if FLeftGutter.Visible
then FTextArea.Padding[bsLeft] := GutterTextDist
@ -7173,10 +7167,8 @@ end;
procedure TCustomSynEdit.RecalcCharExtent;
var
i: Integer;
OldLinesInWindow: Integer;
begin
(* Highlighter or Font changed *)
OldLinesInWindow := FTextArea.LinesInWindow;
FFontDummy.Assign(Font);
with FFontDummy do begin

View File

@ -264,6 +264,25 @@ type
property UnderlinePriority default 0;
end;
{ TLazSynSurface }
TLazSynSurface = class
private
FBounds: TRect;
protected
procedure BoundsChanged; virtual;
procedure DoPaint(ACanvas: TCanvas; AClip: TRect); virtual; abstract;
public
procedure Paint(ACanvas: TCanvas; AClip: TRect);
procedure SetBounds(ATop, ALeft, ABottom, ARight: Integer);
property Left: Integer read FBounds.Left;
property Top: Integer read FBounds.Top;
property Right:Integer read FBounds.Right;
property Bottom: integer read FBounds.Bottom;
property Bounds: TRect read FBounds;
end;
{ TSynBookMarkOpt }
TSynBookMarkOpt = class(TPersistent)
@ -804,6 +823,43 @@ begin
(Style <> []) or (StyleMask <> []);
end;
{ TLazSynSurface }
procedure TLazSynSurface.BoundsChanged;
begin
//
end;
procedure TLazSynSurface.Paint(ACanvas: TCanvas; AClip: TRect);
begin
if (AClip.Left >= Bounds.Right) or
(AClip.Right <= Bounds.Left) or
(AClip.Top >= Bounds.Bottom) or
(AClip.Bottom <= Bounds.Top)
then
exit;
if (AClip.Left < Bounds.Left) then AClip.Left := Bounds.Left;
if (AClip.Right > Bounds.Right) then AClip.Right := Bounds.Right;
if (AClip.Top < Bounds.Top) then AClip.Top := Bounds.Top;
if (AClip.Bottom < Bounds.Bottom) then AClip.Bottom := Bounds.Bottom;
DoPaint(ACanvas, AClip);
end;
procedure TLazSynSurface.SetBounds(ATop, ALeft, ABottom, ARight: Integer);
begin
if (FBounds.Left = ALeft) and (FBounds.Top = ATop) and
(FBounds.Right = ARight) and (FBounds.Bottom = ABottom)
then exit;
FBounds.Left := ALeft;
FBounds.Top := ATop;
FBounds.Right := ARight;
FBounds.Bottom := ABottom;
BoundsChanged;
end;
{ TSynBookMarkOpt }
constructor TSynBookMarkOpt.Create(AOwner: TComponent);

View File

@ -6,7 +6,7 @@ interface
uses
SysUtils, Classes, Controls, Graphics, LCLType, LCLIntf, Menus,
SynEditMarks, SynEditMiscClasses, SynEditMiscProcs,
SynEditMarks, SynEditMiscClasses, SynEditMiscProcs, LazSynTextArea,
SynTextDrawer, SynGutterBase, SynGutterLineNumber, SynGutterCodeFolding,
SynGutterMarks, SynGutterChanges, SynEditMouseCmds;
@ -92,11 +92,36 @@ type
procedure InitForOptions(AnOptions: TSynEditorMouseOptions); override;
end;
{ TLazSynGutterArea }
TLazSynGutterArea = class(TLazSynSurface)
private
FGutter: TSynGutter;
FTextArea: TLazSynTextArea;
protected
procedure DoPaint(ACanvas: TCanvas; AClip: TRect); override;
public
property TextArea: TLazSynTextArea read FTextArea write FTextArea;
property Gutter: TSynGutter read FGutter write FGutter;
end;
implementation
uses
SynEdit;
{ TLazSynGutterArea }
procedure TLazSynGutterArea.DoPaint(ACanvas: TCanvas; AClip: TRect);
var
ScreenRow1, ScreenRow2: integer;
begin
// TODO TextArea top/bottom padding;
ScreenRow1 := Max((AClip.Top - Bounds.Top) div TextArea.LineHeight, 0);
ScreenRow2 := Min((AClip.Bottom-1 - Bounds.Top) div TextArea.LineHeight, TextArea.LinesInWindow + 1);
FGutter.Paint(ACanvas, AClip, ScreenRow1, ScreenRow2);
end;
{ TSynGutter }
constructor TSynGutter.Create(AOwner: TSynEditBase; ASide: TSynGutterSide;

View File

@ -74,7 +74,7 @@ end;
procedure TSynGutterChanges.Paint(Canvas: TCanvas; AClip: TRect; FirstLine, LastLine: integer);
var
i, iLine: integer;
i, c, iLine: integer;
LineHeight: Integer;
rcLine: TRect;
AliasMode: TAntialiasingMode;
@ -82,6 +82,7 @@ begin
if not Visible then exit;
LineHeight := TCustomSynEdit(SynEdit).LineHeight;
c := TCustomSynEdit(SynEdit).Lines.Count;
if MarkupInfo.Background <> clNone then
begin
@ -100,6 +101,7 @@ begin
for i := FirstLine to LastLine do
begin
iLine := FoldView.TextIndex[i];
if (iLine < 0) or (iLine >= c) then break;
// next line rect
rcLine.Top := rcLine.Bottom;
Inc(rcLine.Bottom, LineHeight);

View File

@ -218,7 +218,7 @@ end;
procedure TSynGutterLineNumber.Paint(Canvas : TCanvas; AClip : TRect; FirstLine, LastLine : integer);
var
i, iLine: integer;
i, c, iLine: integer;
rcLine: TRect;
s: string;
dc: HDC;
@ -229,6 +229,7 @@ begin
if not Visible then exit;
LineHeight := TCustomSynEdit(SynEdit).LineHeight;
c := TCustomSynEdit(SynEdit).Lines.Count;
// Changed to use fTextDrawer.BeginDrawing and fTextDrawer.EndDrawing only
// when absolutely necessary. Note: Never change brush / pen / font of the
// canvas inside of this block (only through methods of fTextDrawer)!
@ -256,6 +257,7 @@ begin
for i := FirstLine to LastLine do
begin
iLine := FoldView.DisplayNumber[i];
if (iLine < 0) or (iLine >= c) then break;
// next line rect
rcLine.Top := rcLine.Bottom;
// Must show a dot instead of line number if

View File

@ -123,7 +123,10 @@ begin
aFirstCustomColumnIdx := 0;
if FBookMarkOpt.DrawBookmarksFirst then
aFirstCustomColumnIdx := 1;
MLine := TCustomSynEdit(SynEdit).Marks.Line[FoldView.TextIndex[aScreenLine] + 1];
j := FoldView.TextIndex[aScreenLine];
if (j < 0) or (j >= TCustomSynEdit(SynEdit).Lines.Count) then
exit;
MLine := TCustomSynEdit(SynEdit).Marks.Line[j + 1];
if MLine = nil then
exit;