mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-01 00:43:42 +02:00
934 lines
26 KiB
ObjectPascal
934 lines
26 KiB
ObjectPascal
unit SynGutterBase;
|
|
|
|
{$I synedit.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, math,
|
|
// LCL
|
|
Graphics, Controls, Menus, LCLIntf, LCLType,
|
|
// LazUtils
|
|
LazMethodList,
|
|
// SynEdit
|
|
SynEditMarks, SynEditMiscClasses, SynTextDrawer, SynEditMouseCmds,
|
|
LazSynTextArea;
|
|
|
|
type
|
|
|
|
TGutterClickEvent = procedure(Sender: TObject; X, Y, Line: integer;
|
|
mark: TSynEditMark) of object;
|
|
|
|
TSynGutterPartBase = class;
|
|
TSynGutterPartBaseClass = class of TSynGutterPartBase;
|
|
TSynGutterPartListBase = class;
|
|
|
|
{ TSynGutterBase }
|
|
|
|
TSynGutterSide = (gsLeft, gsRight);
|
|
|
|
TSynGutterBase = class(TPersistent)
|
|
private
|
|
FGutterArea: TLazSynSurfaceWithText;
|
|
FGutterPartList: TSynGutterPartListBase;
|
|
FSide: TSynGutterSide;
|
|
FSynEdit: TSynEditBase;
|
|
FTextDrawer: TheTextDrawer;
|
|
FColor: TColor;
|
|
FLeft, FWidth, FHeight, FTop: Integer;
|
|
FVisible: boolean;
|
|
FAutoSize: boolean;
|
|
FRightOffset, FLeftOffset: integer;
|
|
FInDoChange: Boolean;
|
|
FChangeLock: Integer;
|
|
FNeedOnChange, FNeedOnResize: Boolean;
|
|
FFlags: set of (gfNeedChildBounds);
|
|
FOnResize: TNotifyEvent;
|
|
FOnChange: TNotifyEvent;
|
|
FMouseActions: TSynEditMouseInternalActions;
|
|
FOnResizeHandler: TMethodList;
|
|
FOnChangeHandler: TMethodList;
|
|
|
|
function GetMouseActions: TSynEditMouseActions;
|
|
procedure SetAutoSize(const AValue: boolean);
|
|
procedure SetColor(const Value: TColor);
|
|
procedure SetGutterParts(const AValue: TSynGutterPartListBase);
|
|
procedure SetLeftOffset(const AValue: integer);
|
|
procedure SetMouseActions(const AValue: TSynEditMouseActions);
|
|
procedure SetRightOffset(const AValue: integer);
|
|
procedure SetVisible(const AValue: boolean);
|
|
procedure SetWidth(Value: integer);
|
|
protected
|
|
procedure SetChildBounds;
|
|
procedure DoChange(Sender: TObject);
|
|
procedure DoResize(Sender: TObject);
|
|
procedure IncChangeLock;
|
|
procedure DecChangeLock;
|
|
procedure DoDefaultGutterClick(Sender: TObject; X, Y, Line: integer;
|
|
mark: TSynEditMark); virtual;
|
|
procedure RegisterNewGutterPartList(APartList: TSynGutterPartListBase);
|
|
function PartCount: integer;
|
|
function CreatePartList: TSynGutterPartListBase; virtual; abstract;
|
|
function CreateMouseActions: TSynEditMouseInternalActions; virtual;
|
|
procedure Clear;
|
|
function GetOwner: TPersistent; override;
|
|
property GutterArea: TLazSynSurfaceWithText read FGutterArea write FGutterArea;
|
|
public
|
|
constructor Create(AOwner : TSynEditBase; ASide: TSynGutterSide; ATextDrawer: TheTextDrawer);
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure RecalcBounds;
|
|
procedure ScalePPI(const AScaleFactor: Double);
|
|
procedure DoAutoSize;
|
|
function MaybeHandleMouseAction(var AnInfo: TSynEditMouseActionInfo;
|
|
HandleActionProc: TSynEditMouseActionHandler): Boolean; virtual;
|
|
procedure ResetMouseActions; virtual; // set mouse-actions according to current Options / may clear them
|
|
procedure RegisterResizeHandler(AHandler: TNotifyEvent);
|
|
procedure UnregisterResizeHandler(AHandler: TNotifyEvent);
|
|
procedure RegisterChangeHandler(AHandler: TNotifyEvent);
|
|
procedure UnregisterChangeHandler(AHandler: TNotifyEvent);
|
|
property Left: Integer read FLeft;
|
|
property Top: Integer read FTop;
|
|
property Height:Integer read FHeight;
|
|
property Width: integer read FWidth write SetWidth;
|
|
property Side:TSynGutterSide read FSide;
|
|
property AutoSize: boolean read FAutoSize write SetAutoSize default True;
|
|
property Visible: boolean read FVisible write SetVisible default True;
|
|
property LeftOffset: integer read FLeftOffset write SetLeftOffset
|
|
default 0;
|
|
property RightOffset: integer read FRightOffset write SetRightOffset
|
|
default 0;
|
|
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
|
property OnResize: TNotifyEvent read FOnResize write FOnResize;
|
|
public
|
|
property Parts: TSynGutterPartListBase read FGutterPartList write SetGutterParts;
|
|
public
|
|
// properties available for the GutterPartClasses
|
|
property SynEdit: TSynEditBase read FSynEdit;
|
|
property TextDrawer: TheTextDrawer read FTextDrawer;
|
|
property Color: TColor read FColor write SetColor default clBtnFace;
|
|
property MouseActions: TSynEditMouseActions
|
|
read GetMouseActions write SetMouseActions;
|
|
end;
|
|
|
|
{ TSynGutterPartListBase }
|
|
|
|
TSynGutterPartListBase = class(TSynObjectList)
|
|
private
|
|
FGutter: TSynGutterBase;
|
|
function GetByClass(AClass: TSynGutterPartBaseClass; Index: Integer): TSynGutterPartBase;
|
|
function GetByClassCount(AClass: TSynGutterPartBaseClass): Integer;
|
|
function GetPart(Index: Integer): TSynGutterPartBase;
|
|
function GetSynEdit: TSynEditBase;
|
|
procedure PutPart(Index: Integer; const AValue: TSynGutterPartBase);
|
|
protected
|
|
procedure RegisterItem(AnItem: TSynObjectListItem); override;
|
|
property Gutter: TSynGutterBase read FGutter;
|
|
property SynEdit:TSynEditBase read GetSynEdit;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
constructor Create(AOwner: TComponent; AGutter: TSynGutterBase);
|
|
destructor Destroy; override;
|
|
property Part[Index: Integer]: TSynGutterPartBase
|
|
read GetPart write PutPart; default;
|
|
property ByClassCount[AClass: TSynGutterPartBaseClass]: Integer
|
|
read GetByClassCount;
|
|
property ByClass[AClass: TSynGutterPartBaseClass; Index: Integer]: TSynGutterPartBase
|
|
read GetByClass;
|
|
end;
|
|
|
|
{ TSynGutterPartList
|
|
GutterPartList for the left side Gutter. Historically the left Gutter is reffered to as Gutter without prefix }
|
|
|
|
TSynGutterPartList = class(TSynGutterPartListBase);
|
|
|
|
{ TSynRightGutterPartList
|
|
GutterPartList for the right side Gutter. }
|
|
|
|
TSynRightGutterPartList = class(TSynGutterPartListBase);
|
|
|
|
{ TSynGutterPartBase }
|
|
|
|
TSynGutterPartBase = class(TSynObjectListItem)
|
|
private
|
|
FLeft, FWidth, FHeight, FTop: Integer;
|
|
FLeftOffset: integer;
|
|
FRightOffset: integer;
|
|
FAutoSize : boolean;
|
|
FVisible: Boolean;
|
|
FSynEdit: TSynEditBase;
|
|
FGutter: TSynGutterBase;
|
|
FMarkupInfo: TSynSelectedColor;
|
|
FCursor: TCursor;
|
|
FOnChange: TNotifyEvent;
|
|
FOnGutterClick: TGutterClickEvent;
|
|
FMouseActions: TSynEditMouseInternalActions;
|
|
function GetFullWidth: integer;
|
|
function GetGutterArea: TLazSynSurfaceWithText;
|
|
function GetGutterParts: TSynGutterPartListBase;
|
|
function GetMouseActions: TSynEditMouseActions;
|
|
procedure SetLeftOffset(AValue: integer);
|
|
procedure SetMarkupInfo(const AValue: TSynSelectedColor);
|
|
procedure SetMouseActions(const AValue: TSynEditMouseActions);
|
|
procedure SetRightOffset(AValue: integer);
|
|
protected
|
|
function CreateMouseActions: TSynEditMouseInternalActions; virtual;
|
|
function Scale96ToFont(const ASize: Integer): Integer;
|
|
function PreferedWidth: Integer; virtual; // at PPI 96
|
|
function PreferedWidthAtCurrentPPI: Integer; virtual;
|
|
procedure SetBounds(ALeft, ATop, AHeight: Integer);
|
|
procedure DoAutoSize;
|
|
procedure SetAutoSize(const AValue : boolean); virtual;
|
|
procedure SetVisible(const AValue : boolean); virtual;
|
|
procedure GutterVisibilityChanged; virtual;
|
|
procedure SetWidth(const AValue : integer); virtual;
|
|
procedure Init; override;
|
|
procedure VisibilityOrSize(aCallDoChange: Boolean = False);
|
|
procedure DoResize(Sender: TObject); virtual;
|
|
procedure DoChange(Sender: TObject); virtual;
|
|
property GutterParts: TSynGutterPartListBase read GetGutterParts;
|
|
property Gutter: TSynGutterBase read FGutter;
|
|
property SynEdit:TSynEditBase read FSynEdit;
|
|
property GutterArea: TLazSynSurfaceWithText read GetGutterArea;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
property Left: Integer read FLeft;
|
|
property Top: Integer read FTop;
|
|
property Height:Integer read FHeight;
|
|
procedure PaintAll(Canvas: TCanvas; AClip: TRect; FirstLine, LastLine: integer); virtual;
|
|
procedure Paint(Canvas: TCanvas; AClip: TRect; FirstLine, LastLine: integer); virtual; abstract;
|
|
procedure ScalePPI(const AScaleFactor: Double); virtual;
|
|
public
|
|
// X/Y are relative to the gutter, not the gutter part
|
|
function HasCustomPopupMenu(out PopMenu: TPopupMenu): Boolean; virtual;
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
|
|
procedure MouseMove(Shift: TShiftState; X, Y: Integer); virtual;
|
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
|
|
function MaybeHandleMouseAction(var AnInfo: TSynEditMouseActionInfo;
|
|
HandleActionProc: TSynEditMouseActionHandler): Boolean; virtual;
|
|
function DoHandleMouseAction(AnAction: TSynEditMouseAction;
|
|
var AnInfo: TSynEditMouseActionInfo): Boolean; virtual;
|
|
procedure ResetMouseActions; virtual; // set mouse-actions according to current Options / may clear them
|
|
procedure DoOnGutterClick(X, Y: integer); virtual;
|
|
property OnGutterClick: TGutterClickEvent
|
|
read FOnGutterClick write FOnGutterClick;
|
|
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
|
property Cursor: TCursor read FCursor write FCursor default crDefault;
|
|
property MarkupInfo: TSynSelectedColor read FMarkupInfo write SetMarkupInfo;
|
|
published
|
|
property AutoSize: boolean read FAutoSize write SetAutoSize default True;
|
|
property Width: integer read FWidth write SetWidth default 10;
|
|
property FullWidth: integer read GetFullWidth; // includes Offsets
|
|
property LeftOffset: integer read FLeftOffset write SetLeftOffset default 0;
|
|
property RightOffset: integer read FRightOffset write SetRightOffset default 0;
|
|
property Visible: boolean read FVisible write SetVisible default True;
|
|
property MouseActions: TSynEditMouseActions
|
|
read GetMouseActions write SetMouseActions;
|
|
end;
|
|
|
|
|
|
const
|
|
ScrollBarWidth=0;
|
|
|
|
implementation
|
|
|
|
{ TSynGutterBase }
|
|
|
|
constructor TSynGutterBase.Create(AOwner: TSynEditBase; ASide: TSynGutterSide;
|
|
ATextDrawer: TheTextDrawer);
|
|
begin
|
|
FOnResizeHandler := TMethodList.Create;
|
|
FOnChangeHandler := TMethodList.Create;
|
|
|
|
inherited Create;
|
|
FSide := ASide;
|
|
FSynEdit := AOwner;
|
|
CreatePartList;
|
|
FMouseActions := CreateMouseActions;
|
|
|
|
|
|
FInDoChange := False;
|
|
FChangeLock := 0;
|
|
FTextDrawer := ATextDrawer;
|
|
FWidth := -1;
|
|
FLeftOffset := 0;
|
|
FRightOffset := 0;
|
|
FColor := clBtnFace;
|
|
FVisible := True;
|
|
AutoSize := True;
|
|
end;
|
|
|
|
destructor TSynGutterBase.Destroy;
|
|
begin
|
|
FOnChange := nil;
|
|
FOnResize := nil;
|
|
FreeAndNil(FGutterPartList);
|
|
FreeAndNil(FMouseActions);
|
|
FreeAndNil(FOnChangeHandler);
|
|
FreeAndNil(FOnResizeHandler);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TSynGutterBase.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TSynGutterBase then
|
|
begin
|
|
IncChangeLock;
|
|
try
|
|
FGutterPartList.Assign(TSynGutterBase(Source).FGutterPartList);
|
|
Color := TSynGutterBase(Source).FColor;
|
|
Visible := TSynGutterBase(Source).FVisible;
|
|
AutoSize := TSynGutterBase(Source).FAutoSize;
|
|
Width := TSynGutterBase(Source).FWidth;
|
|
LeftOffset := TSynGutterBase(Source).FLeftOffset;
|
|
RightOffset := TSynGutterBase(Source).FRightOffset;
|
|
finally
|
|
DecChangeLock;
|
|
end;
|
|
end else
|
|
inherited;
|
|
end;
|
|
|
|
procedure TSynGutterBase.RecalcBounds;
|
|
var
|
|
NewTop, NewLeft, NewHeight: Integer;
|
|
begin
|
|
// gutters act as alLeft or alRight, so Width is not computed here
|
|
NewTop := 0;
|
|
case FSide of
|
|
gsLeft:
|
|
begin
|
|
NewLeft := 0;
|
|
NewHeight := SynEdit.ClientHeight;
|
|
end;
|
|
gsRight:
|
|
begin
|
|
NewLeft := SynEdit.ClientWidth - Width - ScrollBarWidth;
|
|
NewHeight := SynEdit.ClientHeight;
|
|
end;
|
|
end;
|
|
if (NewLeft = FLeft) and (NewTop = FTop) and (NewHeight = FHeight) then
|
|
exit;
|
|
FLeft := NewLeft;
|
|
FTop := NewTop;
|
|
FHeight := NewHeight;
|
|
|
|
//Resize parts
|
|
IncChangeLock;
|
|
try
|
|
SetChildBounds;
|
|
DoResize(Self);
|
|
finally
|
|
DecChangeLock;
|
|
end;
|
|
end;
|
|
|
|
function TSynGutterBase.MaybeHandleMouseAction(var AnInfo: TSynEditMouseActionInfo;
|
|
HandleActionProc: TSynEditMouseActionHandler): Boolean;
|
|
begin
|
|
Result := HandleActionProc(FMouseActions.GetActionsForOptions(SynEdit.MouseOptions), AnInfo);
|
|
end;
|
|
|
|
procedure TSynGutterBase.ResetMouseActions;
|
|
begin
|
|
FMouseActions.Options := SynEdit.MouseOptions;
|
|
FMouseActions.ResetUserActions;
|
|
end;
|
|
|
|
procedure TSynGutterBase.ScalePPI(const AScaleFactor: Double);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to PartCount-1 do
|
|
Parts[I].ScalePPI(AScaleFactor);
|
|
end;
|
|
|
|
procedure TSynGutterBase.RegisterResizeHandler(AHandler: TNotifyEvent);
|
|
begin
|
|
FOnResizeHandler.Add(TMethod(AHandler));
|
|
end;
|
|
|
|
procedure TSynGutterBase.UnregisterResizeHandler(AHandler: TNotifyEvent);
|
|
begin
|
|
FOnResizeHandler.Remove(TMethod(AHandler));
|
|
end;
|
|
|
|
procedure TSynGutterBase.RegisterChangeHandler(AHandler: TNotifyEvent);
|
|
begin
|
|
FOnChangeHandler.Add(TMethod(AHandler));
|
|
end;
|
|
|
|
procedure TSynGutterBase.UnregisterChangeHandler(AHandler: TNotifyEvent);
|
|
begin
|
|
FOnChangeHandler.Remove(TMethod(AHandler));
|
|
end;
|
|
|
|
procedure TSynGutterBase.SetColor(const Value: TColor);
|
|
begin
|
|
if FColor <> Value then
|
|
begin
|
|
FColor := Value;
|
|
DoChange(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TSynGutterBase.SetAutoSize(const AValue: boolean);
|
|
begin
|
|
if FAutoSize = AValue then exit;
|
|
FAutoSize := AValue;
|
|
if FAutoSize then
|
|
DoAutoSize;
|
|
end;
|
|
|
|
function TSynGutterBase.GetMouseActions: TSynEditMouseActions;
|
|
begin
|
|
Result := FMouseActions.UserActions;
|
|
end;
|
|
|
|
procedure TSynGutterBase.SetGutterParts(const AValue: TSynGutterPartListBase);
|
|
begin
|
|
FGutterPartList.Assign(AValue);
|
|
end;
|
|
|
|
procedure TSynGutterBase.SetLeftOffset(const AValue: integer);
|
|
begin
|
|
if FLeftOffset <> AValue then
|
|
begin
|
|
FLeftOffset := Max(0, AValue);
|
|
DoChange(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TSynGutterBase.SetMouseActions(const AValue: TSynEditMouseActions);
|
|
begin
|
|
FMouseActions.UserActions := AValue;
|
|
end;
|
|
|
|
procedure TSynGutterBase.SetRightOffset(const AValue: integer);
|
|
begin
|
|
if FRightOffset <> AValue then
|
|
begin
|
|
FRightOffset := Max(0, AValue);
|
|
DoChange(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TSynGutterBase.SetVisible(const AValue: boolean);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FVisible <> AValue then
|
|
begin
|
|
FVisible := AValue;
|
|
DoResize(Self);
|
|
DoChange(Self);
|
|
for i := 0 to PartCount - 1 do
|
|
Parts[i].GutterVisibilityChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynGutterBase.SetWidth(Value: integer);
|
|
begin
|
|
Value := Max(0, Value);
|
|
if (FWidth=Value) or (FAutoSize) then exit;
|
|
FWidth := Value;
|
|
DoResize(Self);
|
|
end;
|
|
|
|
procedure TSynGutterBase.DoAutoSize;
|
|
var
|
|
NewWidth, i: Integer;
|
|
begin
|
|
NewWidth := FLeftOffset + FRightOffset;
|
|
for i := PartCount-1 downto 0 do
|
|
if Parts[i].Visible then
|
|
begin
|
|
if Parts[i].AutoSize then
|
|
Parts[i].DoAutoSize;
|
|
NewWidth := NewWidth + Parts[i].FullWidth;
|
|
end;
|
|
|
|
if FWidth = NewWidth then begin
|
|
SetChildBounds;
|
|
exit;
|
|
end;
|
|
|
|
IncChangeLock;
|
|
try
|
|
FWidth := NewWidth;
|
|
Include(FFlags, gfNeedChildBounds);
|
|
|
|
RecalcBounds;
|
|
|
|
if gfNeedChildBounds in FFlags then
|
|
SetChildBounds;
|
|
|
|
DoResize(Self);
|
|
finally
|
|
DecChangeLock;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynGutterBase.SetChildBounds;
|
|
var
|
|
i, NewLeft: Integer;
|
|
begin
|
|
NewLeft := Left + LeftOffset;
|
|
for i := 0 to PartCount - 1 do
|
|
if Parts[i].Visible then begin
|
|
Parts[i].SetBounds(NewLeft, Top, Height);
|
|
NewLeft := NewLeft + Parts[i].FullWidth;
|
|
end;
|
|
Exclude(FFlags, gfNeedChildBounds);
|
|
end;
|
|
|
|
function TSynGutterBase.PartCount: integer;
|
|
begin
|
|
if FGutterPartList <> nil then
|
|
result := FGutterPartList.Count
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TSynGutterBase.CreateMouseActions: TSynEditMouseInternalActions;
|
|
begin
|
|
Result := TSynEditMouseInternalActions.Create(Self);
|
|
end;
|
|
|
|
procedure TSynGutterBase.DoChange(Sender: TObject);
|
|
begin
|
|
if FInDoChange then exit;
|
|
if FChangeLock > 0 then begin;
|
|
FNeedOnChange := True;
|
|
exit;
|
|
end;
|
|
FNeedOnChange := False;
|
|
If FAutoSize then begin
|
|
FInDoChange := True;
|
|
try
|
|
DoAutoSize;
|
|
finally
|
|
FInDoChange := False;
|
|
end;
|
|
end;
|
|
FOnChangeHandler.CallNotifyEvents(Self);
|
|
if Assigned(FOnChange) then
|
|
FOnChange(Self);
|
|
end;
|
|
|
|
procedure TSynGutterBase.DoResize(Sender: TObject);
|
|
begin
|
|
if FChangeLock > 0 then begin;
|
|
FNeedOnResize := True;
|
|
exit;
|
|
end;
|
|
FNeedOnResize := False;
|
|
FOnResizeHandler.CallNotifyEvents(Self);
|
|
if Assigned(FOnResize) then
|
|
FOnResize(Self)
|
|
else
|
|
DoChange(Self);
|
|
end;
|
|
|
|
procedure TSynGutterBase.IncChangeLock;
|
|
begin
|
|
inc(FChangeLock);
|
|
end;
|
|
|
|
procedure TSynGutterBase.DecChangeLock;
|
|
begin
|
|
dec(FChangeLock);
|
|
if FChangeLock = 0 then begin
|
|
if FNeedOnResize then
|
|
DoResize(Self);
|
|
if FNeedOnChange then
|
|
DoChange(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TSynGutterBase.DoDefaultGutterClick(Sender: TObject; X, Y, Line: integer; mark: TSynEditMark);
|
|
begin
|
|
end;
|
|
|
|
procedure TSynGutterBase.RegisterNewGutterPartList(APartList: TSynGutterPartListBase);
|
|
begin
|
|
if (APartList = nil) or (APartList = FGutterPartList) then
|
|
exit;
|
|
if FGutterPartList <> nil then
|
|
FreeAndNil(FGutterPartList);
|
|
FGutterPartList := APartList;
|
|
FGutterPartList.OnChange := @DoChange;
|
|
end;
|
|
|
|
procedure TSynGutterBase.Clear;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FGutterPartList = nil then exit;
|
|
for i := FGutterPartList.Count - 1 downto 0 do
|
|
FGutterPartList[i].Free;
|
|
FGutterPartList.Clear;
|
|
end;
|
|
|
|
function TSynGutterBase.GetOwner: TPersistent;
|
|
begin
|
|
Result := FSynEdit;
|
|
end;
|
|
|
|
{ TSynGutterPartBase }
|
|
|
|
function TSynGutterPartBase.GetGutterParts: TSynGutterPartListBase;
|
|
begin
|
|
Result := TSynGutterPartListBase(Owner);
|
|
end;
|
|
|
|
function TSynGutterPartBase.GetMouseActions: TSynEditMouseActions;
|
|
begin
|
|
Result := FMouseActions.UserActions;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.SetLeftOffset(AValue: integer);
|
|
begin
|
|
if FLeftOffset = AValue then Exit;
|
|
FLeftOffset := AValue;
|
|
VisibilityOrSize;
|
|
end;
|
|
|
|
function TSynGutterPartBase.GetGutterArea: TLazSynSurfaceWithText;
|
|
begin
|
|
Result := Gutter.GutterArea;
|
|
end;
|
|
|
|
function TSynGutterPartBase.GetFullWidth: integer;
|
|
begin
|
|
Result := FWidth + FLeftOffset + FRightOffset;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.SetMarkupInfo(const AValue: TSynSelectedColor);
|
|
begin
|
|
FMarkupInfo.Assign(AValue);
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.SetMouseActions(const AValue: TSynEditMouseActions);
|
|
begin
|
|
FMouseActions.UserActions := AValue;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.SetRightOffset(AValue: integer);
|
|
begin
|
|
if FRightOffset = AValue then Exit;
|
|
FRightOffset := AValue;
|
|
VisibilityOrSize;
|
|
end;
|
|
|
|
function TSynGutterPartBase.PreferedWidth: Integer;
|
|
begin
|
|
Result := 12;
|
|
end;
|
|
|
|
function TSynGutterPartBase.PreferedWidthAtCurrentPPI: Integer;
|
|
begin
|
|
Result := Scale96ToFont(PreferedWidth);
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.SetBounds(ALeft, ATop, AHeight: Integer);
|
|
begin
|
|
if (ALeft = FLeft) and (ATop = FTop) and (AHeight = FHeight) then
|
|
exit;
|
|
FLeft := ALeft;
|
|
FTop := ATop;
|
|
FHeight := AHeight;
|
|
DoResize(Self);
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.DoAutoSize;
|
|
var
|
|
NewWidth: Integer;
|
|
begin
|
|
NewWidth := PreferedWidthAtCurrentPPI;
|
|
if FWidth = NewWidth then exit;
|
|
FWidth := NewWidth;
|
|
VisibilityOrSize;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.SetAutoSize(const AValue : boolean);
|
|
var
|
|
OldSize: Integer;
|
|
begin
|
|
if FAutoSize=AValue then exit;
|
|
FAutoSize:=AValue;
|
|
OldSize := FWidth;
|
|
if FAutoSize then
|
|
DoAutoSize;
|
|
if FWidth = OldSize then
|
|
DoChange(Self); // Size Did not Change
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.SetVisible(const AValue : boolean);
|
|
begin
|
|
if FVisible=AValue then exit;
|
|
FVisible:=AValue;
|
|
VisibilityOrSize(True);
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.GutterVisibilityChanged;
|
|
begin
|
|
//
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.SetWidth(const AValue : integer);
|
|
begin
|
|
if (FWidth=AValue) or ((FAutoSize) and not(csLoading in ComponentState)) then exit;
|
|
FWidth:=AValue;
|
|
VisibilityOrSize;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.DoChange(Sender : TObject);
|
|
begin
|
|
if Assigned(FOnChange) then
|
|
FOnChange(Self);
|
|
end;
|
|
|
|
function TSynGutterPartBase.CreateMouseActions: TSynEditMouseInternalActions;
|
|
begin
|
|
Result := TSynEditMouseInternalActions.Create(Self);
|
|
end;
|
|
|
|
function TSynGutterPartBase.Scale96ToFont(const ASize: Integer): Integer;
|
|
begin
|
|
Result := ASize;
|
|
if SynEdit<>nil then
|
|
Result := SynEdit.Scale96ToFont(Result);
|
|
end;
|
|
|
|
constructor TSynGutterPartBase.Create(AOwner: TComponent);
|
|
begin
|
|
FMarkupInfo := TSynSelectedColor.Create;
|
|
FMarkupInfo.Background := clBtnFace;
|
|
FMarkupInfo.Foreground := clNone;
|
|
FMarkupInfo.FrameColor := clNone;
|
|
FMarkupInfo.OnChange := @DoChange;
|
|
|
|
FMouseActions := CreateMouseActions;
|
|
|
|
FVisible := True;
|
|
FAutoSize := True;
|
|
FLeftOffset := 0;
|
|
FRightOffset := 0;
|
|
Inherited Create(AOwner); // Todo: Lock the DoChange from RegisterItem, and call DoChange at the end (after/in autosize)
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.Init;
|
|
begin
|
|
inherited Init;
|
|
FGutter := GutterParts.Gutter;
|
|
FSynEdit := GutterParts.SynEdit;
|
|
FriendEdit := FSynEdit;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.VisibilityOrSize(aCallDoChange: Boolean);
|
|
begin
|
|
if (csLoading in ComponentState) then exit;
|
|
Gutter.IncChangeLock;
|
|
try
|
|
if Gutter.AutoSize then
|
|
Gutter.DoAutoSize; // Calculate new total width of gutter
|
|
DoResize(Self);
|
|
if aCallDoChange then
|
|
DoChange(Self);
|
|
finally
|
|
Gutter.DecChangeLock;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.DoResize(Sender: TObject);
|
|
begin
|
|
DoChange(Sender);
|
|
end;
|
|
|
|
destructor TSynGutterPartBase.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
FreeAndNil(FMouseActions);
|
|
FreeAndNil(FMarkupInfo);
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.Assign(Source : TPersistent);
|
|
var
|
|
Src: TSynGutterPartBase;
|
|
begin
|
|
if Source is TSynGutterPartBase then
|
|
begin
|
|
Src := TSynGutterPartBase(Source);
|
|
FVisible := Src.FVisible;
|
|
FWidth := Src.FWidth;
|
|
FAutoSize := Src.FAutoSize;
|
|
MarkupInfo.Assign(Src.MarkupInfo);
|
|
DoChange(Self);
|
|
// Todo, maybe on Resize?
|
|
end else
|
|
inherited;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.PaintAll(Canvas: TCanvas; AClip: TRect; FirstLine,
|
|
LastLine: integer);
|
|
var
|
|
OffsRect: TRect;
|
|
begin
|
|
if not Visible then exit;
|
|
|
|
if MarkupInfo.Background = clNone then
|
|
begin
|
|
Paint(Canvas, AClip, FirstLine, LastLine);
|
|
exit;
|
|
end;
|
|
|
|
if FLeftOffset > 0 then begin
|
|
OffsRect := AClip;
|
|
OffsRect.Left := FLeft;
|
|
OffsRect.Right := FLeft + FLeftOffset;
|
|
|
|
Canvas.Brush.Color := MarkupInfo.Background;
|
|
LCLIntf.SetBkColor(Canvas.Handle, TColorRef(Canvas.Brush.Color));
|
|
Canvas.FillRect(OffsRect);
|
|
end;
|
|
|
|
if FRightOffset > 0 then begin
|
|
OffsRect := AClip;
|
|
OffsRect.Right := FLeft + FullWidth;
|
|
OffsRect.Left := OffsRect.Right - FRightOffset;
|
|
|
|
Canvas.Brush.Color := MarkupInfo.Background;
|
|
LCLIntf.SetBkColor(Canvas.Handle, TColorRef(Canvas.Brush.Color));
|
|
Canvas.FillRect(OffsRect);
|
|
end;
|
|
|
|
AClip.Left := AClip.Left + FLeftOffset;
|
|
AClip.Right := AClip.Right - FRightOffset;
|
|
Paint(Canvas, AClip, FirstLine, LastLine);
|
|
end;
|
|
|
|
function TSynGutterPartBase.HasCustomPopupMenu(out PopMenu: TPopupMenu): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
|
|
Y: Integer);
|
|
begin
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
end;
|
|
|
|
function TSynGutterPartBase.MaybeHandleMouseAction(var AnInfo: TSynEditMouseActionInfo;
|
|
HandleActionProc: TSynEditMouseActionHandler): Boolean;
|
|
begin
|
|
Result := HandleActionProc(FMouseActions.GetActionsForOptions(SynEdit.MouseOptions), AnInfo);
|
|
end;
|
|
|
|
function TSynGutterPartBase.DoHandleMouseAction(AnAction: TSynEditMouseAction;
|
|
var AnInfo: TSynEditMouseActionInfo): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.ResetMouseActions;
|
|
begin
|
|
FMouseActions.Options := SynEdit.MouseOptions;
|
|
FMouseActions.ResetUserActions;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.ScalePPI(const AScaleFactor: Double);
|
|
begin
|
|
if not FAutoSize then
|
|
Width := Round(Width*AScaleFactor)
|
|
else
|
|
DoAutoSize;
|
|
end;
|
|
|
|
procedure TSynGutterPartBase.DoOnGutterClick(X, Y : integer);
|
|
begin
|
|
if Assigned(FOnGutterClick) then
|
|
FOnGutterClick(Self, X, Y, 0, nil);
|
|
end;
|
|
|
|
{ TSynGutterPartListBase }
|
|
|
|
constructor TSynGutterPartListBase.Create(AOwner: TComponent);
|
|
begin
|
|
Inherited Create(AOwner);
|
|
include(FComponentStyle, csTransient);
|
|
if (FGutter = nil) and (SynEdit.FindGutterFromGutterPartList(Self) <> nil) then
|
|
FGutter := SynEdit.FindGutterFromGutterPartList(Self) as TSynGutterBase;
|
|
Gutter.RegisterNewGutterPartList(self);
|
|
end;
|
|
|
|
constructor TSynGutterPartListBase.Create(AOwner: TComponent; AGutter: TSynGutterBase);
|
|
begin
|
|
FGutter := AGutter;
|
|
Create(AOwner);
|
|
end;
|
|
|
|
destructor TSynGutterPartListBase.Destroy;
|
|
begin
|
|
FGutter.FGutterPartList := nil;
|
|
OnChange := nil;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TSynGutterPartListBase.RegisterItem(AnItem: TSynObjectListItem);
|
|
begin
|
|
TSynGutterPartBase(AnItem).OnChange := @DoChange;
|
|
TSynGutterPartBase(AnItem).OnGutterClick := @Gutter.DoDefaultGutterClick;
|
|
inherited RegisterItem(AnItem);
|
|
end;
|
|
|
|
function TSynGutterPartListBase.GetSynEdit: TSynEditBase;
|
|
begin
|
|
Result := TSynEditBase(Owner);
|
|
end;
|
|
|
|
function TSynGutterPartListBase.GetPart(Index: Integer): TSynGutterPartBase;
|
|
begin
|
|
Result := TSynGutterPartBase(BaseItems[Index]);
|
|
end;
|
|
|
|
procedure TSynGutterPartListBase.PutPart(Index: Integer; const AValue: TSynGutterPartBase);
|
|
begin
|
|
BaseItems[Index] := TSynObjectListItem(AValue);
|
|
end;
|
|
|
|
function TSynGutterPartListBase.GetByClass(AClass: TSynGutterPartBaseClass; Index: Integer): TSynGutterPartBase;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to Count -1 do
|
|
if Part[i] is AClass then begin
|
|
if Index = 0 then
|
|
exit(Part[i]);
|
|
dec(Index);
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TSynGutterPartListBase.GetByClassCount(AClass: TSynGutterPartBaseClass): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := 0;
|
|
for i := 0 to Count -1 do
|
|
if Part[i] is AClass then
|
|
inc(Result);
|
|
end;
|
|
|
|
end.
|
|
|