mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-02 16:12:35 +02:00
439 lines
12 KiB
ObjectPascal
439 lines
12 KiB
ObjectPascal
unit SynGutterLineOverview;
|
|
|
|
{$I synedit.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, Graphics, Controls, LCLProc, LCLType, LCLIntf, sysutils, math,
|
|
SynGutterBase, SynEditTypes, SynEditTextBase, SynEditTextBuffer, SynEditMiscClasses;
|
|
|
|
type
|
|
TSynGutterLineOverview = class;
|
|
TSynGutterLineOverviewProviderList = class;
|
|
|
|
{ TSynGutterLineOverviewProvider }
|
|
|
|
TSynGutterLineOverviewProvider = class(TSynObjectListItem)
|
|
private
|
|
FColor: TColor;
|
|
FHeight: Integer;
|
|
FGutterPart: TSynGutterLineOverview;
|
|
FPriority: Integer;
|
|
FRGBColor: TColor;
|
|
function GetList: TSynGutterLineOverviewProviderList;
|
|
procedure SetColor(const AValue: TColor);
|
|
procedure SetHeight(const AValue: Integer);
|
|
procedure SetPriority(const AValue: Integer);
|
|
protected
|
|
function Compare(Other: TSynObjectListItem): Integer; override;
|
|
procedure DoChange(Sender: TObject);
|
|
|
|
procedure InvalidateTextLines(AFromLine, AToLine: Integer);
|
|
procedure InvalidatePixelLines(AFromLine, AToLine: Integer);
|
|
function TextLineToPixel(ALine: Integer): Integer;
|
|
procedure ReCalc; virtual; // Does not invalidate
|
|
function PixLineHeight: Integer;
|
|
|
|
function SynEdit: TSynEditBase;
|
|
property Owner: TSynGutterLineOverviewProviderList read GetList; //the list
|
|
property GutterPart: TSynGutterLineOverview read FGutterPart;
|
|
property RGBColor: TColor read FRGBColor;
|
|
|
|
procedure Paint(Canvas: TCanvas; AClip: TRect; TopOffset: integer); virtual;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
property Height: Integer read FHeight write SetHeight;
|
|
published
|
|
property Priority: Integer read FPriority write SetPriority;
|
|
property Color: TColor read FColor write SetColor;
|
|
end;
|
|
|
|
{ TSynGutterLineOverviewProviderList }
|
|
|
|
TSynGutterLineOverviewProviderList = class(TSynObjectList)
|
|
private
|
|
function GetGutterPart: TSynGutterLineOverview;
|
|
function GetProviders(AIndex: Integer): TSynGutterLineOverviewProvider;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
property Owner: TSynGutterLineOverview read GetGutterPart;
|
|
property Providers[AIndex: Integer]: TSynGutterLineOverviewProvider
|
|
read GetProviders; default;
|
|
end;
|
|
|
|
{ TSynGutterLOvProviderCurrentPage }
|
|
|
|
TSynGutterLOvProviderCurrentPage = class(TSynGutterLineOverviewProvider)
|
|
private
|
|
FCurTopLine, FCurLinesInWindow: Integer;
|
|
FPixelTopLine, FPixelBottomLine: Integer;
|
|
protected
|
|
procedure SynStatusChanged(Sender: TObject; Changes: TSynStatusChanges);
|
|
|
|
procedure Paint(Canvas: TCanvas; AClip: TRect; TopOffset: integer); override;
|
|
procedure ReCalc; override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
TSynGutterLOvProviderModifiedLines = class(TSynGutterLineOverviewProvider)
|
|
end;
|
|
|
|
TSynGutterLOvProviderBookmarks = class(TSynGutterLineOverviewProvider)
|
|
end;
|
|
|
|
TSynGutterLOvProviderCustom = class(TSynGutterLineOverviewProvider)
|
|
end;
|
|
|
|
{ TSynChildWinControl
|
|
Allow individual invalidates, for less painting
|
|
}
|
|
|
|
TSynChildWinControl = class(TCustomControl)
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
end;
|
|
|
|
{ TSynGutterLineOverview }
|
|
|
|
TSynGutterLineOverview = class(TSynGutterPartBase)
|
|
private
|
|
FProviders: TSynGutterLineOverviewProviderList;
|
|
FWinControl: TSynChildWinControl;
|
|
protected
|
|
function PreferedWidth: Integer; override;
|
|
procedure Init; override;
|
|
procedure LineCountChanged(Sender: TSynEditStrings; AIndex, ACount: Integer);
|
|
procedure BufferChanged(Sender: TObject);
|
|
procedure SetVisible(const AValue : boolean); override;
|
|
procedure DoChange(Sender: TObject); override;
|
|
protected
|
|
procedure InvalidateTextLines(AFromLine, AToLine: Integer);
|
|
procedure InvalidatePixelLines(AFromLine, AToLine: Integer);
|
|
function TextLineToPixel(ALine: Integer): Integer;
|
|
procedure DoResize(Sender: TObject); override;
|
|
Procedure PaintWinControl(Sender: TObject);
|
|
public
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
|
|
procedure Paint(Canvas: TCanvas; AClip: TRect; FirstLine, LastLine: integer); override;
|
|
property Providers: TSynGutterLineOverviewProviderList read FProviders;
|
|
published
|
|
property MarkupInfo;
|
|
end;
|
|
|
|
implementation
|
|
uses
|
|
SynEdit;
|
|
|
|
{ TSynGutterLineOverviewProvider }
|
|
|
|
constructor TSynGutterLineOverviewProvider.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
FGutterPart := Owner.Owner;
|
|
FColor := clGray;
|
|
FriendEdit := SynEdit;
|
|
end;
|
|
|
|
destructor TSynGutterLineOverviewProvider.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TSynGutterLineOverviewProvider.GetList: TSynGutterLineOverviewProviderList;
|
|
begin
|
|
Result := TSynGutterLineOverviewProviderList(inherited Owner);
|
|
end;
|
|
|
|
procedure TSynGutterLineOverviewProvider.SetColor(const AValue: TColor);
|
|
begin
|
|
if FColor = AValue then exit;
|
|
FColor := AValue;
|
|
FRGBColor := ColorToRGB(AValue);
|
|
DoChange(Self);
|
|
end;
|
|
|
|
procedure TSynGutterLineOverviewProvider.SetHeight(const AValue: Integer);
|
|
begin
|
|
if FHeight = AValue then exit;
|
|
FHeight := AValue;
|
|
ReCalc;
|
|
end;
|
|
|
|
procedure TSynGutterLineOverviewProvider.SetPriority(const AValue: Integer);
|
|
begin
|
|
if FPriority = AValue then exit;
|
|
FPriority := AValue;
|
|
Owner.Sort;
|
|
end;
|
|
|
|
function TSynGutterLineOverviewProvider.SynEdit: TSynEditBase;
|
|
begin
|
|
Result := FGutterPart.SynEdit;
|
|
end;
|
|
|
|
function TSynGutterLineOverviewProvider.Compare(Other: TSynObjectListItem): Integer;
|
|
begin
|
|
Result := Priority - TSynGutterLineOverviewProvider(Other).Priority;
|
|
if Result = 0 then
|
|
Result := inherited Compare(Other);
|
|
end;
|
|
|
|
procedure TSynGutterLineOverviewProvider.DoChange(Sender: TObject);
|
|
begin
|
|
FGutterPart.DoChange(Sender);
|
|
end;
|
|
|
|
procedure TSynGutterLineOverviewProvider.InvalidateTextLines(AFromLine, AToLine: Integer);
|
|
begin
|
|
FGutterPart.InvalidateTextLines(AFromLine, AToLine);
|
|
end;
|
|
|
|
procedure TSynGutterLineOverviewProvider.InvalidatePixelLines(AFromLine, AToLine: Integer);
|
|
begin
|
|
FGutterPart.InvalidatePixelLines(AFromLine, AToLine);
|
|
end;
|
|
|
|
function TSynGutterLineOverviewProvider.TextLineToPixel(ALine: Integer): Integer;
|
|
var
|
|
c: Integer;
|
|
begin
|
|
if ALine < 0 then exit(-1);
|
|
c := TextBuffer.Count;
|
|
if c = 0 then
|
|
Result := -1
|
|
else
|
|
Result := (ALine - 1) * Height div c;
|
|
end;
|
|
|
|
procedure TSynGutterLineOverviewProvider.ReCalc;
|
|
begin
|
|
// nothing
|
|
end;
|
|
|
|
function TSynGutterLineOverviewProvider.PixLineHeight: Integer;
|
|
begin
|
|
Result := 1;
|
|
end;
|
|
|
|
procedure TSynGutterLineOverviewProvider.Paint(Canvas: TCanvas; AClip: TRect;
|
|
TopOffset: integer);
|
|
begin
|
|
// nothing
|
|
end;
|
|
|
|
{ TSynGutterLineOverviewProviderList }
|
|
|
|
function TSynGutterLineOverviewProviderList.GetGutterPart: TSynGutterLineOverview;
|
|
begin
|
|
Result := TSynGutterLineOverview(inherited Owner);
|
|
end;
|
|
|
|
function TSynGutterLineOverviewProviderList.GetProviders(AIndex: Integer): TSynGutterLineOverviewProvider;
|
|
begin
|
|
Result := TSynGutterLineOverviewProvider(BaseItems[AIndex]);
|
|
end;
|
|
|
|
constructor TSynGutterLineOverviewProviderList.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
Sorted := True;
|
|
end;
|
|
|
|
{ TSynGutterLOvProviderCurrentPage }
|
|
|
|
procedure TSynGutterLOvProviderCurrentPage.SynStatusChanged(Sender: TObject;
|
|
Changes: TSynStatusChanges);
|
|
begin
|
|
InvalidatePixelLines(FPixelTopLine, FPixelBottomLine);
|
|
FCurTopLine := TSynEdit(SynEdit).TopLine;
|
|
FCurLinesInWindow := TSynEdit(SynEdit).LinesInWindow;
|
|
ReCalc;
|
|
InvalidatePixelLines(FPixelTopLine, FPixelBottomLine);
|
|
end;
|
|
|
|
procedure TSynGutterLOvProviderCurrentPage.ReCalc;
|
|
begin
|
|
FPixelTopLine := TextLineToPixel(FCurTopLine);
|
|
FPixelBottomLine := TextLineToPixel(FCurTopLine + FCurLinesInWindow - 1) - 1 + PixLineHeight;
|
|
end;
|
|
|
|
procedure TSynGutterLOvProviderCurrentPage.Paint(Canvas: TCanvas; AClip: TRect;
|
|
TopOffset: integer);
|
|
begin
|
|
if (FPixelBottomLine < AClip.Top - TopOffset) or
|
|
(FPixelTopLine > AClip.Bottom - TopOffset)
|
|
then
|
|
exit;
|
|
|
|
AClip.Top := Max(AClip.Top, FPixelTopLine+TopOffset);
|
|
AClip.Bottom := Min(AClip.Bottom, FPixelBottomLine+TopOffset);
|
|
Canvas.Brush.Color := FRGBColor;
|
|
Canvas.FillRect(AClip);
|
|
end;
|
|
|
|
constructor TSynGutterLOvProviderCurrentPage.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
FColor := 0;
|
|
Color := clGray;
|
|
TSynEdit(SynEdit).RegisterStatusChangedHandler({$IFDEF FPC}@{$ENDIF}SynStatusChanged,
|
|
[scTopLine, scLinesInWindow]);
|
|
end;
|
|
|
|
destructor TSynGutterLOvProviderCurrentPage.Destroy;
|
|
begin
|
|
TSynEdit(SynEdit).UnRegisterStatusChangedHandler({$IFDEF FPC}@{$ENDIF}SynStatusChanged);
|
|
inherited;
|
|
end;
|
|
|
|
{ TSynChildWinControl }
|
|
|
|
constructor TSynChildWinControl.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
BorderStyle := bsNone;
|
|
if AOwner is TWinControl then
|
|
DoubleBuffered := TWinControl(AOwner).DoubleBuffered;
|
|
end;
|
|
|
|
{ TSynGutterLineOverview }
|
|
|
|
procedure TSynGutterLineOverview.Init;
|
|
begin
|
|
inherited Init;
|
|
TSynEditStringList(TextBuffer).AddGenericHandler(senrLineCount, TMethod({$IFDEF FPC}@{$ENDIF}LineCountChanged));
|
|
TSynEditStringList(TextBuffer).AddGenericHandler(senrTextBufferChanged, TMethod({$IFDEF FPC}@{$ENDIF}BufferChanged));
|
|
FWinControl := TSynChildWinControl.Create(Self);
|
|
FWinControl.Parent := SynEdit;
|
|
FWinControl.DoubleBuffered := SynEdit.DoubleBuffered;
|
|
FWinControl.OnPaint := {$IFDEF FPC}@{$ENDIF}PaintWinControl;
|
|
DoResize(Self);
|
|
|
|
FProviders := TSynGutterLineOverviewProviderList.Create(Self);
|
|
MarkupInfo.Background := clLtGray;
|
|
LineCountchanged(nil, 0, 0);
|
|
end;
|
|
|
|
destructor TSynGutterLineOverview.Destroy;
|
|
begin
|
|
TSynEditStringList(TextBuffer).RemoveHanlders(self);
|
|
FreeAndNil(FProviders);
|
|
FreeAndNil(FWinControl);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TSynGutterLineOverview.LineCountChanged(Sender: TSynEditStrings; AIndex,
|
|
ACount: Integer);
|
|
begin
|
|
if not SynEdit.HandleAllocated then exit;
|
|
FWinControl.Invalidate;
|
|
end;
|
|
|
|
procedure TSynGutterLineOverview.BufferChanged(Sender: TObject);
|
|
begin
|
|
TSynEditStringList(Sender).RemoveHanlders(self);
|
|
TSynEditStringList(TextBuffer).AddGenericHandler(senrLineCount, TMethod({$IFDEF FPC}@{$ENDIF}LineCountChanged));
|
|
TSynEditStringList(TextBuffer).AddGenericHandler(senrTextBufferChanged, TMethod({$IFDEF FPC}@{$ENDIF}BufferChanged));
|
|
LineCountChanged(nil, 0, 0);
|
|
end;
|
|
|
|
procedure TSynGutterLineOverview.SetVisible(const AValue: boolean);
|
|
begin
|
|
inherited SetVisible(AValue);
|
|
FWinControl.Visible := Visible;
|
|
end;
|
|
|
|
procedure TSynGutterLineOverview.DoChange(Sender: TObject);
|
|
begin
|
|
inherited;
|
|
FWinControl.Invalidate;
|
|
end;
|
|
|
|
procedure TSynGutterLineOverview.InvalidateTextLines(AFromLine, AToLine: Integer);
|
|
begin
|
|
InvalidatePixelLines(TextLineToPixel(AFromLine), TextLineToPixel(AToLine));
|
|
end;
|
|
|
|
procedure TSynGutterLineOverview.InvalidatePixelLines(AFromLine, AToLine: Integer);
|
|
var
|
|
r: TRect;
|
|
begin
|
|
if not SynEdit.HandleAllocated then exit;
|
|
r := Rect(0, Top, Width, Top + Height);
|
|
r.Top := AFromLine;
|
|
r.Bottom := AToLine;
|
|
InvalidateRect(FWinControl.Handle, @r, False);
|
|
end;
|
|
|
|
function TSynGutterLineOverview.TextLineToPixel(ALine: Integer): Integer;
|
|
var
|
|
c: Integer;
|
|
begin
|
|
if ALine < 0 then exit(-1);
|
|
c := TextBuffer.Count;
|
|
if c = 0 then
|
|
Result := -1
|
|
else
|
|
Result := (ALine - 1) * Height div c;
|
|
end;
|
|
|
|
procedure TSynGutterLineOverview.DoResize(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
inherited DoResize(Sender);
|
|
if not SynEdit.HandleAllocated then exit;
|
|
FWinControl.Top := Top;
|
|
FWinControl.Left := Left;
|
|
FWinControl.Width := Width;
|
|
FWinControl.Height := Height;
|
|
FWinControl.Invalidate;
|
|
for i := 0 to FProviders.Count - 1 do
|
|
FProviders[i].Height := Height;
|
|
end;
|
|
|
|
procedure TSynGutterLineOverview.PaintWinControl(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
AClip: TRect;
|
|
begin
|
|
if not Visible then exit;
|
|
AClip := FWinControl.Canvas.ClipRect;
|
|
AClip.Left := 0;
|
|
AClip.Right := Width;
|
|
FWinControl.Canvas.Brush.Color := MarkupInfo.Background;
|
|
FWinControl.Canvas.FillRect(AClip);
|
|
|
|
for i := 0 to Providers.Count - 1 do
|
|
Providers[i].Paint(FWinControl.Canvas, AClip, 0);
|
|
end;
|
|
|
|
function TSynGutterLineOverview.PreferedWidth: Integer;
|
|
begin
|
|
Result := 10;
|
|
end;
|
|
|
|
procedure TSynGutterLineOverview.Assign(Source : TPersistent);
|
|
begin
|
|
if Assigned(Source) and (Source is TSynGutterLineOverview) then
|
|
begin
|
|
inherited;
|
|
// Todo: assign providerlist?
|
|
end;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TSynGutterLineOverview.Paint(Canvas : TCanvas; AClip : TRect; FirstLine, LastLine : integer);
|
|
begin
|
|
// do nothing
|
|
end;
|
|
|
|
end.
|
|
|