📄 synedit.pas
字号:
SynEditStrConst;
{$ENDIF}
{$IFDEF SYN_CLX}
const
FrameWidth = 2; { the border width when BoderStyle = bsSingle (until we support TWidgetStyle...) }
{$ENDIF}
function TrimTrailingSpaces(const S: string): string;
var
I: Integer;
begin
I := Length(S);
while (I > 0) and (S[I] in [#32, #9]) do
Dec(I);
Result := Copy(S, 1, I);
end;
{ THookedCommandHandlerEntry }
type
THookedCommandHandlerEntry = class(TObject)
private
fEvent: THookedCommandEvent;
fData: pointer;
constructor Create(AEvent: THookedCommandEvent; AData: pointer);
function Equals(AEvent: THookedCommandEvent): boolean;
end;
constructor THookedCommandHandlerEntry.Create(AEvent: THookedCommandEvent;
AData: pointer);
begin
inherited Create;
fEvent := AEvent;
fData := AData;
end;
function THookedCommandHandlerEntry.Equals(AEvent: THookedCommandEvent): boolean;
begin
with TMethod(fEvent) do
Result := (Code = TMethod(AEvent).Code) and (Data = TMethod(AEvent).Data);
end;
{ TCustomSynEdit }
function TCustomSynEdit.PixelsToNearestRowColumn(aX, aY: integer): TDisplayCoord;
// Result is in display coordinates
var
f: Single;
begin
{$IFDEF SYN_CLX}
with ClientRect.TopLeft do
begin
Dec( aX, X );
Dec( aY, Y );
end;
{$ENDIF}
f := (aX - fGutterWidth - 2) / fCharWidth;
// don't return a partially visible last line
if aY >= fLinesInWindow * fTextHeight then
begin
aY := fLinesInWindow * fTextHeight - 1;
if aY < 0 then
aY := 0;
end;
Result.Column := Max( 1, LeftChar + Round(f) );
Result.Row := Max( 1, TopLine + (aY div fTextHeight) );
end;
function TCustomSynEdit.PixelsToRowColumn(aX, aY: integer): TDisplayCoord;
begin
{$IFDEF SYN_CLX}
with ClientRect.TopLeft do
begin
Dec( aX, X );
Dec( aY, Y );
end;
{$ENDIF}
Result.Column := Max( 1, LeftChar + ( (aX - fGutterWidth - 2) div fCharWidth ) );
Result.Row := Max( 1, TopLine + (aY div fTextHeight) );
end;
function TCustomSynEdit.RowColumnToPixels(const RowCol: TDisplayCoord): TPoint;
begin
Result.X := (RowCol.Column-1) * fCharWidth + fTextOffset;
Result.Y := (RowCol.Row - fTopLine) * fTextHeight;
{$IFDEF SYN_CLX}
with ClientRect.TopLeft do
begin
Inc( Result.X, X );
Inc( Result.Y, Y );
end;
{$ENDIF}
end;
procedure TCustomSynEdit.ComputeCaret(X, Y: Integer);
//X,Y are pixel coordinates
var
vCaretNearestPos : TDisplayCoord;
begin
vCaretNearestPos := PixelsToNearestRowColumn(X, Y);
vCaretNearestPos.Row := MinMax(vCaretNearestPos.Row, 1, DisplayLineCount);
SetInternalDisplayXY(vCaretNearestPos);
end;
procedure TCustomSynEdit.ComputeScroll(X, Y: Integer);
//X,Y are pixel coordinates
var
iScrollBounds: TRect; { relative to the client area }
begin
{ don't scroll if dragging text from other control }
if (not MouseCapture) and (not Dragging) then
begin
fScrollTimer.Enabled := False;
Exit;
end;
iScrollBounds := Bounds(fGutterWidth, 0, fCharsInWindow * fCharWidth,
fLinesInWindow * fTextHeight);
if BorderStyle = bsNone then
InflateRect( iScrollBounds, -2, -2 );
if X < iScrollBounds.Left then
fScrollDeltaX := (X - iScrollBounds.Left) div fCharWidth - 1
else if X >= iScrollBounds.Right then
fScrollDeltaX := (X - iScrollBounds.Right) div fCharWidth + 1
else
fScrollDeltaX := 0;
if Y < iScrollBounds.Top then
fScrollDeltaY := (Y - iScrollBounds.Top) div fTextHeight - 1
else if Y >= iScrollBounds.Bottom then
fScrollDeltaY := (Y - iScrollBounds.Bottom) div fTextHeight + 1
else
fScrollDeltaY := 0;
fScrollTimer.Enabled := (fScrollDeltaX <> 0) or (fScrollDeltaY <> 0);
end;
procedure TCustomSynEdit.DoCopyToClipboard(const SText: string);
{$IFDEF SYN_CLX}
begin
Clipboard.AsText := SText;
end;
{$ELSE}
var
Mem: HGLOBAL;
P: PChar;
SLen: integer;
Failed: boolean;
begin
if SText <> '' then begin
Failed := TRUE; // assume the worst.
SLen := Length(SText);
// Open and Close are the only TClipboard methods we use because TClipboard
// is very hard (impossible) to work with if you want to put more than one
// format on it at a time.
Clipboard.Open;
try
// Clear anything already on the clipboard.
EmptyClipboard;
// Put it on the clipboard as normal text format so it can be pasted into
// things like notepad or Delphi.
Mem := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, SLen + 1);
if Mem <> 0 then begin
P := GlobalLock(Mem);
try
if P <> nil then begin
Move(PChar(SText)^, P^, SLen + 1);
// Put it on the clipboard in text format
Failed := SetClipboardData(CF_TEXT, Mem) = 0;
end;
finally
GlobalUnlock(Mem);
end;
end;
// Don't free Mem! It belongs to the clipboard now, and it will free it
// when it is done with it.
if not Failed then begin
// Copy it in our custom format so we know what kind of block it is.
// That effects how it is pasted in.
Mem := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, SLen +
SizeOf(TSynSelectionMode) + 1);
P := GlobalLock(Mem);
try
if P <> nil then begin
// Our format: TSynSelectionMode value followed by text.
PSynSelectionMode(P)^ := fActiveSelectionMode;
inc(P, SizeOf(TSynSelectionMode));
Move(PChar(SText)^, P^, SLen + 1);
Failed := SetClipboardData(SynEditClipboardFormat, Mem) = 0;
end;
finally
GlobalUnlock(Mem);
end;
// Don't free Mem! It belongs to the clipboard now, and it will free it
// when it is done with it.
end;
finally
Clipboard.Close;
if Failed then
raise ESynEditError.Create('Clipboard copy operation failed');
end;
end;
end;
{$ENDIF}
procedure TCustomSynEdit.CopyToClipboard;
var
SText: string;
ChangeTrim: boolean;
begin
if SelAvail then
begin
ChangeTrim := (fActiveSelectionMode = smColumn) and (eoTrimTrailingSpaces in Options);
try
if ChangeTrim then
Exclude( fOptions, eoTrimTrailingSpaces );
SText := SelText;
finally
if ChangeTrim then
Include( fOptions, eoTrimTrailingSpaces );
end;
DoCopyToClipboard(SText);
end;
end;
procedure TCustomSynEdit.CutToClipboard;
begin
if not ReadOnly and SelAvail then
begin
BeginUndoBlock;
try
DoCopyToClipboard(SelText);
SelText := '';
finally
EndUndoBlock;
end;
end;
end;
constructor TCustomSynEdit.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fLines := TSynEditStringList.Create;
fOrigLines := fLines;
with TSynEditStringList(fLines) do
begin
OnChange := LinesChanged;
OnChanging := LinesChanging;
OnCleared := ListCleared;
OnDeleted := ListDeleted;
OnInserted := ListInserted;
OnPutted := ListPutted;
end;
fFontDummy := TFont.Create;
fUndoList := TSynEditUndoList.Create;
fUndoList.OnAddedUndo := UndoRedoAdded;
fOrigUndoList := fUndoList;
fRedoList := TSynEditUndoList.Create;
fRedoList.OnAddedUndo := UndoRedoAdded;
fOrigRedoList := fRedoList;
{$IFDEF SYN_COMPILER_4_UP}
{$IFDEF SYN_CLX}
{$ELSE}
DoubleBuffered := false;
{$ENDIF}
{$ENDIF}
fActiveLineColor := clNone;
fSelectedColor := TSynSelectedColor.Create;
fSelectedColor.OnChange := SelectedColorsChanged;
fBookMarkOpt := TSynBookMarkOpt.Create(Self);
fBookMarkOpt.OnChange := BookMarkOptionsChanged;
// fRightEdge has to be set before FontChanged is called for the first time
fRightEdge := 80;
fGutter := TSynGutter.Create;
fGutter.OnChange := GutterChanged;
fGutterWidth := fGutter.Width;
fWordWrapGlyph := TSynGlyph.Create(HINSTANCE, 'SynEditWrapped', clLime);
fWordWrapGlyph.OnChange := WordWrapGlyphChange;
fTextOffset := fGutterWidth + 2;
{$IFDEF SYN_COMPILER_7_UP}
{$IFNDEF SYN_CLX}
ControlStyle := ControlStyle + [csOpaque, csSetCaption, csNeedsBorderPaint];
{$ELSE}
ControlStyle := ControlStyle + [csOpaque, csSetCaption];
{$ENDIF}
{$ELSE}
ControlStyle := ControlStyle + [csOpaque, csSetCaption];
{$ENDIF}
Height := 150;
Width := 200;
Cursor := crIBeam;
Color := clWindow;
{$IFDEF SYN_WIN32}
fFontDummy.Name := 'Courier New';
fFontDummy.Size := 10;
{$ENDIF}
{$IFDEF SYN_KYLIX}
fFontDummy.Name := 'adobe-courier';
if fFontDummy.Name = 'adobe-courier' then
fFontDummy.Size := 12
else begin
fFontDummy.Name := 'terminal';
fFontDummy.Size := 14;
end;
{$ENDIF}
{$IFDEF SYN_COMPILER_3_UP}
fFontDummy.CharSet := DEFAULT_CHARSET;
{$ENDIF}
fTextDrawer := TheTextDrawer.Create([fsBold], fFontDummy);
Font.Assign(fFontDummy);
Font.OnChange := SynFontChanged;
ParentFont := False;
ParentColor := False;
TabStop := True;
fInserting := True;
fMaxScrollWidth := 1024;
fScrollBars := ssBoth;
fBorderStyle := bsSingle;
fInsertCaret := ctVerticalLine;
fOverwriteCaret := ctBlock;
FSelectionMode := smNormal;
fActiveSelectionMode := smNormal;
fFocusList := TList.Create;
fKbdHandler := TSynEditKbdHandler.Create;
fKeystrokes := TSynEditKeyStrokes.Create(Self);
fMarkList := TSynEditMarkList.Create(self);
fMarkList.OnChange := MarkListChange;
SetDefaultKeystrokes;
fRightEdgeColor := clSilver;
{$IFDEF SYN_MBCSSUPPORT}
fImeCount := 0;
fMBCSStepAside := False;
{$ENDIF}
fWantReturns := True;
fWantTabs := False;
fTabWidth := 8;
fLeftChar := 1;
fTopLine := 1;
fCaretX := 1;
fLastCaretX := 1;
fCaretY := 1;
fBlockBegin.Char := 1;
fBlockBegin.Line := 1;
fBlockEnd := fBlockBegin;
fOptions := SYNEDIT_DEFAULT_OPTIONS;
fScrollTimer := TTimer.Create(Self);
fScrollTimer.Enabled := False;
fScrollTimer.Interval := 100;
fScrollTimer.OnTimer := ScrollTimerHandler;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -