4434 lines
130 KiB
ObjectPascal

{
Copyright (C) Alexey Torgashin, uvviewsoft.com
License: MPL 2.0 or LGPL
}
{$mode objfpc}{$H+}
//{$define test_markedrange}
//{$define test_attribs}
//{$define beep_wrapinfo}
//{$define debug_findwrapindex}
//{$define beep_cached_update}
//{$define test_foldlist}
//{$define allow_proc_msg}
{$define fix_horzscroll} //workaround for gtk2 widgetset unstable: it freezes app
//when horz-scroll hides/shows/hides/...
//ok also for win32
unit ATSynEdit;
interface
uses
{$ifdef Windows}
windows, imm, messages,
{$endif}
Classes, SysUtils, Graphics,
Controls, ExtCtrls, Menus, Forms,
LMessages, LCLType,
ATStringProc,
ATStrings,
ATSynEdit_Colors,
ATSynEdit_Keymap,
ATSynEdit_CanvasProc,
ATSynEdit_Carets,
ATSynEdit_Markers,
ATSynEdit_Gutter,
ATSynEdit_WrapInfo,
ATSynEdit_Ranges,
ATSynEdit_Adapters;
type
TATDirection = (
cDirNone,
cDirLeft,
cDirRight,
cDirUp,
cDirDown
);
TATSelectColumnDirection = (
cDirColumnLeft,
cDirColumnRight,
cDirColumnUp,
cDirColumnDown,
cDirColumnPageUp,
cDirColumnPageDown
);
TATCaseConvert = (
cCaseLower,
cCaseUpper,
cCaseTitle,
cCaseInvert,
cCaseSentence
);
TATCommandResult = (
cResultText,
cResultCaretAny,
cResultCaretLeft,
cResultCaretTop,
cResultCaretRight,
cResultCaretBottom,
cResultKeepColumnSel,
cResultScroll,
cResultState
);
TATCommandResults = set of TATCommandResult;
TATFoldStyle = ( //affects folding of blocks without "text hint" passed from adapter
cFoldHereWithDots, //show "..." from fold-pos
cFoldHereWithTruncatedText, //show truncated line instead of "..."
cFoldFromEndOfLine, //looks like Lazarus: show "..." after line, bad with 2 blocks starting at the same line
cFoldFromNextLine //looks like SynWrite: don't show "...", show separator line
);
type
TATAutoIndentKind = (
cIndentAsIs,
cIndentSpaces,
cIndentTabsSpaces,
cIndentTabsOnly
);
TATPageUpDownSize = (
cPageSizeFull,
cPageSizeFullMinus1,
cPageSizeHalf
);
TATSynWrapMode = (
cWrapOff,
cWrapOn,
cWrapAtMargin
);
TATSynNumbersStyle = (
cNumbersAll,
cNumbersNone,
cNumbersEach10th,
cNumbersEach5th
);
TATSynPaintFlag = (
cPaintUpdateBitmap,
cPaintUpdateCaretsCoords,
cPaintUpdateScrollbars
);
TATSynPaintFlags = set of TATSynPaintFlag;
TATSynScrollInfo = record
NMin,
NMax,
NPage,
NPos,
NPosLast: integer;
end;
TATSynCaretShape = (
cCaretShapeFull,
cCaretShapeVertPixels1,
cCaretShapeVertPixels2,
cCaretShapeVertPixels3,
cCaretShapeVertPixels4,
cCaretShapeVertPercents10,
cCaretShapeVertPercents15,
cCaretShapeVertPercents20,
cCaretShapeVertPercents25,
cCaretShapeVertPercents30,
cCaretShapeVertPercents35,
cCaretShapeVertPercents40,
cCaretShapeVertPercents50,
cCaretShapeHorzPixels1,
cCaretShapeHorzPixels2,
cCaretShapeHorzPixels3,
cCaretShapeHorzPixels4,
cCaretShapeHorzPixels5,
cCaretShapeHorzPercents10,
cCaretShapeHorzPercents15,
cCaretShapeHorzPercents20,
cCaretShapeHorzPercents25,
cCaretShapeHorzPercents30,
cCaretShapeHorzPercents35,
cCaretShapeHorzPercents40,
cCaretShapeHorzPercents50,
cCaretShapeFrameFull
);
const
cInitCaretShapeIns = cCaretShapeVertPixels1;
cInitCaretShapeOvr = cCaretShapeFull;
cInitCaretShapeRO = cCaretShapeHorzPixels1;
cInitTextOffsetFromLine = {$ifdef windows} 0 {$else} 1 {$endif};
cInitSpacingText = 1;
cInitTimerBlink = 600;
cInitTimerAutoScroll = 80;
cInitTimerNiceScroll = 200;
cInitMinimapVisible = false;
cInitMicromapVisible = false;
cInitMarginRight = 80;
cInitTabSize = 8;
cInitMicromapWidth = 30;
cInitMinimapWidth = 160;
cInitNumbersStyle = cNumbersEach5th;
cInitBitmapWidth = 1000;
cInitBitmapHeight = 800;
cInitGutterPlusSize = 4;
cInitFoldStyle = cFoldHereWithTruncatedText;
cGutterBands = 6;
cGutterSizeBm = 16;
cGutterSizeNum = 10;
cGutterSizeFold = 14;
cGutterSizeState = 3;
cGutterSizeSep = 1;
cGutterSizeEmpty = 2;
const
cFoldedLenOfEmptyHint = 50;
cFoldedMarkIndentInner = 2;
cFoldedMarkIndentOuter = 0;
cScrollKeepHorz = 1; //keep char, allow handy clicking after eol of longest line
cScrollIndentCaretHorz = 10; //offsets for caret-moving: if caret goes out of control
cScrollIndentCaretVert = 0; //must be 0, >0 gives jumps on move-down
cScrollIndentGotoHorz = 10; //offsets for "goto" command: if caret goes out of control
cScrollIndentGotoVert = 3;
cSpeedScrollAutoHorz = 10; //auto-scroll (drag out of control): speed x
cSpeedScrollAutoVert = 1; //... speed y
cSpeedScrollNiceHorz = 4; //browser-scroll (middle-click): speed x
cSpeedScrollNiceVert = 1; //... speed y
cResizeBitmapStep = 200; //resize bitmap by N pixels step
cSizeGutterFoldLineDx = 3;
cSizeRulerHeight = 20;
cSizeRulerMarkSmall = 3;
cSizeRulerMarkBig = 7;
cMinFontSize = 6;
cMinTabSize = 1;
cMaxTabSize = 64;
cMinMinimapWidth = 30;
cMaxCharsForOutput = 1000; //don't paint more chars in line
cMinWrapColumn = 20; //too small width won't give smaller wrap-column
cMinWrapColumnAbs = 4; //absolute min of wrap-column (leave n chars on line anyway)
cMinMarginRt = 20;
cMinCaretTime = 300;
cMaxCaretTime = 2000;
cMinCharsAfterAnyIndent = 20; //if indent is too big, leave 20 chrs in wrapped-parts anyway
cMaxLinesForOldWrapUpdate = 100; //if less lines, force old wrapinfo update (fast)
cHintScrollPrefix: string = 'Line';
cHintScrollDx = 5;
cStrMenuItemFoldAll: string = 'Fold all';
cStrMenuItemUnfoldAll: string = 'Unfold all';
cStrMenuItemFoldLevel: string = 'Fold level';
var
cRectEmpty: TRect = (Left: 0; Top: 0; Right: 0; Bottom: 0);
cATClipboardFormatId: integer = 0; //must be inited
cATClipboardSignatureColBlock: integer = $1000;
type
TATSynEditClickEvent = procedure(Sender: TObject; var AHandled: boolean) of object;
TATSynEditClickMoveCaretEvent = procedure(Sender: TObject; APrevPnt, ANewPnt: TPoint) of object;
TATSynEditCommandEvent = procedure(Sender: TObject; ACommand: integer; const AText: string; var AHandled: boolean) of object;
TATSynEditClickGutterEvent = procedure(Sender: TObject; ABand: integer; ALineNum: integer) of object;
TATSynEditClickMicromapEvent = procedure(Sender: TObject; AX, AY: integer) of object;
TATSynEditDrawBookmarkEvent = procedure(Sender: TObject; C: TCanvas; ALineNum: integer; const ARect: TRect) of object;
TATSynEditDrawRectEvent = procedure(Sender: TObject; C: TCanvas; const ARect: TRect) of object;
TATSynEditCalcBookmarkColorEvent = procedure(Sender: TObject; ABookmarkKind: integer; out AColor: TColor) of object;
TATSynEditCalcStapleEvent = procedure(Sender: TObject; ALine, AIndent: integer; var AStapleColor: TColor) of object;
TATSynEditCalcHiliteEvent = procedure(Sender: TObject; var AParts: TATLineParts;
ALineIndex, ACharIndex, ALineLen: integer; var AColorAfterEol: TColor) of object;
type
{ TATSynEdit }
TATSynEdit = class(TCustomControl)
private
FTimerBlink: TTimer;
FTimerScroll: TTimer;
FTimerNiceScroll: TTimer;
FPaintStatic: boolean;
FPaintFlags: TATSynPaintFlags;
FPaintLocked: integer;
FBitmap: TBitmap;
FKeymap: TATKeymap;
FWantTabs: boolean;
FEditorIndex: integer;
FMarginRight: integer;
FMarginList: TList;
FStringsInt,
FStringsExternal: TATStrings;
FAdapterHilite: TATAdapterHilite;
FFold: TATSynRanges;
FFoldImageList: TImageList;
FFoldStyle: TATFoldStyle;
FCursorText,
FCursorBm: TCursor;
FTextOffset: TPoint;
FTextLocked: string;
FTextHint: string;
FTextHintFontStyle: TFontStyles;
FTextHintCenter: boolean;
FSelRect: TRect;
FSelRectBegin,
FSelRectEnd: TPoint;
FCarets: TATCarets;
FCaretBlinkEnabled: boolean;
FCaretShapeIns,
FCaretShapeOvr,
FCaretShapeRO: TATSynCaretShape;
FCaretShown: boolean;
FCaretVirtual: boolean;
FCaretSpecPos: boolean;
FCaretStopUnfocused: boolean;
FMarkers: TATMarkers;
FAttribs: TATMarkers;
FMarkedRange: TATMarkers;
FMenuStd,
FMenuText,
FMenuGutterBm,
FMenuGutterNum,
FMenuGutterFold,
FMenuGutterFoldStd,
FMenuMinimap,
FMenuMicromap,
FMenuRuler: TPopupMenu;
FOverwrite: boolean;
FHintWnd: THintWindow;
FMouseDownPnt: TPoint;
FMouseDownNumber: integer;
FMouseDownDouble: boolean;
FMouseDownRight: boolean;
FMouseNiceScrollPos: TPoint;
FMouseDragDropping: boolean;
FMouseDragMinimap: boolean;
FMouseAutoScroll: TATDirection;
FLastTextCmd: integer;
FLastTextCmdText: atString;
FCursorOnMinimap: boolean;
FCursorOnGutter: boolean;
FOnBeforeCalcHilite: TNotifyEvent;
FOnClickDbl,
FOnClickTriple,
FOnClickMiddle: TATSynEditClickEvent;
FOnClickMoveCaret: TATSynEditClickMoveCaretEvent;
FOnClickEndSelect: TATSynEditClickMoveCaretEvent;
FOnChangeCaretPos: TNotifyEvent;
FOnChange: TNotifyEvent;
FOnScroll: TNotifyEvent;
FOnClickGutter: TATSynEditClickGutterEvent;
FOnClickMicromap: TATSynEditClickMicromapEvent;
FOnDrawBookmarkIcon: TATSynEditDrawBookmarkEvent;
FOnDrawLine: TATSynEditDrawLineEvent;
FOnDrawMicromap: TATSynEditDrawRectEvent;
FOnDrawEditor: TATSynEditDrawRectEvent;
FOnDrawRuler: TATSynEditDrawRectEvent;
FOnChangeState: TNotifyEvent;
FOnCommand: TATSynEditCommandEvent;
FOnCalcHilite: TATSynEditCalcHiliteEvent;
FOnCalcStaple: TATSynEditCalcStapleEvent;
FOnCalcBookmarkColor: TATSynEditCalcBookmarkColorEvent;
FWrapInfo: TATSynWrapInfo;
//FWrapProgress: integer;
FWrapColumn: integer;
FWrapMode: TATSynWrapMode;
FWrapUpdateNeeded: boolean;
FWrapIndented: boolean;
FUnprintedVisible,
FUnprintedSpaces,
FUnprintedEnds,
FUnprintedEndsDetails,
FUnprintedReplaceSpec: boolean;
FPrevVisibleColumns: integer;
FCharSize: TPoint;
FCharSizeMinimap: TPoint;
FCharSpacingText: TPoint;
FTabSize: integer;
FGutter: TATGutter;
FGutterBandBm,
FGutterBandNum,
FGutterBandState,
FGutterBandFold,
FGutterBandSep,
FGutterBandEmpty: integer;
FColors: TATSynEditColors;
FRectMain,
FRectMinimap,
FRectMicromap,
FRectGutter,
FRectRuler: TRect;
FLineBottom: integer;
FScrollVert,
FScrollHorz: TATSynScrollInfo;
FScrollVertMinimap,
FScrollHorzMinimap: TATSynScrollInfo;
FPrevHorz,
FPrevVert: TATSynScrollInfo;
FMinimapWidth: integer;
FMinimapCharWidth: integer;
FMinimapVisible: boolean;
FMinimapShowSelBorder: boolean;
FMinimapShowSelAlways: boolean;
FMicromapWidth: integer;
FMicromapVisible: boolean;
FOptMaxLinesToCountUnindent: integer;
FOptShowStapleStyle: TATLineStyle;
FOptShowStapleIndent: integer;
FOptShowStapleWidthPercent: integer;
FOptMouseEnableNormalSelection: boolean;
FOptMouseEnableColumnSelection: boolean;
FOptMouseDownForPopup: boolean;
FOptCaretPreferLeftSide: boolean;
FOptMarkersSize: integer;
FOptShowScrollHint: boolean;
FOptTextOffsetTop: integer;
FOptTextOffsetFromLine: integer;
FOptSavingForceFinalEol: boolean;
FOptSavingTrimSpaces: boolean;
FOptUndoGrouped: boolean;
FOptIndentSize: integer;
FOptIndentKeepsAlign: boolean;
FOptRulerVisible: boolean;
FOptRulerSize: integer;
FOptRulerFontSize: integer;
FOptRulerMarkSizeSmall: integer;
FOptRulerMarkSizeBig: integer;
FOptRulerTextIndent: integer;
FOptGutterVisible: boolean;
FOptGutterPlusSize: integer;
FOptGutterShowFoldAlways: boolean;
FOptGutterShowFoldLines: boolean;
FOptGutterShowFoldLinesAll: boolean;
FOptNumbersAutosize: boolean;
FOptNumbersAlignment: TAlignment;
FOptNumbersFontSize: integer;
FOptNumbersStyle: TATSynNumbersStyle;
FOptNumbersShowFirst,
FOptNumbersShowCarets: boolean;
FOptNumbersSkippedChar: atString;
FOptNumbersIndentLeft,
FOptNumbersIndentRight: integer;
FOptWordChars: atString;
FOptAutoIndent: boolean;
FOptAutoIndentKind: TATAutoIndentKind;
FOptTabSpaces: boolean;
FOptLastLineOnTop: boolean;
FOptOverwriteSel: boolean;
FOptOverwriteAllowedOnPaste: boolean;
FOptKeyBackspaceUnindent: boolean;
FOptKeyPageKeepsRelativePos: boolean;
FOptKeyUpDownNavigateWrapped: boolean;
FOptKeyHomeEndNavigateWrapped: boolean;
FOptKeyUpDownKeepColumn: boolean;
FOptCopyLinesIfNoSel: boolean;
FOptCutLinesIfNoSel: boolean;
FOptShowFullSel: boolean;
FOptShowFullHilite: boolean;
FOptShowCurLine: boolean;
FOptShowCurLineMinimal: boolean;
FOptShowCurColumn: boolean;
FOptMouseHideCursor: boolean;
FOptMouse2ClickSelectsLine: boolean;
FOptMouse3ClickSelectsLine: boolean;
FOptMouse2ClickDragSelectsWords: boolean;
FOptMouseDragDrop: boolean;
FOptMouseRightClickMovesCaret: boolean;
FOptMouseGutterClickSelectsLine: boolean;
FOptMouseNiceScroll: boolean;
FOptKeyPageUpDownSize: TATPageUpDownSize;
FOptKeyLeftRightSwapSel: boolean;
FOptKeyLeftRightSwapSelAndSelect: boolean;
FOptKeyHomeToNonSpace: boolean;
FOptKeyEndToNonSpace: boolean;
FOptKeyTabIndents: boolean;
FOptShowIndentLines: boolean;
FOptShowGutterCaretBG: boolean;
FOptAllowScrollbarVert: boolean;
FOptAllowScrollbarHorz: boolean;
FOptAllowZooming: boolean;
FOptAllowReadOnly: boolean;
//
procedure DebugFindWrapIndex;
function DoCalcIndentCharsFromPrevLines(AX, AY: integer): integer;
procedure DoCalcPosColor(AX, AY: integer; var AColor: TColor);
procedure DoCalcLineEntireColor(ALine: integer; ACoordTop: integer;
ALineWithCaret: boolean; out AColor: TColor; out AColorForced: boolean);
procedure DoCaretsAssign(NewCarets: TATCarets);
procedure DoCaretsShift_CaretItem(Caret: TATCaretItem; APosX, APosY, AShiftX,
AShiftY, AShiftBelowX: integer);
procedure DoCaretsShift_MarkerItem(Mark: TATMarkerItem; APosX, APosY, AShiftX,
AShiftY, AShiftBelowX: integer; APosAfter: TPoint);
procedure DoDebugAddAttribs;
procedure DoDropText;
procedure DoFoldbarClick(ALine: integer);
procedure DoFoldForLevel(ALevel: integer);
procedure DoFoldForLevelAndLines(ALineFrom, ALineTo: integer; ALevel: integer;
AForThisRange: TATSynRange);
procedure DoHandleRightClick(X, Y: integer);
function DoHandleClickEvent(AEvent: TATSynEditClickEvent): boolean;
procedure DoHintShow;
procedure DoHintHide;
procedure DoMenuGutterFold_AddDynamicItems(Menu: TPopupMenu);
procedure DoMenuGutterFold;
procedure DoMenuText;
procedure DoMinimapClick(APosY: integer);
procedure DoMinimapDrag(APosY: integer);
procedure DoPaintMarkersTo(C: TCanvas);
procedure DoSelectionDeleteColumnBlock;
procedure DoSelect_NormalSelToColumnSel(out ABegin, AEnd: TPoint);
function GetColorTextBG: TColor;
function GetColorTextFont: TColor;
function GetMinimapActualHeight: integer;
function GetMinimapSelTop: integer;
function GetMinimapSelTop_PixelsToWrapIndex(APixels: integer): integer;
function GetRectMinimapSel: TRect;
procedure InitResourcesFoldbar;
function IsFoldLineNeededBeforeWrapitem(N: integer): boolean;
procedure MenuFoldFoldAllClick(Sender: TObject);
procedure MenuFoldLevelClick(Sender: TObject);
procedure MenuFoldUnfoldAllClick(Sender: TObject);
procedure MenuFoldPlusMinusClick(Sender: TObject);
procedure PaintEx(ALine: integer);
procedure DoPaintGutterFolding(C: TCanvas; AWrapItemIndex: integer; ACoordX1,
ACoordX2, ACoordY1, ACoordY2: integer);
procedure DoPaintGutterBandBG(C: TCanvas; ABand: integer; AColor: TColor; ATop,
ABottom: integer);
procedure DoPaintLockedWarning(C: TCanvas);
procedure DoPaintStaple(C: TCanvas; const R: TRect; AColor: TColor);
procedure DoPaintStaples(C: TCanvas; const ARect: TRect; ACharSize: TPoint;
const AScrollHorz: TATSynScrollInfo);
procedure DoPaintTextHintTo(C: TCanvas);
procedure DoPartCalc_ApplyOver(var AParts: TATLineParts; AOffsetMax,
ALineIndex, ACharIndex: integer);
procedure DoPartCalc_CreateNew(var AParts: TATLineParts; AOffsetMax,
ALineIndex, ACharIndex: integer; AColorBG: TColor);
procedure DoPartCalc_ApplyAttribsOver(var AParts: TATLineParts; AOffsetMax,
ALineIndex, ACharIndex: integer);
function GetAutoIndentString(APosX, APosY: integer): atString;
function GetFirstUnfoldedLineNumber: integer;
function GetFoldedMarkText(ALine: integer): string;
function GetLastUnfoldedLineNumber: integer;
function GetModified: boolean;
function GetNextUnfoldedLineNumber(ALine: integer; ADown: boolean): integer;
function GetOneLine: boolean;
function GetRedoCount: integer;
function GetLinesFromTop: integer;
function GetText: atString;
function GetUndoAfterSave: boolean;
function GetUndoCount: integer;
function GetUndoLimit: integer;
procedure DoInitPopupMenu;
function IsCaretBlocked: boolean;
function IsLineFoldedFull(ALine: integer): boolean;
function IsLinePartWithCaret(ALine: integer; ACoordY: integer): boolean;
procedure MenuClick(Sender: TObject);
procedure MenuPopup(Sender: TObject);
procedure DoCalcWrapInfos(ALine: integer; AIndentMaximal: integer; AItems: TList);
procedure DoCalcLineHilite(const AItem: TATSynWrapItem;
var AParts: TATLineParts; ACharsSkipped, ACharsMax: integer;
AColorBG: TColor; AColorForced: boolean; var AColorAfter: TColor);
//select
procedure DoSelectionDeleteOrReset;
procedure DoSelect_ExtendSelectionByLine;
procedure DoSelect_CharRange(ACaretIndex: integer; Pnt: TPoint);
procedure DoSelect_WordRange(ACaretIndex: integer; P1, P2: TPoint);
procedure DoSelect_Word_ByClick;
procedure DoSelect_Line_ByClick;
//paint
function DoPaint(AFlags: TATSynPaintFlags; ALineFrom: integer): boolean;
procedure DoPaintNiceScroll(C: TCanvas);
procedure DoPaintMarginLineTo(C: TCanvas; AX: integer; AColor: TColor);
procedure DoPaintTo(C: TCanvas; ALineFrom: integer);
procedure DoPaintRulerTo(C: TCanvas);
procedure DoPaintTextTo(C: TCanvas; const ARect: TRect;
const ACharSize: TPoint; AWithGutter, AMainText: boolean;
var AScrollHorz, AScrollVert: TATSynScrollInfo; ALineFrom: integer);
procedure DoPaintLineIndent(C: TCanvas; const ARect: TRect; ACharSize: TPoint;
ACoordY: integer; AIndentSize: integer; AColorBG: TColor;
AScrollPos: integer; AIndentLines: boolean);
procedure DoPaintMinimapSelTo(C: TCanvas);
procedure DoPaintMinimapTo(C: TCanvas);
procedure DoPaintMicromapTo(C: TCanvas);
procedure DoPaintMarginsTo(C: TCanvas);
procedure DoPaintFoldedMark(C: TCanvas; APos: TPoint; ACoord: TPoint;
const AMarkText: string);
procedure DoPaintCarets(C: TCanvas; AWithInvalidate: boolean);
procedure DoPaintModeStatic;
procedure DoPaintModeBlinking;
procedure DoPaintSelectedLineBG(C: TCanvas; ACharSize: TPoint;
const AVisRect: TRect; APointLeft: TPoint; APointText: TPoint;
ALineIndex: integer; AEolSelected: boolean;
const AScrollHorz: TATSynScrollInfo);
//carets
procedure DoCaretsExtend(ADown: boolean; ALines: integer);
function GetCaretManyAllowed: boolean;
function GetCaretSelectionIndex(P: TPoint): integer;
function GetCaretBlinkTime: integer;
function DoCaretSwapEdge(AMoveLeft: boolean): boolean;
procedure DoCaretsSort;
//events
procedure DoEventBeforeCalcHilite;
procedure DoEventClickMicromap(AX, AY: integer);
procedure DoEventClickGutter(ABandIndex, ALineNumber: integer);
function DoEventCommand(ACommand: integer; const AText: string): boolean;
procedure DoEventDrawBookmarkIcon(C: TCanvas; ALineNumber: integer; const ARect: TRect);
//
function GetCharSpacingX: integer;
function GetCharSpacingY: integer;
function GetEndOfFilePos: TPoint;
function GetMarginString: string;
function GetReadOnly: boolean;
function GetLineTop: integer;
function GetTextForClipboard: string;
function GetWrapInfoIndex(AMousePos: TPoint): integer;
function GetStrings: TATStrings;
function GetMouseNiceScroll: boolean;
procedure SetCaretShapeRO(AValue: TATSynCaretShape);
procedure SetCaretBlinkEnabled(AValue: boolean);
procedure SetMouseNiceScroll(AValue: boolean);
procedure SetCaretManyAllowed(AValue: boolean);
procedure SetCaretBlinkTime(AValue: integer);
procedure SetCaretShapeIns(AValue: TATSynCaretShape);
procedure SetCaretShapeOvr(AValue: TATSynCaretShape);
procedure SetCharSpacingX(AValue: integer);
procedure SetCharSpacingY(AValue: integer);
procedure SetMarginString(AValue: string);
procedure SetMicromapVisible(AValue: boolean);
procedure SetMinimapVisible(AValue: boolean);
procedure SetOneLine(AValue: boolean);
procedure SetReadOnly(AValue: boolean);
procedure SetLineTop(AValue: integer);
procedure SetLinesFromTop(AValue: integer);
procedure SetStrings(Obj: TATStrings);
function GetRectMain: TRect;
function GetRectMinimap: TRect;
function GetRectMicromap: TRect;
function GetRectGutter: TRect;
function GetRectRuler: TRect;
function GetTextOffset: TPoint;
function GetGutterNumbersWidth(C: TCanvas): integer;
function GetPageLines: integer;
function GetVisibleLines: integer;
function GetVisibleColumns: integer;
function GetVisibleLinesMinimap: integer;
function GetMinimapScrollPos: integer;
procedure SetTabSize(AValue: integer);
procedure SetText(AValue: atString);
procedure SetUndoAfterSave(AValue: boolean);
procedure SetUndoLimit(AValue: integer);
procedure SetWrapMode(AValue: TATSynWrapMode);
procedure SetWrapIndented(AValue: boolean);
procedure UpdateCursor;
procedure UpdateGutterAutosize(C: TCanvas);
procedure UpdateMinimapAutosize(C: TCanvas);
function DoFormatLineNumber(N: integer): atString;
function UpdateScrollInfoFromMessage(const Msg: TLMScroll;
var Info: TATSynScrollInfo): boolean;
procedure UpdateWrapInfo;
function UpdateScrollbars: boolean;
procedure UpdateScrollbarVert;
procedure UpdateScrollbarHorz;
procedure UpdateCaretsCoords(AOnlyLast: boolean = false);
function GetCharSize(C: TCanvas; ACharSpacing: TPoint): TPoint;
function GetScrollbarVisible(bVertical: boolean): boolean;
procedure SetMarginRight(AValue: integer);
procedure TimerBlinkTick(Sender: TObject);
procedure TimerScrollTick(Sender: TObject);
procedure TimerNiceScrollTick(Sender: TObject);
//carets
procedure DoCaretAddToPoint(AX, AY: integer);
procedure DoCaretsColumnToPoint(AX, AY: integer);
procedure DoCaretsShift(APosX, APosY: integer; AShiftX, AShiftY: integer;
APosAfter: TPoint; AShiftBelowX: integer = 0);
procedure DoCaretsDeleteOnSameLines;
//editing
procedure DoCommandResults(Res: TATCommandResults);
function DoCommand_FoldLevel(ALevel: integer): TATCommandResults;
function DoCommand_FoldUnfoldAll(ADoFold: boolean): TATCommandResults;
function DoCommand_TextTrimSpaces(AMode: TATTrimSpaces): TATCommandResults;
function DoCommand_TextChangeCase(AMode: TATCaseConvert): TATCommandResults;
function DoCommand_SizeChange(AIncrease: boolean): TATCommandResults;
function DoCommand_MoveSelectionUpDown(ADown: boolean): TATCommandResults;
function DoCommand_TextInsertEmptyAboveBelow(ADown: boolean): TATCommandResults;
function DoCommand_SelectColumn(ADir: TATSelectColumnDirection
): TATCommandResults;
function DoCommand_SelectColumnToLineEdge(AToEnd: boolean): TATCommandResults;
function DoCommand_TextInsertColumnBlockOnce(const AText: atString; AKeepCaret: boolean): TATCommandResults;
function DoCommand_CaretsExtend(ADown: boolean; ALines: integer): TATCommandResults;
function DoCommand_Undo: TATCommandResults;
function DoCommand_Redo: TATCommandResults;
function DoCommand_TextIndentUnindent(ARight: boolean): TATCommandResults;
function DoCommand_SelectWords: TATCommandResults;
function DoCommand_SelectLines: TATCommandResults;
function DoCommand_SelectAll: TATCommandResults;
function DoCommand_SelectInverted: TATCommandResults;
function DoCommand_SelectSplitToLines: TATCommandResults;
function DoCommand_SelectExtendByLine: TATCommandResults;
function DoCommand_Cancel: TATCommandResults;
function DoCommand_ToggleReadOnly: TATCommandResults;
function DoCommand_ToggleOverwrite: TATCommandResults;
function DoCommand_ToggleWordWrap: TATCommandResults;
function DoCommand_ToggleUnprinted: TATCommandResults;
function DoCommand_ToggleUnprintedSpaces: TATCommandResults;
function DoCommand_ToggleUnprintedEnds: TATCommandResults;
function DoCommand_ToggleUnprintedEndDetails: TATCommandResults;
function DoCommand_ToggleLineNums: TATCommandResults;
function DoCommand_ToggleFolding: TATCommandResults;
function DoCommand_ToggleRuler: TATCommandResults;
function DoCommand_ToggleMinimap: TATCommandResults;
function DoCommand_GotoWord(ANext: boolean): TATCommandResults;
function DoCommand_ScrollVert(ALines: integer): TATCommandResults;
function DoCommand_TextInsertAtCarets(const AText: atString; AKeepCaret,
AOvrMode, ASelectThen: boolean): TATCommandResults;
function DoCommand_TextInsertTabSpacesAtCarets(AOvrMode: boolean): TATCommandResults;
function DoCommand_TextTabulation: TATCommandResults;
function DoCommand_KeyHome: TATCommandResults;
function DoCommand_KeyEnd: TATCommandResults;
function DoCommand_KeyLeft(ASelCommand: boolean): TATCommandResults;
function DoCommand_KeyRight(ASelCommand: boolean): TATCommandResults;
function DoCommand_KeyUpDown(ADown: boolean; ALines: integer; AKeepRelativePos: boolean): TATCommandResults;
function DoCommand_KeyUpDown_NextLine(ADown: boolean; ALines: integer): TATCommandResults;
function DoCommand_KeyUpDown_Wrapped(ADown: boolean; ALines: integer): TATCommandResults;
function DoCommand_TextBackspace: TATCommandResults;
function DoCommand_TextDelete: TATCommandResults;
function DoCommand_TextDeleteSelection: TATCommandResults;
function DoCommand_TextDeleteLeft(ALen: integer; AAllowUnindent: boolean): TATCommandResults;
function DoCommand_TextDeleteRight(ALen: integer): TATCommandResults;
function DoCommand_TextInsertEol(AKeepCaret: boolean): TATCommandResults;
function DoCommand_TextDeleteLines: TATCommandResults;
function DoCommand_TextDuplicateLine: TATCommandResults;
function DoCommand_TextDeleteToLineBegin: TATCommandResults;
function DoCommand_TextDeleteToLineEnd: TATCommandResults;
function DoCommand_TextDeleteWord(ANext: boolean): TATCommandResults;
function DoCommand_TextDeleteToFileEnd: TATCommandResults;
function DoCommand_GotoTextBegin: TATCommandResults;
function DoCommand_GotoTextEnd: TATCommandResults;
function DoCommand_ClipboardPaste(AKeepCaret, ASelectThen: boolean): TATCommandResults;
function DoCommand_ClipboardPasteColumnBlock(AKeepCaret: boolean): TATCommandResults;
function DoCommand_ClipboardCopy(Append: boolean = false): TATCommandResults;
function DoCommand_ClipboardCut: TATCommandResults;
//
function GetCommandFromKey(var Key: Word; Shift: TShiftState): integer;
function DoMouseWheelAction(Shift: TShiftState; AUp: boolean): boolean;
function GetCaretsArray: TATPointArray;
procedure SetCaretsArray(const L: TATPointArray);
property MouseNiceScroll: boolean read GetMouseNiceScroll write SetMouseNiceScroll;
procedure DoDebugInitFoldList;
procedure OnCanvasFontChanged(Sender:TObject);
protected
procedure DoSendShowHideToInterface; override;
public
//overrides
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure SetFocus; override;
//updates
procedure Invalidate; override;
procedure Update(AUpdateWrapInfo: boolean = false; AUpdateCaretsCoords: boolean = true); reintroduce;
procedure UpdateIncorrectCaretPositions;
procedure UpdateFoldedFromLinesHidden;
procedure DoEventCarets;
procedure DoEventScroll;
procedure DoEventChange;
procedure DoEventState;
//general
property Strings: TATStrings read GetStrings write SetStrings;
property Fold: TATSynRanges read FFold;
property Keymap: TATKeymap read FKeymap write FKeymap;
property Modified: boolean read GetModified;
property AdapterHilite: TATAdapterHilite read FAdapterHilite write FAdapterHilite;
property EditorIndex: integer read FEditorIndex write FEditorIndex;
property LineTop: integer read GetLineTop write SetLineTop;
property LineBottom: integer read FLineBottom;
property LinesFromTop: integer read GetLinesFromTop write SetLinesFromTop;
property ModeOverwrite: boolean read FOverwrite write FOverwrite;
property ModeReadOnly: boolean read GetReadOnly write SetReadOnly;
property ModeOneLine: boolean read GetOneLine write SetOneLine;
property UndoCount: integer read GetUndoCount;
property RedoCount: integer read GetRedoCount;
property Text: atString read GetText write SetText;
property SelRect: TRect read FSelRect;
function IsSelRectEmpty: boolean;
function IsPosSelected(AX, AY: integer): boolean;
function IsPosFolded(AX, AY: integer): boolean;
function IsLineFolded(ALine: integer; ADetectPartialFold: boolean = false): boolean;
function IsCharWord(ch: Widechar): boolean;
property TextCharSize: TPoint read FCharSize;
procedure DoUnfoldLine(ALine: integer);
//gutter
property Gutter: TATGutter read FGutter;
property GutterBandBm: integer read FGutterBandBm write FGutterBandBm;
property GutterBandNum: integer read FGutterBandNum write FGutterBandNum;
property GutterBandState: integer read FGutterBandState write FGutterBandState;
property GutterBandFold: integer read FGutterBandFold write FGutterBandFold;
property GutterBandSep: integer read FGutterBandSep write FGutterBandSep;
property GutterBandEmpty: integer read FGutterBandEmpty write FGutterBandEmpty;
//files
procedure LoadFromFile(const AFilename: string);
procedure SaveToFile(const AFilename: string);
//carets
procedure DoCaretSingle(APosX, APosY, AEndX, AEndY: integer; AUseEndXY: boolean);
procedure DoCaretSingle(AX, AY: integer; AClearSelection: boolean = true);
procedure DoCaretSingleAsIs;
function CaretPosToClientPos(P: TPoint): TPoint;
function ClientPosToCaretPos(P: TPoint; out AEndOfLinePos: boolean): TPoint;
property Carets: TATCarets read FCarets;
property Markers: TATMarkers read FMarkers;
property Attribs: TATMarkers read FAttribs;
function IsLineWithCaret(ALine: integer): boolean;
procedure DoGotoPos(APnt: TPoint; AIndentHorz, AIndentVert: integer);
procedure DoGotoPos_AndUnfold(APnt: TPoint; AIndentHorz, AIndentVert: integer);
procedure DoGotoCaret(AEdge: TATCaretEdge);
//misc
procedure DoCommand(ACmd: integer; const AText: atString = ''); virtual;
procedure BeginUpdate;
procedure EndUpdate;
function TextSelected: atString;
function TextCurrentWord: atString;
procedure DoSelect_All;
procedure DoSelect_None;
procedure DoSelect_Inverted;
procedure DoSelect_SplitSelectionToLines;
procedure DoSelect_Line(P: TPoint);
procedure DoSelect_Word(P: TPoint);
procedure DoSelect_LineRange(ALineFrom: integer; P: TPoint);
procedure DoSelect_ColumnBlock(P1, P2: TPoint);
procedure DoRangeFold(ARange: TATSynRange);
procedure DoRangeUnfold(ARange: TATSynRange);
procedure DoScrollByDelta(Dx, Dy: integer);
procedure DoSizeChange(AInc: boolean);
procedure DoCommentSelectionLines(Act: TATCommentAction;
const AComment: atString);
function DoCalcLineHiliteEx(ALineIndex: integer; var AParts: TATLineParts;
AColorBG: TColor; out AColorAfter: TColor): boolean;
procedure DoSetMarkedLines(ALine1, ALine2: integer);
procedure DoGetMarkedLines(out ALine1, ALine2: integer);
protected
procedure Paint; override;
procedure DoOnResize; override;
procedure UTF8KeyPress(var UTF8Key: TUTF8Char); override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure MouseMove(Shift: TShiftState; X,Y: Integer); override;
function DoMouseWheelDown(Shift: TShiftState; MousePos{%H-}: TPoint): boolean; override;
function DoMouseWheelUp(Shift: TShiftState; MousePos{%H-}: TPoint): boolean; override;
procedure DblClick; override;
procedure TripleClick; override;
function DoGetTextString: atString; virtual;
//messages
procedure WMGetDlgCode(var Msg: TLMNoParams); message LM_GETDLGCODE;
procedure WMEraseBkgnd(var Msg: TLMEraseBkgnd); message LM_ERASEBKGND;
procedure WMHScroll(var Msg: TLMHScroll); message LM_HSCROLL;
procedure WMVScroll(var Msg: TLMVScroll); message LM_VSCROLL;
// Windows IME Support
{$ifdef Windows}
procedure WMIME_STARTCOMPOSITION(var Msg:TMessage); message WM_IME_STARTCOMPOSITION;
procedure WMIME_COMPOSITION(var Msg:TMessage); message WM_IME_COMPOSITION;
procedure WMIME_ENDCOMPOSITION(var Msg:TMessage); message WM_IME_ENDCOMPOSITION;
{$endif}
published
property Align;
property Anchors;
property BorderSpacing;
property BorderStyle;
property Enabled;
property Font;
property ParentFont;
property ParentShowHint;
property ShowHint;
property TabOrder;
property TabStop;
property Visible;
//menu
property PopupTextDefault: TPopupMenu read FMenuStd;
property PopupText: TPopupMenu read FMenuText write FMenuText;
property PopupGutterBm: TPopupMenu read FMenuGutterBm write FMenuGutterBm;
property PopupGutterNum: TPopupMenu read FMenuGutterNum write FMenuGutterNum;
property PopupGutterFold: TPopupMenu read FMenuGutterFold write FMenuGutterFold;
property PopupMinimap: TPopupMenu read FMenuMinimap write FMenuMinimap;
property PopupMicromap: TPopupMenu read FMenuMicromap write FMenuMicromap;
property PopupRuler: TPopupMenu read FMenuRuler write FMenuRuler;
//events std
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnMouseWheel;
property OnMouseWheelDown;
property OnMouseWheelUp;
property OnUTF8KeyPress;
//events new
property OnClickDouble: TATSynEditClickEvent read FOnClickDbl write FOnClickDbl;
property OnClickTriple: TATSynEditClickEvent read FOnClickTriple write FOnClickTriple;
property OnClickMiddle: TATSynEditClickEvent read FOnClickMiddle write FOnClickMiddle;
property OnClickGutter: TATSynEditClickGutterEvent read FOnClickGutter write FOnClickGutter;
property OnClickMicromap: TATSynEditClickMicromapEvent read FOnClickMicromap write FOnClickMicromap;
property OnClickMoveCaret: TATSynEditClickMoveCaretEvent read FOnClickMoveCaret write FOnClickMoveCaret;
property OnClickEndSelect: TATSynEditClickMoveCaretEvent read FOnClickEndSelect write FOnClickEndSelect;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property OnChangeState: TNotifyEvent read FOnChangeState write FOnChangeState;
property OnChangeCaretPos: TNotifyEvent read FOnChangeCaretPos write FOnChangeCaretPos;
property OnScroll: TNotifyEvent read FOnScroll write FOnScroll;
property OnCommand: TATSynEditCommandEvent read FOnCommand write FOnCommand;
property OnDrawBookmarkIcon: TATSynEditDrawBookmarkEvent read FOnDrawBookmarkIcon write FOnDrawBookmarkIcon;
property OnDrawLine: TATSynEditDrawLineEvent read FOnDrawLine write FOnDrawLine;
property OnDrawMicromap: TATSynEditDrawRectEvent read FOnDrawMicromap write FOnDrawMicromap;
property OnDrawEditor: TATSynEditDrawRectEvent read FOnDrawEditor write FOnDrawEditor;
property OnDrawRuler: TATSynEditDrawRectEvent read FOnDrawRuler write FOnDrawRuler;
property OnCalcHilite: TATSynEditCalcHiliteEvent read FOnCalcHilite write FOnCalcHilite;
property OnCalcStaple: TATSynEditCalcStapleEvent read FOnCalcStaple write FOnCalcStaple;
property OnCalcBookmarkColor: TATSynEditCalcBookmarkColorEvent read FOnCalcBookmarkColor write FOnCalcBookmarkColor;
property OnBeforeCalcHilite: TNotifyEvent read FOnBeforeCalcHilite write FOnBeforeCalcHilite;
//misc
property CursorText: TCursor read FCursorText write FCursorText;
property CursorBm: TCursor read FCursorBm write FCursorBm;
property Colors: TATSynEditColors read FColors write FColors;
property WantTabs: boolean read FWantTabs write FWantTabs;
//options
property OptTabSpaces: boolean read FOptTabSpaces write FOptTabSpaces;
property OptTabSize: integer read FTabSize write SetTabSize;
property OptWordChars: atString read FOptWordChars write FOptWordChars;
property OptFoldStyle: TATFoldStyle read FFoldStyle write FFoldStyle;
property OptTextLocked: string read FTextLocked write FTextLocked;
property OptTextHint: string read FTextHint write FTextHint;
property OptTextHintFontStyle: TFontStyles read FTextHintFontStyle write FTextHintFontStyle;
property OptTextHintCenter: boolean read FTextHintCenter write FTextHintCenter;
property OptTextOffsetTop: integer read FOptTextOffsetTop write FOptTextOffsetTop;
property OptTextOffsetFromLine: integer read FOptTextOffsetFromLine write FOptTextOffsetFromLine;
property OptAutoIndent: boolean read FOptAutoIndent write FOptAutoIndent;
property OptAutoIndentKind: TATAutoIndentKind read FOptAutoIndentKind write FOptAutoIndentKind;
property OptCopyLinesIfNoSel: boolean read FOptCopyLinesIfNoSel write FOptCopyLinesIfNoSel;
property OptCutLinesIfNoSel: boolean read FOptCutLinesIfNoSel write FOptCutLinesIfNoSel;
property OptLastLineOnTop: boolean read FOptLastLineOnTop write FOptLastLineOnTop;
property OptOverwriteSel: boolean read FOptOverwriteSel write FOptOverwriteSel;
property OptOverwriteAllowedOnPaste: boolean read FOptOverwriteAllowedOnPaste write FOptOverwriteAllowedOnPaste;
property OptShowStapleStyle: TATLineStyle read FOptShowStapleStyle write FOptShowStapleStyle;
property OptShowStapleIndent: integer read FOptShowStapleIndent write FOptShowStapleIndent;
property OptShowStapleWidthPercent: integer read FOptShowStapleWidthPercent write FOptShowStapleWidthPercent;
property OptShowFullSel: boolean read FOptShowFullSel write FOptShowFullSel;
property OptShowFullHilite: boolean read FOptShowFullHilite write FOptShowFullHilite;
property OptShowCurLine: boolean read FOptShowCurLine write FOptShowCurLine;
property OptShowCurLineMinimal: boolean read FOptShowCurLineMinimal write FOptShowCurLineMinimal;
property OptShowScrollHint: boolean read FOptShowScrollHint write FOptShowScrollHint;
property OptShowCurColumn: boolean read FOptShowCurColumn write FOptShowCurColumn;
property OptCaretManyAllowed: boolean read GetCaretManyAllowed write SetCaretManyAllowed;
property OptCaretVirtual: boolean read FCaretVirtual write FCaretVirtual;
property OptCaretShape: TATSynCaretShape read FCaretShapeIns write SetCaretShapeIns;
property OptCaretShapeOvr: TATSynCaretShape read FCaretShapeOvr write SetCaretShapeOvr;
property OptCaretShapeRO: TATSynCaretShape read FCaretShapeRO write SetCaretShapeRO;
property OptCaretBlinkTime: integer read GetCaretBlinkTime write SetCaretBlinkTime;
property OptCaretBlinkEnabled: boolean read FCaretBlinkEnabled write SetCaretBlinkEnabled;
property OptCaretStopUnfocused: boolean read FCaretStopUnfocused write FCaretStopUnfocused;
property OptCaretPreferLeftSide: boolean read FOptCaretPreferLeftSide write FOptCaretPreferLeftSide;
property OptMarkersSize: integer read FOptMarkersSize write FOptMarkersSize;
property OptGutterVisible: boolean read FOptGutterVisible write FOptGutterVisible;
property OptGutterPlusSize: integer read FOptGutterPlusSize write FOptGutterPlusSize;
property OptGutterShowFoldAlways: boolean read FOptGutterShowFoldAlways write FOptGutterShowFoldAlways;
property OptGutterShowFoldLines: boolean read FOptGutterShowFoldLines write FOptGutterShowFoldLines;
property OptGutterShowFoldLinesAll: boolean read FOptGutterShowFoldLinesAll write FOptGutterShowFoldLinesAll;
property OptRulerVisible: boolean read FOptRulerVisible write FOptRulerVisible;
property OptRulerSize: integer read FOptRulerSize write FOptRulerSize;
property OptRulerFontSize: integer read FOptRulerFontSize write FOptRulerFontSize;
property OptRulerMarkSizeSmall: integer read FOptRulerMarkSizeSmall write FOptRulerMarkSizeSmall;
property OptRulerMarkSizeBig: integer read FOptRulerMarkSizeBig write FOptRulerMarkSizeBig;
property OptRulerTextIndent: integer read FOptRulerTextIndent write FOptRulerTextIndent;
property OptMinimapVisible: boolean read FMinimapVisible write SetMinimapVisible;
property OptMinimapCharWidth: integer read FMinimapCharWidth write FMinimapCharWidth;
property OptMinimapShowSelBorder: boolean read FMinimapShowSelBorder write FMinimapShowSelBorder;
property OptMinimapShowSelAlways: boolean read FMinimapShowSelAlways write FMinimapShowSelAlways;
property OptMicromapVisible: boolean read FMicromapVisible write SetMicromapVisible;
property OptMicromapWidth: integer read FMicromapWidth write FMicromapWidth;
property OptCharSpacingX: integer read GetCharSpacingX write SetCharSpacingX;
property OptCharSpacingY: integer read GetCharSpacingY write SetCharSpacingY;
property OptWrapMode: TATSynWrapMode read FWrapMode write SetWrapMode;
property OptWrapIndented: boolean read FWrapIndented write SetWrapIndented;
property OptMarginRight: integer read FMarginRight write SetMarginRight;
property OptMarginString: string read GetMarginString write SetMarginString;
property OptNumbersAutosize: boolean read FOptNumbersAutosize write FOptNumbersAutosize;
property OptNumbersAlignment: TAlignment read FOptNumbersAlignment write FOptNumbersAlignment;
property OptNumbersFontSize: integer read FOptNumbersFontSize write FOptNumbersFontSize;
property OptNumbersStyle: TATSynNumbersStyle read FOptNumbersStyle write FOptNumbersStyle;
property OptNumbersShowFirst: boolean read FOptNumbersShowFirst write FOptNumbersShowFirst;
property OptNumbersShowCarets: boolean read FOptNumbersShowCarets write FOptNumbersShowCarets;
property OptNumbersSkippedChar: atString read FOptNumbersSkippedChar write FOptNumbersSkippedChar;
property OptNumbersIndentLeft: integer read FOptNumbersIndentLeft write FOptNumbersIndentLeft;
property OptNumbersIndentRight: integer read FOptNumbersIndentRight write FOptNumbersIndentRight;
property OptUnprintedVisible: boolean read FUnprintedVisible write FUnprintedVisible;
property OptUnprintedSpaces: boolean read FUnprintedSpaces write FUnprintedSpaces;
property OptUnprintedEnds: boolean read FUnprintedEnds write FUnprintedEnds;
property OptUnprintedEndsDetails: boolean read FUnprintedEndsDetails write FUnprintedEndsDetails;
property OptUnprintedReplaceSpec: boolean read FUnprintedReplaceSpec write FUnprintedReplaceSpec;
property OptMouseEnableNormalSelection: boolean read FOptMouseEnableNormalSelection write FOptMouseEnableNormalSelection;
property OptMouseEnableColumnSelection: boolean read FOptMouseEnableColumnSelection write FOptMouseEnableColumnSelection;
property OptMouseDownForPopup: boolean read FOptMouseDownForPopup write FOptMouseDownForPopup;
property OptMouseHideCursorOnType: boolean read FOptMouseHideCursor write FOptMouseHideCursor;
property OptMouse2ClickSelectsLine: boolean read FOptMouse2ClickSelectsLine write FOptMouse2ClickSelectsLine;
property OptMouse3ClickSelectsLine: boolean read FOptMouse3ClickSelectsLine write FOptMouse3ClickSelectsLine;
property OptMouse2ClickDragSelectsWords: boolean read FOptMouse2ClickDragSelectsWords write FOptMouse2ClickDragSelectsWords;
property OptMouseDragDrop: boolean read FOptMouseDragDrop write FOptMouseDragDrop;
property OptMouseNiceScroll: boolean read FOptMouseNiceScroll write FOptMouseNiceScroll;
property OptMouseRightClickMovesCaret: boolean read FOptMouseRightClickMovesCaret write FOptMouseRightClickMovesCaret;
property OptMouseGutterClickSelectsLine: boolean read FOptMouseGutterClickSelectsLine write FOptMouseGutterClickSelectsLine;
property OptKeyBackspaceUnindent: boolean read FOptKeyBackspaceUnindent write FOptKeyBackspaceUnindent;
property OptKeyPageKeepsRelativePos: boolean read FOptKeyPageKeepsRelativePos write FOptKeyPageKeepsRelativePos;
property OptKeyUpDownNavigateWrapped: boolean read FOptKeyUpDownNavigateWrapped write FOptKeyUpDownNavigateWrapped;
property OptKeyUpDownKeepColumn: boolean read FOptKeyUpDownKeepColumn write FOptKeyUpDownKeepColumn;
property OptKeyHomeEndNavigateWrapped: boolean read FOptKeyHomeEndNavigateWrapped write FOptKeyHomeEndNavigateWrapped;
property OptKeyPageUpDownSize: TATPageUpDownSize read FOptKeyPageUpDownSize write FOptKeyPageUpDownSize;
property OptKeyLeftRightSwapSel: boolean read FOptKeyLeftRightSwapSel write FOptKeyLeftRightSwapSel;
property OptKeyLeftRightSwapSelAndSelect: boolean read FOptKeyLeftRightSwapSelAndSelect write FOptKeyLeftRightSwapSelAndSelect;
property OptKeyHomeToNonSpace: boolean read FOptKeyHomeToNonSpace write FOptKeyHomeToNonSpace;
property OptKeyEndToNonSpace: boolean read FOptKeyEndToNonSpace write FOptKeyEndToNonSpace;
property OptKeyTabIndents: boolean read FOptKeyTabIndents write FOptKeyTabIndents;
property OptIndentSize: integer read FOptIndentSize write FOptIndentSize;
property OptIndentKeepsAlign: boolean read FOptIndentKeepsAlign write FOptIndentKeepsAlign;
property OptMaxLinesToCountUnindent: integer read FOptMaxLinesToCountUnindent write FOptMaxLinesToCountUnindent;
property OptShowIndentLines: boolean read FOptShowIndentLines write FOptShowIndentLines;
property OptShowGutterCaretBG: boolean read FOptShowGutterCaretBG write FOptShowGutterCaretBG;
property OptAllowScrollbarVert: boolean read FOptAllowScrollbarVert write FOptAllowScrollbarVert;
property OptAllowScrollbarHorz: boolean read FOptAllowScrollbarHorz write FOptAllowScrollbarHorz;
property OptAllowZooming: boolean read FOptAllowZooming write FOptAllowZooming;
property OptAllowReadOnly: boolean read FOptAllowReadOnly write FOptAllowReadOnly;
property OptUndoLimit: integer read GetUndoLimit write SetUndoLimit;
property OptUndoGrouped: boolean read FOptUndoGrouped write FOptUndoGrouped;
property OptUndoAfterSave: boolean read GetUndoAfterSave write SetUndoAfterSave;
property OptSavingForceFinalEol: boolean read FOptSavingForceFinalEol write FOptSavingForceFinalEol;
property OptSavingTrimSpaces: boolean read FOptSavingTrimSpaces write FOptSavingTrimSpaces;
end;
implementation
uses
LCLIntf,
LCLProc,
Dialogs,
Types,
Math,
Clipbrd,
ATSynEdit_Commands,
ATSynEdit_Keymap_Init,
ATStringProc_WordJump;
{$I atsynedit_proc.inc}
{ TATSynEdit }
procedure TATSynEdit.DoPaintRulerTo(C: TCanvas);
var
NX, NSize, NPrevSize, NRulerStart, i: integer;
Str: string;
begin
NPrevSize:= C.Font.Size;
NRulerStart:= FScrollHorz.NPos;
if FOptRulerFontSize<>0 then
C.Font.Size:= FOptRulerFontSize;
C.Font.Color:= FColors.RulerFont;
C.Pen.Color:= FColors.RulerFont;
C.Brush.Color:= FColors.RulerBG;
C.FillRect(FRectRuler);
C.Line(FRectRuler.Left, FRectRuler.Bottom-1,
FRectRuler.Right, FRectRuler.Bottom-1);
for i:= NRulerStart to NRulerStart+GetVisibleColumns+1 do
begin
NX:= FTextOffset.X+(i-NRulerStart)*FCharSize.X;
NSize:= IfThen(i mod 5 = 0, FOptRulerMarkSizeBig, FOptRulerMarkSizeSmall);
C.Line(NX, FRectRuler.Bottom-1,
NX, FRectRuler.Bottom-1-NSize);
if i mod 10 = 0 then
begin
Str:= IntToStr(i);
C.TextOut(NX - C.TextWidth(Str) div 2, FOptRulerTextIndent, Str);
end;
end;
C.Font.Size:= NPrevSize;
end;
procedure TATSynEdit.UpdateGutterAutosize(C: TCanvas);
begin
FGutter[FGutterBandNum].Size:= GetGutterNumbersWidth(C);
FGutter.Update;
end;
procedure TATSynEdit.UpdateMinimapAutosize(C: TCanvas);
{
Minimap must give same cnt of small chars, as rest width gives for normal chars.
This gives:
MapSize / CharWidth_small = (ClientWidth - MapSize) / CharWidth_big
MapSize = (ClientWidth * CharWidth_small) / (CharWidth_big+CharWidth_small)
}
var
CharSmall, CharBig: integer;
begin
CharBig:= FCharSize.X;
CharSmall:= FCharSizeMinimap.X;
if FMinimapCharWidth=0 then
begin
FMinimapWidth:= (ClientWidth - IfThen(FMicromapVisible, FMicromapWidth) - FTextOffset.X)
* CharSmall div (CharSmall+CharBig);
end
else
FMinimapWidth:= CharSmall*FMinimapCharWidth;
FMinimapWidth:= Max(cMinMinimapWidth, FMinimapWidth);
end;
function TATSynEdit.DoFormatLineNumber(N: integer): atString;
begin
if FOptNumbersShowCarets then
if IsLineWithCaret(N-1) then
begin
Result:= IntToStr(N);
Exit
end;
if FOptNumbersShowFirst then
if N=1 then
begin
Result:= IntToStr(N);
Exit
end;
case FOptNumbersStyle of
cNumbersAll:
Result:= IntToStr(N);
cNumbersNone:
Result:= FOptNumbersSkippedChar;
cNumbersEach10th:
begin
if (N mod 10 = 0) then
Result:= IntToStr(N)
else
if (N mod 5) = 0 then
Result:= '-'
else
Result:= FOptNumbersSkippedChar;
end;
cNumbersEach5th:
begin
if (N mod 5 = 0) then
Result:= IntToStr(N)
else
Result:= FOptNumbersSkippedChar;
end;
else
raise Exception.Create('Unknown num-style');
end;
end;
function TATSynEdit.GetScrollbarVisible(bVertical: boolean): boolean;
const
cKind: array[boolean] of integer = (SB_HORZ, SB_VERT);
var
si: TScrollInfo;
begin
FillChar(si{%H-}, SizeOf(si), 0);
si.cbSize:= SizeOf(si);
si.fMask:= SIF_ALL;
GetScrollInfo(Handle, cKind[bVertical], si);
Result:= Longword(si.nMax) > Longword(si.nPage);
end;
procedure TATSynEdit.SetMarginRight(AValue: integer);
begin
if AValue=FMarginRight then Exit;
FMarginRight:= Max(AValue, cMinMarginRt);
if FWrapMode=cWrapAtMargin then
FWrapUpdateNeeded:= true;
Update;
end;
procedure TATSynEdit.UpdateWrapInfo;
var
NNewVisibleColumns: integer;
NIndentMaximal: integer;
Items: TList;
ListNums: TList;
i, j: integer;
NLine, NIndexFrom, NIndexTo: integer;
UseCachedUpdate: boolean;
begin
//FWrapProgress:= 0;
NNewVisibleColumns:= GetVisibleColumns;
NIndentMaximal:= Max(2, NNewVisibleColumns-cMinCharsAfterAnyIndent); //don't do too big NIndent
if (not FWrapUpdateNeeded) and
(FWrapMode=cWrapOn) and
(FPrevVisibleColumns<>NNewVisibleColumns) then
FWrapUpdateNeeded:= true;
if not FWrapUpdateNeeded then Exit;
FWrapUpdateNeeded:= false;
FPrevVisibleColumns:= NNewVisibleColumns;
{$ifdef beep_wrapinfo}
Beep;
{$endif}
case FWrapMode of
cWrapOff:
FWrapColumn:= 0;
cWrapOn:
FWrapColumn:= Max(cMinWrapColumn, NNewVisibleColumns-cScrollKeepHorz);
cWrapAtMargin:
FWrapColumn:= Max(cMinWrapColumn, FMarginRight);
end;
UseCachedUpdate:=
(FWrapInfo.Count>0) and
(Strings.Count>cMaxLinesForOldWrapUpdate) and
(not Strings.ListUpdatesHard) and
(Strings.ListUpdates.Count>0);
//UseCachedUpdate:= false;////to disable
Items:= TList.Create;
ListNums:= TList.Create;
try
if not UseCachedUpdate then
begin
FWrapInfo.Clear;
FWrapInfo.SetCapacity(Strings.Count);
for i:= 0 to Strings.Count-1 do
begin
DoCalcWrapInfos(i, NIndentMaximal, Items);
for j:= 0 to Items.Count-1 do
FWrapInfo.Add(TATSynWrapItem(Items[j]));
end;
end
else
begin
{$ifdef beep_cached_update}
Beep;
{$endif}
ListNums.Assign(Strings.ListUpdates);
for i:= 0 to ListNums.Count-1 do
begin
NLine:= NativeInt{%H-}(ListNums[i]);
DoCalcWrapInfos(NLine, NIndentMaximal, Items);
if Items.Count=0 then Continue;
FWrapInfo.FindIndexesOfLineNumber(NLine, NIndexFrom, NIndexTo);
if NIndexFrom<0 then
begin
//Showmessage('Cant find wrap-index for line '+Inttostr(NLine));
Continue;
end;
//slow for 100carets, 1M lines, so made method in which
//we can optimize it (instead of del/ins do assign)
FWrapInfo.ReplaceItems(NIndexFrom, NIndexTo, Items);
end;
end;
finally
FreeAndNil(ListNums);
FreeAndNil(Items);
end;
Strings.ListUpdates.Clear;
Strings.ListUpdatesHard:= false;
{$ifdef debug_findwrapindex}
DebugFindWrapIndex;
{$endif}
end;
procedure TATSynEdit.DoCalcWrapInfos(ALine: integer; AIndentMaximal: integer; AItems: TList);
var
NHiddenIndex, NOffset, NLen, NIndent, NVisColumns: integer;
NFinal: TATSynWrapFinal;
Str: atString;
begin
AItems.Clear;
NHiddenIndex:= Strings.LinesHidden[ALine, FEditorIndex];
if NHiddenIndex<0 then Exit;
Str:= Strings.Lines[ALine];
NLen:= Length(Str);
NVisColumns:= Max(GetVisibleColumns, cMinWrapColumnAbs);
//line collapsed partially?
if NHiddenIndex>0 then
begin
AItems.Add(TATSynWrapItem.Create(ALine, 1, Min(NLen, NHiddenIndex-1), 0, cWrapItemCollapsed));
Exit;
end;
//wrap not needed?
if (FWrapColumn<cMinWrapColumnAbs) then
begin
AItems.Add(TATSynWrapItem.Create(ALine, 1, NLen, 0, cWrapItemFinal));
Exit;
end;
NOffset:= 1;
NIndent:= 0;
repeat
NLen:= SFindWordWrapOffset(
//very slow to calc for entire line (eg len=70K),
//calc for first NVisColumns chars
Copy(Str, 1, NVisColumns),
Max(FWrapColumn-NIndent, cMinWrapColumnAbs),
FTabSize,
FOptWordChars,
FWrapIndented);
if NLen>=Length(Str) then
NFinal:= cWrapItemFinal
else
NFinal:= cWrapItemMiddle;
AItems.Add(TATSynWrapItem.Create(ALine, NOffset, NLen, NIndent, NFinal));
if FWrapIndented then
if NOffset=1 then
begin
NIndent:= SGetIndentExpanded(Str, FTabSize);
NIndent:= Min(NIndent, AIndentMaximal);
end;
Inc(NOffset, NLen);
Delete(Str, 1, NLen);
until Str='';
end;
function TATSynEdit.GetVisibleLines: integer;
begin
Result:= (FRectMain.Bottom-FRectMain.Top) div FCharSize.Y;
end;
function TATSynEdit.GetVisibleColumns: integer;
begin
Result:= (FRectMain.Right-FRectMain.Left) div FCharSize.X;
end;
function TATSynEdit.GetVisibleLinesMinimap: integer;
begin
Result:= (FRectMinimap.Bottom-FRectMinimap.Top) div FCharSizeMinimap.Y - 1;
end;
function TATSynEdit.GetMinimapScrollPos: integer;
begin
Result:=
Int64(FScrollVert.NPos) *
Max(0, FScrollVert.NMax-GetVisibleLinesMinimap) div
Max(1, FScrollVert.NMax-FScrollVert.NPage);
end;
procedure TATSynEdit.SetTabSize(AValue: integer);
begin
if FTabSize=AValue then Exit;
FTabSize:= Min(cMaxTabSize, Max(cMinTabSize, AValue));
FWrapUpdateNeeded:= true;
end;
procedure TATSynEdit.SetText(AValue: atString);
begin
Strings.LoadFromString(AValue);
DoCaretSingle(0, 0);
Update(true);
end;
procedure TATSynEdit.SetWrapMode(AValue: TATSynWrapMode);
var
NLine: integer;
begin
if FWrapMode=AValue then Exit;
NLine:= LineTop;
FWrapMode:= AValue;
FWrapUpdateNeeded:= true;
if FWrapMode<>cWrapOff then
FScrollHorz.NPos:= 0;
Invalidate;
AppProcessMessages;
LineTop:= NLine;
Invalidate;
end;
procedure TATSynEdit.SetWrapIndented(AValue: boolean);
begin
if FWrapIndented=AValue then Exit;
FWrapIndented:=AValue;
if FWrapMode<>cWrapOff then
FWrapUpdateNeeded:= true;
end;
function TATSynEdit.UpdateScrollbars: boolean;
var
bVert1, bVert2,
bHorz1, bHorz2: boolean;
begin
Result:= false;
with FScrollVert do
begin
NPage:= Max(1, GetVisibleLines)-1;
NMin:= 0;
if FOptLastLineOnTop then
NMax:= Max(1, FWrapInfo.Count+NPage-1)
else
NMax:= Max(1, FWrapInfo.Count-1);
NPosLast:= Max(NMin, NMax-NPage);
end;
with FScrollHorz do
begin
NPage:= Max(1, GetVisibleColumns);
NMin:= 0;
//NMax calculated in DoPaintTextTo
//hide horz bar for word-wrap:
if FWrapMode=cWrapOn then
NMax:= NPage;
NPosLast:= Max(NMin, NMax-NPage);
end;
bVert1:= GetScrollbarVisible(true);
bHorz1:= GetScrollbarVisible(false);
UpdateScrollbarVert;
UpdateScrollbarHorz;
bVert2:= GetScrollbarVisible(true);
bHorz2:= GetScrollbarVisible(false);
Result:= (bVert1<>bVert2) or (bHorz1<>bHorz2);
if not IsEqualScrollInfo(FPrevHorz, FScrollHorz) or
not IsEqualScrollInfo(FPrevVert, FScrollVert) then
begin
FPrevHorz:= FScrollHorz;
FPrevVert:= FScrollVert;
DoEventScroll;
end;
end;
procedure TATSynEdit.UpdateScrollbarVert;
var
si: TScrollInfo;
begin
if not FOptAllowScrollbarVert then Exit;
FillChar(si{%H-}, SizeOf(si), 0);
si.cbSize:= SizeOf(si);
si.fMask:= SIF_ALL;// or SIF_DISABLENOSCROLL; //todo -- DisableNoScroll doesnt work(Win)
si.nMin:= FScrollVert.NMin;
si.nMax:= FScrollVert.NMax;
si.nPage:= FScrollVert.NPage;
si.nPos:= FScrollVert.NPos;
SetScrollInfo(Handle, SB_VERT, si, True);
end;
procedure TATSynEdit.UpdateScrollbarHorz;
var
si: TScrollInfo;
begin
if not FOptAllowScrollbarHorz then Exit;
FillChar(si{%H-}, SizeOf(si), 0);
si.cbSize:= SizeOf(si);
si.fMask:= SIF_ALL; //or SIF_DISABLENOSCROLL; don't work
si.nMin:= FScrollHorz.NMin;
si.nMax:= FScrollHorz.NMax;
si.nPage:= FScrollHorz.NPage;
si.nPos:= FScrollHorz.NPos;
SetScrollInfo(Handle, SB_HORZ, si, True);
end;
function TATSynEdit.GetRectMain: TRect;
begin
Result.Left:= FTextOffset.X;
Result.Top:= FTextOffset.Y;
Result.Right:= ClientWidth
- IfThen(FMinimapVisible, FMinimapWidth)
- IfThen(FMicromapVisible, FMicromapWidth);
Result.Bottom:= ClientHeight;
end;
function TATSynEdit.GetRectMinimap: TRect;
begin
if FMinimapVisible then
begin
Result.Left:= ClientWidth-FMinimapWidth-IfThen(FMicromapVisible, FMicromapWidth);
Result.Top:= 0;
Result.Right:= Result.Left+FMinimapWidth;
Result.Bottom:= ClientHeight;
end
else
Result:= cRectEmpty;
end;
function TATSynEdit.GetRectMinimapSel: TRect;
begin
Result.Left:= FRectMinimap.Left;
Result.Right:= FRectMinimap.Right;
Result.Top:= GetMinimapSelTop;
Result.Bottom:= Result.Top +
Min(
(FScrollVert.NPage+1)*FCharSizeMinimap.Y,
GetMinimapActualHeight
);
end;
function TATSynEdit.GetRectMicromap: TRect;
begin
if FMicromapVisible then
begin
Result.Left:= ClientWidth-FMicromapWidth;
Result.Top:= 0;
Result.Right:= ClientWidth;
Result.Bottom:= ClientHeight;
end
else
Result:= cRectEmpty;
end;
function TATSynEdit.GetRectGutter: TRect;
begin
if FOptGutterVisible then
begin
Result.Left:= 0;
Result.Top:= IfThen(FOptRulerVisible, FOptRulerSize);
Result.Right:= FGutter.Width;
Result.Bottom:= ClientHeight;
end
else
Result:= cRectEmpty;
end;
function TATSynEdit.GetRectRuler: TRect;
begin
if FOptRulerVisible then
begin
Result.Left:= 0;
Result.Right:= FRectMain.Right;
Result.Top:= 0;
Result.Bottom:= Result.Top+FOptRulerSize;
end
else
Result:= cRectEmpty;
end;
procedure TATSynEdit.DoPaintTo(C: TCanvas; ALineFrom: integer);
begin
if csLoading in ComponentState then Exit;
C.Brush.Color:= GetColorTextBG;
C.FillRect(ClientRect);
C.Font.Assign(Font);
FCharSize:= GetCharSize(C, FCharSpacingText);
if FOptGutterVisible and FOptNumbersAutosize then
UpdateGutterAutosize(C);
if FMinimapVisible then
UpdateMinimapAutosize(C);
FTextOffset:= GetTextOffset; //after gutter autosize
FRectMinimap:= GetRectMinimap;
FRectMicromap:= GetRectMicromap;
FRectGutter:= GetRectGutter;
FRectMain:= GetRectMain; //after gutter/minimap
FRectRuler:= GetRectRuler; //after main
UpdateWrapInfo;
DoPaintTextTo(C, FRectMain, FCharSize, FOptGutterVisible, true, FScrollHorz, FScrollVert, ALineFrom);
DoPaintMarginsTo(C);
DoPaintNiceScroll(C);
if FOptRulerVisible then
begin
DoPaintRulerTo(C);
if Assigned(FOnDrawRuler) then
FOnDrawRuler(Self, C, FRectRuler);
end;
if Assigned(FOnDrawEditor) then
FOnDrawEditor(Self, C, FRectMain);
if FMinimapVisible then
DoPaintMinimapTo(C);
if FMicromapVisible then
DoPaintMicromapTo(C);
end;
function TATSynEdit.GetCharSize(C: TCanvas; ACharSpacing: TPoint): TPoint;
var
Size: TPoint;
begin
Size:= CanvasFontSizes(C);
Result.X:= Max(1, Size.X + ACharSpacing.X);
Result.Y:= Max(1, Size.Y + ACharSpacing.Y);
end;
procedure TATSynEdit.DoPaintGutterBandBG(C: TCanvas; ABand: integer; AColor: TColor; ATop, ABottom: integer);
var
X1, X2: integer;
begin
with FGutter[ABand] do
begin X1:= Left; X2:= Right; end;
C.Brush.Color:= AColor;
if ATop>=0 then
C.FillRect(X1, ATop, X2, ABottom)
else
C.FillRect(X1, FRectGutter.Top, X2, FRectGutter.Bottom)
end;
procedure TATSynEdit.DoPaintTextTo(C: TCanvas;
const ARect: TRect;
const ACharSize: TPoint;
AWithGutter, AMainText: boolean;
var AScrollHorz, AScrollVert: TATSynScrollInfo;
ALineFrom: integer);
var
NCoordTop, NCoordSep: integer;
NWrapIndex, NLinesIndex: integer;
NOutputCharsSkipped, NOutputStrWidth: integer;
NOutputSpacesSkipped: real;
WrapItem: TATSynWrapItem;
NColorEntire, NColorAfter: TColor;
Str, StrOut, StrOutUncut: atString;
CurrPoint, CurrPointText, CoordAfterText, CoordNums: TPoint;
LineSeparator: TATLineSeparator;
LineWithCaret, LineEolSelected, LineColorForced: boolean;
Parts: TATLineParts;
Event: TATSynEditDrawLineEvent;
StrSize: TSize;
//
procedure DoPaintGutterBandState(ATop: integer; AColor: TColor);
begin
DoPaintGutterBandBG(C, FGutterBandState, AColor, ATop, ATop+ACharSize.Y);
end;
//
begin
//wrap turned off can cause bad scrollpos, fix it
with AScrollVert do
NPos:= Min(NPos, NPosLast);
C.Brush.Color:= GetColorTextBG;
C.FillRect(ARect);
if AWithGutter then
begin
C.Brush.Color:= FColors.GutterBG;
C.FillRect(FRectGutter);
//paint some bands, for full height coloring
if FGutter[FGutterBandFold].Visible then
DoPaintGutterBandBG(C, FGutterBandFold, FColors.GutterFoldBG, -1, -1);
if FGutter[FGutterBandSep].Visible then
DoPaintGutterBandBG(C, FGutterBandSep, FColors.GutterSeparatorBG, -1, -1);
if FGutter[FGutterBandEmpty].Visible then
DoPaintGutterBandBG(C, FGutterBandEmpty, GetColorTextBG, -1, -1);
end;
if AMainText and (FTextHint<>'') then
if (Strings.Count=0) or ((Strings.Count=1) and (Strings.Lines[0]='')) then
begin
DoPaintTextHintTo(C);
Exit
end;
{$ifndef fix_horzscroll}
AScrollHorz.NMax:= 1;
{$endif}
NCoordTop:= ARect.Top;
if ALineFrom>=0 then
begin
FWrapInfo.FindIndexesOfLineNumber(ALineFrom, NWrapIndex, NColorAfter{dummy});
AScrollVert.NPos:= NWrapIndex;
end
else
NWrapIndex:= AScrollVert.NPos;
DoEventBeforeCalcHilite;
repeat
if NCoordTop>ARect.Bottom then Break;
if not FWrapInfo.IsIndexValid(NWrapIndex) then Break;
WrapItem:= FWrapInfo.Items[NWrapIndex];
NLinesIndex:= WrapItem.NLineIndex;
if not Strings.IsIndexValid(NLinesIndex) then Break;
FLineBottom:= NLinesIndex;
if IsFoldLineNeededBeforeWrapitem(NWrapIndex) then
begin
NCoordSep:= NCoordTop-1;
C.Pen.Color:= Colors.CollapseLine;
C.Line(ARect.Left, NCoordSep, ARect.Right, NCoordSep);
end;
//prepare line
Str:= Strings.Lines[NLinesIndex];
Str:= Copy(Str, WrapItem.NCharIndex, WrapItem.NLength);
LineSeparator:= Strings.LinesSeparator[NLinesIndex];
LineWithCaret:= IsLineWithCaret(NLinesIndex);
LineEolSelected:= IsPosSelected(WrapItem.NCharIndex-1+WrapItem.NLength, WrapItem.NLineIndex);
StrOut:= Str;
StrOutUncut:= StrOut;
AScrollHorz.NMax:= Max(AScrollHorz.NMax,
Round(CanvasTextSpaces(StrOutUncut, FTabSize)) + cScrollKeepHorz);
CurrPoint.X:= ARect.Left;
CurrPoint.Y:= NCoordTop;
C.Brush.Color:= GetColorTextBG;
C.Font.Color:= GetColorTextFont;
DoCalcLineEntireColor(NLinesIndex, NCoordTop, LineWithCaret, NColorEntire, LineColorForced);
C.Brush.Color:= NColorEntire;
C.FillRect(ARect.Left, NCoordTop, ARect.Right, NCoordTop+ACharSize.Y);
CurrPointText:= Point(
Int64(CurrPoint.X) + (Int64(WrapItem.NIndent)-AScrollHorz.NPos)*ACharSize.X,
CurrPoint.Y);
NOutputStrWidth:= 0;
//paint line
if StrOut<>'' then
begin
NOutputCharsSkipped:= 0;
NOutputSpacesSkipped:= 0;
if FWrapInfo.IsItemInitial(NWrapIndex) then
begin
SFindOutputSkipOffset(StrOut, FTabSize, AScrollHorz.NPos, NOutputCharsSkipped, NOutputSpacesSkipped);
Delete(StrOut, 1, NOutputCharsSkipped);
Delete(StrOut, cMaxCharsForOutput, MaxInt);
Inc(CurrPointText.X, Trunc(NOutputSpacesSkipped*ACharSize.X));
end;
if WrapItem.NIndent>0 then
begin
NColorAfter:= GetColorTextBG;
DoCalcPosColor(WrapItem.NCharIndex, NLinesIndex, NColorAfter);
DoPaintLineIndent(C, ARect, ACharSize,
NCoordTop, WrapItem.NIndent,
NColorAfter,
AScrollHorz.NPos, AMainText and FOptShowIndentLines);
end;
NColorAfter:= clNone;
DoCalcLineHilite(WrapItem, Parts{%H-},
NOutputCharsSkipped, cMaxCharsForOutput,
NColorEntire, LineColorForced,
NColorAfter);
//adapter may return ColorAfterEol, paint it
if FOptShowFullHilite then
if NColorAfter<>clNone then
begin
C.Brush.Color:= NColorAfter;
C.FillRect(CurrPointText.X, NCoordTop, ARect.Right, NCoordTop+ACharSize.Y);
end;
//paint selection bg, after applying ColorAfterEol
DoPaintSelectedLineBG(C, ACharSize, ARect,
CurrPoint,
CurrPointText,
NLinesIndex,
LineEolSelected,
AScrollHorz);
if AWithGutter then
Event:= FOnDrawLine
else
Event:= nil;
if FUnprintedReplaceSpec then
StrOut:= SRemoveAsciiControlChars(StrOut);
if AMainText then
CanvasTextOut(C,
CurrPointText.X,
CurrPointText.Y,
StrOut,
FTabSize,
ACharSize,
AMainText,
AMainText and FUnprintedVisible and FUnprintedSpaces,
FColors.UnprintedFont,
FColors.UnprintedHexFont,
NOutputStrWidth,
Trunc(NOutputSpacesSkipped), //todo:
//needed number of chars of all chars counted as 1.0,
//while NOutputSpacesSkipped is with cjk counted as 1.7
@Parts,
Event,
FOptTextOffsetFromLine,
ClientWidth+ACharSize.X*2
)
else
CanvasTextOutMinimap(C,
StrOut,
CurrPointText,
FCharSizeMinimap,
FTabSize,
@Parts
);
//restore after textout
C.Font.Style:= Font.Style;
end
else
//paint empty line bg
begin
if FOptShowFullHilite then
begin
NColorAfter:= clNone;
DoCalcPosColor(0, NLinesIndex, NColorAfter);
if NColorAfter<>clNone then
begin
C.Brush.Color:= NColorAfter;
C.FillRect(ARect.Left, NCoordTop, ARect.Right, NCoordTop+ACharSize.Y);
end;
end;
DoPaintSelectedLineBG(C, ACharSize, ARect,
CurrPoint,
CurrPointText,
NLinesIndex,
LineEolSelected,
AScrollHorz);
end;
CoordAfterText:= Point(
CurrPointText.X+NOutputStrWidth,
CurrPointText.Y);
if WrapItem.NFinal=cWrapItemFinal then
begin
//for OptShowFullSel=false paint eol bg
if LineEolSelected then
begin
C.Brush.Color:= FColors.TextSelBG;
C.FillRect(
CoordAfterText.X,
CoordAfterText.Y,
CoordAfterText.X+ACharSize.X,
CoordAfterText.Y+ACharSize.Y);
end;
//paint eol mark
if AMainText and FUnprintedVisible and FUnprintedEnds then
DoPaintUnprintedEol(C,
cLineEndNiceNames[Strings.LinesEnds[WrapItem.NLineIndex]],
CoordAfterText,
ACharSize,
FColors.UnprintedFont,
FColors.UnprintedBG,
FUnprintedEndsDetails);
end;
//draw collapsed-mark
if AMainText then
if WrapItem.NFinal=cWrapItemCollapsed then
DoPaintFoldedMark(C,
Point(Strings.LinesHidden[NLinesIndex, FEditorIndex]-1, NLinesIndex),
CoordAfterText,
GetFoldedMarkText(NLinesIndex));
//draw separators
if LineSeparator<>cLineSepNone then
begin
if LineSeparator=cLineSepTop then
NCoordSep:= NCoordTop
else
NCoordSep:= NCoordTop+ACharSize.Y-1;
C.Pen.Color:= Colors.BlockSepLine;
C.Line(ARect.Left, NCoordSep, ARect.Right, NCoordSep);
end;
//draw gutter
if AWithGutter then
begin
//paint area over scrolled text
C.Brush.Color:= FColors.GutterBG;
C.FillRect(FRectGutter.Left, NCoordTop, FRectGutter.Right, NCoordTop+ACharSize.Y);
//gutter band: number
if FGutter[FGutterBandNum].Visible then
begin
if LineWithCaret and FOptShowGutterCaretBG then
DoPaintGutterBandBG(C, FGutterBandNum, FColors.GutterCaretBG, NCoordTop, NCoordTop+ACharSize.Y);
if FWrapInfo.IsItemInitial(NWrapIndex) then
begin
C.Font.Color:= FColors.GutterFont;
if FOptNumbersFontSize<>0 then
C.Font.Size:= FOptNumbersFontSize;
Str:= DoFormatLineNumber(NLinesIndex+1);
StrSize:= C.TextExtent(Str);
case FOptNumbersAlignment of
taLeftJustify: CoordNums.X:= FGutter[FGutterBandNum].Left + FOptNumbersIndentLeft;
taRightJustify: CoordNums.X:= FGutter[FGutterBandNum].Right - StrSize.cx - FOptNumbersIndentRight;
taCenter: CoordNums.X:= (FGutter[FGutterBandNum].Left + FGutter[FGutterBandNum].Right - StrSize.cx) div 2;
end;
if FOptNumbersFontSize=0 then
CoordNums.Y:= NCoordTop
else
CoordNums.Y:= NCoordTop + ACharSize.y div 2 - StrSize.cy div 2;
C.TextOut(CoordNums.X, CoordNums.Y, Str);
C.Font.Size:= Font.Size;
end;
end;
//gutter band: bookmark
if FGutter[FGutterBandBm].Visible then
if FWrapInfo.IsItemInitial(NWrapIndex) then
begin
if Strings.LinesBm[NLinesIndex]<>0 then
DoEventDrawBookmarkIcon(C, NLinesIndex,
Rect(
FGutter[FGutterBandBm].Left,
NCoordTop,
FGutter[FGutterBandBm].Right,
NCoordTop+ACharSize.Y
));
end;
//gutter band: fold
if FGutter[FGutterBandFold].Visible then
begin
DoPaintGutterBandBG(C, FGutterBandFold, FColors.GutterFoldBG, NCoordTop, NCoordTop+ACharSize.Y);
DoPaintGutterFolding(C,
NWrapIndex,
FGutter[FGutterBandFold].Left,
FGutter[FGutterBandFold].Right,
NCoordTop,
NCoordTop+ACharSize.Y
);
end;
//gutter band: state
if FGutter[FGutterBandState].Visible then
begin
case Strings.LinesState[NLinesIndex] of
cLineStateChanged: DoPaintGutterBandState(NCoordTop, FColors.StateChanged);
cLineStateAdded: DoPaintGutterBandState(NCoordTop, FColors.StateAdded);
cLineStateSaved: DoPaintGutterBandState(NCoordTop, FColors.StateSaved);
end;
end;
//gutter band: separator
if FGutter[FGutterBandSep].Visible then
DoPaintGutterBandBG(C, FGutterBandSep, FColors.GutterSeparatorBG, NCoordTop, NCoordTop+ACharSize.Y);
//gutter band: empty indent
if FGutter[FGutterBandEmpty].Visible then
DoPaintGutterBandBG(C, FGutterBandEmpty, GetColorTextBG, NCoordTop, NCoordTop+ACharSize.Y);
end;
//end of painting line
Inc(NCoordTop, ACharSize.Y);
Inc(NWrapIndex);
until false;
//staples
if AMainText then
DoPaintStaples(C, ARect, ACharSize, AScrollHorz);
end;
function TATSynEdit.GetMinimapSelTop: integer;
begin
Result:= FRectMinimap.Top + (FScrollVert.NPos-FScrollVertMinimap.NPos)*FCharSizeMinimap.Y;
end;
function TATSynEdit.GetMinimapActualHeight: integer;
begin
Result:=
Max(2, Min(
FRectMinimap.Bottom-FRectMinimap.Top,
FWrapInfo.Count*FCharSizeMinimap.Y
));
end;
function TATSynEdit.GetMinimapSelTop_PixelsToWrapIndex(APixels: integer): integer;
var
Percent: double;
const
PercentFix: double = 0.02;
begin
{
1) calculate percent position of mouse
2) must correct this! we must scroll to 0 if almost at the top;
must scroll to end if almost at the end - do this by increment n%
}
Percent:= (APixels-FRectMinimap.Top) / GetMinimapActualHeight;
if Percent<0.1 then Percent:= Max(0.0, Percent-PercentFix) else
if Percent>0.9 then Percent:= Min(100.0, Percent+PercentFix);
Result:= Round(Percent * FWrapInfo.Count);
end;
procedure TATSynEdit.DoPaintMinimapSelTo(C: TCanvas);
var
R: TRect;
begin
if not FMinimapShowSelAlways then
if not FCursorOnMinimap then Exit;
R:= GetRectMinimapSel;
if IntersectRect(R, R, FRectMinimap) then
begin
CanvasInvertRect(C, R, FColors.MinimapSelBG);
if FMinimapShowSelBorder then
begin
C.Pen.Color:= FColors.MinimapBorder;
C.Brush.Style:= bsClear;
C.Rectangle(R);
C.Brush.Style:= bsSolid;
end;
end;
end;
procedure TATSynEdit.DoPaintMinimapTo(C: TCanvas);
begin
DoClearScrollInfo(FScrollHorzMinimap);
DoClearScrollInfo(FScrollVertMinimap);
FScrollVertMinimap.NPos:= GetMinimapScrollPos;
FScrollVertMinimap.NPosLast:= MaxInt div 2;
DoPaintTextTo(C, FRectMinimap, FCharSizeMinimap, false, false, FScrollHorzMinimap, FScrollVertMinimap, -1);
DoPaintMinimapSelTo(C);
if FColors.MinimapBorder<>clNone then
begin
C.Pen.Color:= FColors.MinimapBorder;
C.Line(FRectMinimap.Left-1, FRectMinimap.Top,
FRectMinimap.Left-1, FRectMinimap.Bottom);
end;
end;
procedure TATSynEdit.DoPaintMicromapTo(C: TCanvas);
begin
if Assigned(FOnDrawMicromap) then
FOnDrawMicromap(Self, C, FRectMicromap)
else
begin
C.Brush.Color:= clCream;
C.FillRect(FRectMicromap);
end;
end;
procedure TATSynEdit.DoPaintMarginLineTo(C: TCanvas; AX: integer; AColor: TColor);
begin
if (AX>=FRectMain.Left) and (AX<FRectMain.Right) then
begin
C.Pen.Color:= AColor;
C.Line(AX, FRectMain.Top,
AX, FRectMain.Bottom);
end;
end;
procedure TATSynEdit.DoPaintMarginsTo(C: TCanvas);
//
function PosX(NMargin: integer): integer;
begin
Result:= FRectMain.Left + FCharSize.X*(NMargin-FScrollHorz.NPos);
end;
var
i: integer;
begin
if FMarginRight>1 then
DoPaintMarginLineTo(C, PosX(FMarginRight), FColors.MarginRight);
for i:= 0 to FMarginList.Count-1 do
DoPaintMarginLineTo(C, PosX(NativeInt{%H-}(FMarginList[i])), FColors.MarginUser);
end;
procedure TATSynEdit.DoPaintFoldedMark(C: TCanvas;
APos: TPoint; ACoord: TPoint; const AMarkText: string);
var
NWidth: integer;
Str: string;
begin
Str:= STabsToSpaces(AMarkText, FTabSize);
Inc(ACoord.X, cFoldedMarkIndentOuter);
//set colors:
//if 1st chars selected, then use selection-color
if IsPosSelected(APos.X, APos.Y) then
begin
C.Font.Color:= Colors.TextSelFont;
C.Brush.Color:= Colors.TextSelBG;
end
else
begin
C.Font.Color:= Colors.CollapseMarkFont;
C.Brush.Color:= Colors.CollapseMarkBG;
end;
//paint text
C.TextOut(
ACoord.X+cFoldedMarkIndentInner,
ACoord.Y+FOptTextOffsetFromLine,
Str);
NWidth:= C.TextWidth(Str) + 2*cFoldedMarkIndentInner;
//paint frame
C.Pen.Color:= FColors.CollapseMarkBorder;
C.Brush.Style:= bsClear;
C.Rectangle(ACoord.X, ACoord.Y, ACoord.X+NWidth, ACoord.Y+FCharSize.Y);
C.Brush.Style:= bsSolid;
end;
function TATSynEdit.GetCharSpacingX: integer;
begin
Result:= FCharSpacingText.X;
end;
function TATSynEdit.GetCharSpacingY: integer;
begin
Result:= FCharSpacingText.Y;
end;
function TATSynEdit.GetMarginString: string;
var
i: integer;
begin
Result:= '';
for i:= 0 to FMarginList.Count-1 do
Result:= Result+IntToStr(NativeInt{%H-}(FMarginList[i]))+' ';
end;
function TATSynEdit.GetReadOnly: boolean;
begin
Result:= Strings.ReadOnly;
end;
function TATSynEdit.GetLineTop: integer;
var
Item: TATSynWrapItem;
begin
Result:= 0;
Item:= FWrapInfo.Items[FScrollVert.NPos];
if Assigned(Item) then
Result:= Item.NLineIndex;
end;
constructor TATSynEdit.Create(AOwner: TComponent);
var
i: integer;
begin
inherited;
Caption:= '';
ControlStyle:= ControlStyle+[csOpaque, csDoubleClicks, csTripleClicks];
BorderStyle:= bsNone;
TabStop:= true;
Width:= 300;
Height:= 200;
Font.Name:= 'Courier New';
Font.Size:= {$ifndef darwin} 9 {$else} 14 {$endif};
FWantTabs:= true;
FCharSize:= Point(4, 4); //not nul
FEditorIndex:= 0;
FCarets:= TATCarets.Create;
FCarets.Add(0, 0);
FCaretBlinkEnabled:= true;
FCaretShown:= false;
FCaretShapeIns:= cInitCaretShapeIns;
FCaretShapeOvr:= cInitCaretShapeOvr;
FCaretShapeRO:= cInitCaretShapeRO;
FCaretVirtual:= true;
FCaretSpecPos:= false;
FCaretStopUnfocused:= true;
FMarkers:= TATMarkers.Create;
FAttribs:= TATMarkers.Create;
FMarkedRange:= TATMarkers.Create;
{$ifdef test_markedrange}
DoSetMarkedRange(1, 3);
{$endif}
{$ifdef test_attribs}
DoDebugAddAttribs;
{$endif}
FPaintLocked:= 0;
FPaintStatic:= false;
FPaintFlags:= [cPaintUpdateBitmap, cPaintUpdateScrollbars];
FColors:= TATSynEditColors.Create;
InitDefaultColors(FColors);
FCursorText:= crIBeam;
FCursorBm:= crHandPoint;
FTimerBlink:= TTimer.Create(Self);
FTimerBlink.Interval:= cInitTimerBlink;
FTimerBlink.OnTimer:= @TimerBlinkTick;
FTimerBlink.Enabled:= true;
FTimerScroll:= TTimer.Create(Self);
FTimerScroll.Interval:= cInitTimerAutoScroll;
FTimerScroll.OnTimer:= @TimerScrollTick;
FTimerScroll.Enabled:= false;
FTimerNiceScroll:= TTimer.Create(Self);
FTimerNiceScroll.Interval:= cInitTimerNiceScroll;
FTimerNiceScroll.OnTimer:= @TimerNiceScrollTick;
FTimerNiceScroll.Enabled:= false;
FBitmap:= Graphics.TBitmap.Create;
FBitmap.PixelFormat:= pf24bit;
FBitmap.Width:= cInitBitmapWidth;
FBitmap.Height:= cInitBitmapHeight;
FStringsExternal:= nil;
FStringsInt:= TATStrings.Create;
FStringsInt.OnGetCaretsArray:= @GetCaretsArray;
FStringsInt.OnSetCaretsArray:= @SetCaretsArray;
FFold:= TATSynRanges.Create;
FFoldStyle:= cInitFoldStyle;
FWrapInfo:= TATSynWrapInfo.Create;
FWrapInfo.OnCheckLineCollapsed:= @IsLineFoldedFull;
FWrapUpdateNeeded:= true;
FWrapMode:= cWrapOn;
FWrapColumn:= cInitMarginRight;
FWrapIndented:= true;
//FWrapProgress:= 0;
FOverwrite:= false;
FTabSize:= cInitTabSize;
FMarginRight:= cInitMarginRight;
FMarginList:= TList.Create;
FUnprintedVisible:= true;
FUnprintedSpaces:= true;
FUnprintedEnds:= true;
FUnprintedEndsDetails:= true;
FUnprintedReplaceSpec:= true;
FTextLocked:= 'wait...';
FTextHint:= '';
FTextHintFontStyle:= [fsItalic];
FTextHintCenter:= false;
FGutter:= TATGutter.Create;
FOptGutterVisible:= true;
FOptGutterPlusSize:= cInitGutterPlusSize;
FOptGutterShowFoldAlways:= true;
FOptGutterShowFoldLines:= true;
FOptGutterShowFoldLinesAll:= false;
FGutterBandBm:= 0;
FGutterBandNum:= 1;
FGutterBandState:= 2;
FGutterBandFold:= 3;
FGutterBandSep:= 4;
FGutterBandEmpty:= 5;
for i:= 1 to cGutterBands do
FGutter.Add(10);
FGutter[FGutterBandBm].Size:= cGutterSizeBm;
FGutter[FGutterBandNum].Size:= cGutterSizeNum;
FGutter[FGutterBandState].Size:= cGutterSizeState;
FGutter[FGutterBandFold].Size:= cGutterSizeFold;
FGutter[FGutterBandSep].Size:= cGutterSizeSep;
FGutter[FGutterBandEmpty].Size:= cGutterSizeEmpty;
FGutter[FGutterBandSep].Visible:= false;
FGutter.Update;
FOptNumbersAutosize:= true;
FOptNumbersAlignment:= taRightJustify;
FOptNumbersFontSize:= 0;
FOptNumbersStyle:= cInitNumbersStyle;
FOptNumbersShowFirst:= true;
FOptNumbersShowCarets:= false;
FOptNumbersSkippedChar:= '.';
FOptNumbersIndentLeft:= 5;
FOptNumbersIndentRight:= 5;
FOptRulerVisible:= true;
FOptRulerSize:= cSizeRulerHeight;
FOptRulerMarkSizeSmall:= cSizeRulerMarkSmall;
FOptRulerMarkSizeBig:= cSizeRulerMarkBig;
FOptRulerFontSize:= 8;
FOptRulerTextIndent:= 0;
FMinimapWidth:= cInitMinimapWidth;
FMinimapCharWidth:= 0;
FMinimapVisible:= cInitMinimapVisible;
FMinimapShowSelBorder:= false;
FMinimapShowSelAlways:= true;
FMicromapWidth:= cInitMicromapWidth;
FMicromapVisible:= cInitMicromapVisible;
FCharSpacingText:= Point(0, cInitSpacingText);
FCharSizeMinimap:= Point(1, 2);
FOptShowStapleStyle:= cLineStyleSolid;
FOptShowStapleIndent:= -1;
FOptShowStapleWidthPercent:= 100;
FOptMaxLinesToCountUnindent:= 100;
FOptTextOffsetTop:= 0;
FOptTextOffsetFromLine:= cInitTextOffsetFromLine;
FOptAllowScrollbarVert:= true;
FOptAllowScrollbarHorz:= true;
FOptAllowZooming:= true;
FOptAllowReadOnly:= true;
FOptKeyBackspaceUnindent:= true;
FOptKeyPageKeepsRelativePos:= true;
FOptKeyUpDownNavigateWrapped:= true;
FOptKeyHomeEndNavigateWrapped:= true;
FOptKeyUpDownKeepColumn:= true;
FOptOverwriteAllowedOnPaste:= false;
FOptWordChars:= '';
FOptAutoIndent:= true;
FOptAutoIndentKind:= cIndentAsIs;
FOptTabSpaces:= false;
FOptLastLineOnTop:= false;
FOptOverwriteSel:= true;
FOptMouseDragDrop:= true;
FOptMouseNiceScroll:= true;
FOptMouseHideCursor:= false;
FOptMouse2ClickSelectsLine:= false;
FOptMouse3ClickSelectsLine:= true;
FOptMouse2ClickDragSelectsWords:= true;
FOptMouseRightClickMovesCaret:= false;
FOptMouseGutterClickSelectsLine:= true;
FOptCopyLinesIfNoSel:= true;
FOptCutLinesIfNoSel:= false;
FOptShowFullSel:= false;
FOptShowFullHilite:= true;
FOptShowCurLine:= false;
FOptShowCurLineMinimal:= true;
FOptShowCurColumn:= false;
FOptKeyPageUpDownSize:= cPageSizeFullMinus1;
FOptKeyLeftRightSwapSel:= true;
FOptKeyLeftRightSwapSelAndSelect:= false;
FOptKeyHomeToNonSpace:= true;
FOptKeyEndToNonSpace:= true;
FOptKeyTabIndents:= true;
FOptShowIndentLines:= true;
FOptShowGutterCaretBG:= true;
FOptIndentSize:= 2;
FOptIndentKeepsAlign:= true;
FOptUndoGrouped:= true;
FOptSavingForceFinalEol:= false;
FOptSavingTrimSpaces:= false;
FOptShowScrollHint:= false;
FOptCaretPreferLeftSide:= true;
FOptMarkersSize:= 4;
FOptMouseDownForPopup:= false;
FOptMouseEnableNormalSelection:= true;
FOptMouseEnableColumnSelection:= true;
FMouseDownPnt:= Point(-1, -1);
FMouseDownNumber:= -1;
FMouseDownDouble:= false;
FMouseDownRight:= false;
FMouseDragDropping:= false;
FMouseNiceScrollPos:= Point(0, 0);
FSelRect:= cRectEmpty;
FCursorOnMinimap:= false;
FCursorOnGutter:= false;
FLastTextCmd:= 0;
FLastTextCmdText:= '';
DoClearScrollInfo(FScrollHorz);
DoClearScrollInfo(FScrollVert);
FKeymap:= KeymapFull;
FHintWnd:= THintWindow.Create(Self);
FMenuStd:= TPopupMenu.Create(Self);
FMenuText:= nil;
FMenuGutterBm:= nil;
FMenuGutterNum:= nil;
FMenuGutterFold:= nil;
FMenuGutterFoldStd:= nil;
FMenuMinimap:= nil;
FMenuMicromap:= nil;
FMenuRuler:= nil;
DoInitPopupMenu;
end;
destructor TATSynEdit.Destroy;
begin
FreeAndNil(FHintWnd);
FreeAndNil(FMenuStd);
DoPaintModeStatic;
FreeAndNil(FFold);
FreeAndNil(FTimerNiceScroll);
FreeAndNil(FTimerScroll);
FreeAndNil(FTimerBlink);
FreeAndNil(FCarets);
FreeAndNil(FMarkedRange);
FreeAndNil(FMarkers);
FreeAndNil(FAttribs);
FreeAndNil(FGutter);
FreeAndNil(FMarginList);
FreeAndNil(FWrapInfo);
FreeAndNil(FStringsInt);
FreeAndNil(FBitmap);
FreeAndNil(FColors);
inherited;
end;
procedure TATSynEdit.Update(
AUpdateWrapInfo: boolean = false;
AUpdateCaretsCoords: boolean = true);
begin
UpdateCursor;
if AUpdateWrapInfo then
FWrapUpdateNeeded:= true;
Include(FPaintFlags, cPaintUpdateScrollbars);
if AUpdateCaretsCoords then
Include(FPaintFlags, cPaintUpdateCaretsCoords);
Invalidate;
end;
procedure TATSynEdit.SetFocus;
begin
LCLIntf.SetFocus(Handle);
end;
procedure TATSynEdit.LoadFromFile(const AFilename: string);
begin
DoPaintModeStatic;
FCarets.Clear;
FCarets.Add(0, 0);
Strings.Clear;
FWrapInfo.Clear;
FWrapUpdateNeeded:= true;
DoClearScrollInfo(FScrollHorz);
DoClearScrollInfo(FScrollVert);
BeginUpdate;
//show "wait" text
Strings.Clear;
Update(true);
AppProcessMessages;
try
Strings.LoadFromFile(AFilename);
finally
EndUpdate;
end;
Update;
DoPaintModeBlinking;
DoEventChange;
DoEventCarets;
{$ifdef test_foldlist}
DoDebugInitFoldList;
{$endif}
end;
procedure TATSynEdit.SaveToFile(const AFilename: string);
var
Change1, Change2: boolean;
begin
Change1:= false;
Change2:= false;
if FOptSavingForceFinalEol then
Change1:= Strings.ActionEnsureFinalEol;
if FOptSavingTrimSpaces then
Change2:= Strings.ActionTrimSpaces(cTrimRight);
if Change1 or Change2 then
Update(true);
Strings.SaveToFile(AFilename);
DoEventState; //modified
Update;
end;
function TATSynEdit.GetStrings: TATStrings;
begin
if Assigned(FStringsExternal) then
Result:= FStringsExternal
else
Result:= FStringsInt;
end;
procedure TATSynEdit.SetCaretBlinkTime(AValue: integer);
begin
AValue:= Max(AValue, cMinCaretTime);
AValue:= Min(AValue, cMaxCaretTime);
FTimerBlink.Interval:= AValue;
end;
procedure TATSynEdit.SetCharSpacingX(AValue: integer);
begin
if FCharSpacingText.X=AValue then Exit;
FCharSpacingText.X:= AValue;
FWrapUpdateNeeded:= true;
end;
procedure TATSynEdit.SetCharSpacingY(AValue: integer);
begin
if FCharSpacingText.Y=AValue then Exit;
FCharSpacingText.Y:= AValue;
FWrapUpdateNeeded:= true;
end;
procedure TATSynEdit.SetMarginString(AValue: string);
var
S: string;
N: integer;
begin
FMarginList.Clear;
repeat
S:= SGetItem(AValue, ' ');
if S='' then Break;
N:= StrToIntDef(S, 0);
if N<2 then Continue;
FMarginList.Add(pointer{%H-}(N));
until false;
end;
procedure TATSynEdit.SetMicromapVisible(AValue: boolean);
begin
if FMicromapVisible=AValue then Exit;
FMicromapVisible:= AValue;
FWrapUpdateNeeded:= true;
end;
procedure TATSynEdit.SetMinimapVisible(AValue: boolean);
begin
if FMinimapVisible=AValue then Exit;
FMinimapVisible:= AValue;
FWrapUpdateNeeded:= true;
end;
procedure TATSynEdit.SetOneLine(AValue: boolean);
begin
Strings.OneLine:= AValue;
Carets.OneLine:= AValue;
if AValue then
begin
OptGutterVisible:= false;
OptRulerVisible:= false;
OptMinimapVisible:= false;
OptMicromapVisible:= false;
OptCaretVirtual:= false;
OptCaretManyAllowed:= false;
OptUnprintedVisible:= false;
OptWrapMode:= cWrapOff;
OptAllowScrollbarVert:= false;
OptAllowScrollbarHorz:= false;
OptAllowZooming:= false;
OptAllowReadOnly:= false;
OptMouseNiceScroll:= false;
OptMouseDragDrop:= false;
OptMarginRight:= 1000;
OptUndoLimit:= 200;
end;
end;
procedure TATSynEdit.SetReadOnly(AValue: boolean);
begin
if not FOptAllowReadOnly then Exit;
Strings.ReadOnly:= AValue;
end;
procedure TATSynEdit.SetLineTop(AValue: integer);
var
NFrom, NTo, i: integer;
begin
//find exact match
FWrapInfo.FindIndexesOfLineNumber(AValue, NFrom, NTo);
if NFrom>=0 then
begin
FScrollVert.NPos:= NFrom;
Update;
Exit
end;
//find approx match
for i:= 0 to FWrapInfo.Count-1 do
with FWrapInfo.Items[i] do
if NLineIndex>=AValue then
begin
FScrollVert.NPos:= i;
Update;
Exit
end;
end;
procedure TATSynEdit.SetLinesFromTop(AValue: integer);
begin
with FScrollVert do
NPos:= Max(0, NPos + (GetLinesFromTop - AValue));
end;
procedure TATSynEdit.SetStrings(Obj: TATStrings);
begin
FStringsExternal:= Obj;
end;
function TATSynEdit.GetTextOffset: TPoint;
begin
Result.X:= 0;
if FOptGutterVisible then
Inc(Result.X, FGutter.Width);
Result.Y:= FOptTextOffsetTop;
if FOptRulerVisible then
Inc(Result.Y, FOptRulerSize);
end;
function TATSynEdit.GetGutterNumbersWidth(C: TCanvas): integer;
var
Str: atString;
CharSize: integer;
begin
if FOptNumbersFontSize<>0 then
C.Font.Size:= FOptNumbersFontSize;
CharSize:= C.TextWidth('0');
Str:= IntToStr(Max(10, Strings.Count));
Result:=
Length(Str)*CharSize+
FOptNumbersIndentLeft+
FOptNumbersIndentRight;
if FOptNumbersFontSize<>0 then
C.Font.Size:= Font.Size;
end;
function TATSynEdit.GetPageLines: integer;
begin
case FOptKeyPageUpDownSize of
cPageSizeFull: Result:= GetVisibleLines;
cPageSizeFullMinus1: Result:= GetVisibleLines-1;
cPageSizeHalf: Result:= GetVisibleLines div 2;
else
raise Exception.Create('Unknown pagesize');
end;
end;
function TATSynEdit.DoPaint(AFlags: TATSynPaintFlags; ALineFrom: integer): boolean;
var
ARect: TRect;
begin
Result:= false;
if not Assigned(FBitmap) then Exit;
if cPaintUpdateBitmap in AFlags then
begin
DoPaintTo(FBitmap.Canvas, ALineFrom);
if cPaintUpdateCaretsCoords in AFlags then
begin
UpdateCaretsCoords;
//paint margin
if FOptShowCurColumn and (Carets.Count>0) then
DoPaintMarginLineTo(FBitmap.Canvas, Carets[0].CoordX, FColors.MarginCaret);
end;
//paint markers after calc carets
DoPaintMarkersTo(FBitmap.Canvas);
FCaretShown:= false;
DoPaintCarets(FBitmap.Canvas, false);
end;
ARect:= Canvas.ClipRect;
Canvas.CopyRect(ARect, FBitmap.Canvas, ARect);
if cPaintUpdateScrollbars in AFlags then
Result:= UpdateScrollbars;
end;
procedure TATSynEdit.DoPaintLockedWarning(C: TCanvas);
var
Str: string;
begin
C.Brush.Color:= Colors.LockedBG;
C.FillRect(ClientRect);
C.Font.Assign(Self.Font);
Str:= FTextLocked;
C.TextOut(10, 10, Str);
end;
procedure TATSynEdit.Paint;
begin
PaintEx(-1);
end;
procedure TATSynEdit.PaintEx(ALine: integer);
begin
if FPaintLocked>0 then
begin
DoPaintLockedWarning(Canvas);
Exit
end;
//if scrollbars shown, paint again
if DoPaint(FPaintFlags, ALine) then
DoPaint(FPaintFlags, ALine);
Exclude(FPaintFlags, cPaintUpdateBitmap);
end;
procedure TATSynEdit.DoOnResize;
var
SizeX, SizeY: integer;
begin
inherited;
if Assigned(FBitmap) then
begin
SizeX:= (Width div cResizeBitmapStep + 1)*cResizeBitmapStep;
SizeY:= (Height div cResizeBitmapStep + 1)*cResizeBitmapStep;
if (SizeX>FBitmap.Width) or (SizeY>FBitmap.Height) then
begin
FBitmap.SetSize(SizeX, SizeY);
FBitmap.FreeImage; //recommended, else seen black bitmap on bigsize
end;
end;
FWrapUpdateNeeded:= true;
Include(FPaintFlags, cPaintUpdateScrollbars);
Include(FPaintFlags, cPaintUpdateCaretsCoords);
Include(FPaintFlags, cPaintUpdateBitmap);
PaintEx(LineTop);
end;
//needed to remove flickering on resize and mouse-over
procedure TATSynEdit.WMEraseBkgnd(var Msg: TLMEraseBkgnd);
begin
Msg.Result:= 1;
end;
procedure TATSynEdit.DoHintShow;
var
S: string;
P: TPoint;
R: TRect;
begin
if not FOptShowScrollHint then Exit;
S:= cHintScrollPrefix+' '+IntToStr(LineTop+1);
R:= FHintWnd.CalcHintRect(500, S, nil);
P:= ClientToScreen(Point(ClientWidth-(R.Right-R.Left), 0));
OffsetRect(R, P.X, P.Y);
OffsetRect(R, -cHintScrollDx, cHintScrollDx);
FHintWnd.ActivateHint(R, S);
FHintWnd.Invalidate; //for Win
end;
procedure TATSynEdit.DoHintHide;
begin
if Assigned(FHintWnd) then
FHintWnd.Hide;
end;
function TATSynEdit.UpdateScrollInfoFromMessage(const Msg: TLMScroll; var Info: TATSynScrollInfo): boolean;
begin
{
application.MainForm.caption:= format('min %d max %d page %d pos %d',
[info.nmin, info.nmax, info.npage, info.npos]);
}
with Info do
if (NMax-NMin)<NPage then
begin
DoClearScrollInfo(Info);
Exit(true);
end;
case Msg.ScrollCode of
SB_TOP: Info.NPos:= Info.NMin;
SB_BOTTOM: Info.NPos:= Info.NPosLast;
SB_LINEUP: Info.NPos:= Max(Info.NPos-1, Info.NMin);
SB_LINEDOWN: Info.NPos:= Min(Info.NPos+1, Info.NPosLast);
SB_PAGEUP: Info.NPos:= Max(Info.NPos-Info.NPage, Info.NMin);
SB_PAGEDOWN: Info.NPos:= Min(Info.NPos+Info.NPage, Info.NPosLast);
SB_THUMBPOSITION: Info.NPos:= Msg.Pos;
SB_THUMBTRACK:
begin
Info.NPos:= Msg.Pos;
if @Info=@FScrollVert then DoHintShow;
end;
SB_ENDSCROLL:
DoHintHide;
end;
Result:= Msg.ScrollCode<>SB_THUMBTRACK;
end;
procedure TATSynEdit.WMVScroll(var Msg: TLMVScroll);
begin
Include(FPaintFlags, cPaintUpdateCaretsCoords);
UpdateScrollInfoFromMessage(Msg, FScrollVert);
Invalidate;
end;
{ Simple Windows IME support, only tested with Korean }
{$ifdef Windows}
procedure TATSynEdit.WMIME_STARTCOMPOSITION(var Msg: TMessage);
begin
Msg.Result:=-1;
end;
procedure TATSynEdit.WMIME_COMPOSITION(var Msg: TMessage);
var
IMC:HIMC;
imeCode, len:Integer;
p:PWideChar;
res:TATCommandResults;
begin
if not ModeReadOnly then
begin
{ work with GCS_COMPSTR and GCS_RESULTSTR }
if Msg.lParam and GCS_COMPSTR <> 0 then
imeCode := GCS_COMPSTR
else if Msg.lParam and GCS_RESULTSTR <> 0 then
imeCode := GCS_RESULTSTR
else
imeCode := 0;
{ check compositon state }
if imeCode<>0 then
begin
IMC := ImmGetContext(Handle);
try
{ Get Result string length }
len := ImmGetCompositionStringW(IMC,imeCode,nil,0);
GetMem(p,len+2);
try
{ get compositon string }
ImmGetCompositionStringW(IMC,imeCode,p,len);
len := len shr 1;
p[len]:=#0;
{ Insert text and
select text if it is not GCS_RESULTSTR }
res:=DoCommand_TextInsertAtCarets(p, False,
(imeCode=GCS_RESULTSTR) and FOverwrite,
(imeCode<>GCS_RESULTSTR) and (Len>0));
DoCommandResults(res);
finally
FreeMem(p);
end;
finally
ImmReleaseContext(Handle,IMC);
end;
end;
end;
Msg.Result:=-1;
end;
procedure TATSynEdit.WMIME_ENDCOMPOSITION(var Msg: TMessage);
begin
Msg.Result:=-1;
end;
{$endif}
procedure TATSynEdit.WMHScroll(var Msg: TLMHScroll);
begin
Include(FPaintFlags, cPaintUpdateCaretsCoords);
UpdateScrollInfoFromMessage(Msg, FScrollHorz);
Invalidate;
end;
procedure TATSynEdit.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
PCaret: TPoint;
EolPos: boolean;
Index: integer;
begin
inherited;
SetFocus;
PCaret:= ClientPosToCaretPos(Point(X, Y), EolPos);
FCaretSpecPos:= false;
FMouseDownNumber:= -1;
FMouseDragDropping:= false;
FMouseDownRight:= Shift=[ssRight];
if MouseNiceScroll then
begin
MouseNiceScroll:= false;
Exit
end;
if FMinimapVisible and PtInRect(FRectMinimap, Point(X, Y)) then
begin
if PtInRect(GetRectMinimapSel, Point(X, Y)) then
FMouseDragMinimap:= true;
if Shift=[ssLeft] then
begin
DoMinimapClick(Y);
Exit
end;
end;
if PtInRect(FRectMain, Point(X, Y)) then
begin
FMouseDownPnt:= PCaret;
if Shift=[ssMiddle] then
begin
if DoHandleClickEvent(FOnClickMiddle) then Exit;
if FOptMouseNiceScroll then
begin
FMouseNiceScrollPos:= Point(X, Y);
MouseNiceScroll:= true;
end;
Exit
end;
if Shift=[ssLeft] then
begin
FSelRect:= cRectEmpty;
Strings.SetGroupMark;
DoCaretSingleAsIs;
if FOptMouseDragDrop and (GetCaretSelectionIndex(FMouseDownPnt)>=0) and not ModeReadOnly then
begin
FMouseDragDropping:= true;
UpdateCursor;
end
else
begin
if Assigned(FOnClickMoveCaret) then
FOnClickMoveCaret(Self, Point(Carets[0].PosX, Carets[0].PosY), FMouseDownPnt);
DoCaretSingle(FMouseDownPnt.X, FMouseDownPnt.Y);
DoSelect_None;
end;
end;
if Shift=[ssLeft, ssShift] then
begin
FSelRect:= cRectEmpty;
DoCaretSingleAsIs;
Carets[0].SelectToPoint(FMouseDownPnt.X, FMouseDownPnt.Y);
end;
if Shift=[ssLeft, ssXControl] then
begin
FSelRect:= cRectEmpty;
DoCaretAddToPoint(FMouseDownPnt.X, FMouseDownPnt.Y);
end;
if Shift=[ssLeft, ssXControl, ssShift] then
begin
FSelRect:= cRectEmpty;
DoCaretsColumnToPoint(FMouseDownPnt.X, FMouseDownPnt.Y);
end;
if Shift=[ssRight] then
begin
if FOptMouseRightClickMovesCaret then
if GetCaretSelectionIndex(FMouseDownPnt)<0 then
begin
DoCaretSingle(FMouseDownPnt.X, FMouseDownPnt.Y);
DoSelect_None;
Invalidate;
end;
end;
end;
if Shift=[ssRight] then
if FOptMouseDownForPopup then
DoHandleRightClick(X, Y);
if FOptGutterVisible and PtInRect(FRectGutter, Point(X, Y)) then
begin
if Shift=[ssLeft] then
begin
Index:= FGutter.IndexAt(X);
if Index=FGutterBandNum then
begin
if FOptMouseGutterClickSelectsLine then
begin
FSelRect:= cRectEmpty;
FMouseDownNumber:= PCaret.Y;
DoSelect_Line(PCaret);
end;
end
else
if Index=FGutterBandFold then
begin
DoFoldbarClick(PCaret.Y);
end
else
//click on other bands- event
DoEventClickGutter(FGutter.IndexAt(X), PCaret.Y);
end;
end;
if FMicromapVisible and PtInRect(FRectMicromap, Point(X, Y)) then
if Shift=[ssLeft] then
begin
DoEventClickMicromap(X-FRectMicromap.Left, Y-FRectMicromap.Top);
Exit
end;
DoCaretsSort;
DoEventCarets;
Update;
end;
procedure TATSynEdit.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
inherited;
if FMouseDragDropping then
begin
DoDropText;
Update;
end;
FMouseDownPnt:= Point(-1, -1);
FMouseDownNumber:= -1;
FMouseDownDouble:= false;
FMouseDragDropping:= false;
FMouseDragMinimap:= false;
FTimerScroll.Enabled:= false;
//popup menu
if FMouseDownRight then
begin
FMouseDownRight:= false;
if not FOptMouseDownForPopup then
DoHandleRightClick(X, Y);
end;
if Carets.Count=1 then
with Carets[0] do
if EndY>=0 then
if Assigned(FOnClickEndSelect) then
FOnClickEndSelect(Self, Point(EndX, EndY), Point(PosX, PosY));
end;
procedure TATSynEdit.DoHandleRightClick(X, Y: integer);
var
Index: integer;
begin
if PtInRect(FRectMain, Point(X, Y)) then
begin
if Assigned(FMenuText) then
FMenuText.PopUp
else
FMenuStd.PopUp;
end
else
if FOptGutterVisible and PtInRect(FRectGutter, Point(X, Y)) then
begin
Index:= FGutter.IndexAt(X);
if Index=FGutterBandBm then
if Assigned(FMenuGutterBm) then FMenuGutterBm.PopUp;
if Index=FGutterBandNum then
if Assigned(FMenuGutterNum) then FMenuGutterNum.PopUp;
if Index=FGutterBandFold then
if Assigned(FMenuGutterFold) then FMenuGutterFold.PopUp else DoMenuGutterFold;
end
else
if FMinimapVisible and PtInRect(FRectMinimap, Point(X, Y)) then
begin
if Assigned(FMenuMinimap) then FMenuMinimap.PopUp;
end
else
if FMicromapVisible and PtInRect(FRectMicromap, Point(X, Y)) then
begin
if Assigned(FMenuMicromap) then FMenuMicromap.PopUp;
end
else
if FOptRulerVisible and PtInRect(FRectRuler, Point(X, Y)) then
begin
if Assigned(FMenuRuler) then FMenuRuler.PopUp;
end;
end;
procedure TATSynEdit.UpdateCursor;
var
P: TPoint;
RectBm: TRect;
begin
if MouseNiceScroll then Exit;
P:= ScreenToClient(Mouse.CursorPos);
RectBm.Left:= FGutter[FGutterBandBm].Left;
RectBm.Right:= FGutter[FGutterBandBm].Right;
RectBm.Top:= FRectMain.Top;
RectBm.Bottom:= FRectMain.Bottom;
if FMouseDragDropping then
Cursor:= crDrag
else
//if FMouseDragMinimap then
// Cursor:= crSizeNS
//else
if PtInRect(FRectMain, P) then
Cursor:= FCursorText
else
if PtInRect(RectBm, P) then
Cursor:= FCursorBm
else
Cursor:= crDefault;
end;
procedure TATSynEdit.MouseMove(Shift: TShiftState; X, Y: Integer);
var
P: TPoint;
RectNums: TRect;
nIndex: integer;
bOnMinimap, bOnGutter, bEolPos: boolean;
begin
inherited;
P:= Point(X, Y);
UpdateCursor;
//detect cursor on minimap
if FMinimapVisible then
begin
bOnMinimap:= PtInRect(FRectMinimap, P);
if not FMinimapShowSelAlways then
if bOnMinimap<>FCursorOnMinimap then
Invalidate;
FCursorOnMinimap:= bOnMinimap;
end;
//detect cursor on gutter
if FOptGutterVisible then
begin
bOnGutter:= PtInRect(FRectGutter, P);
if not FOptGutterShowFoldAlways then
if bOnGutter<>FCursorOnGutter then
Invalidate;
FCursorOnGutter:= bOnGutter;
end;
//numbers
RectNums.Left:= FGutter[FGutterBandNum].Left;
RectNums.Right:= FGutter[FGutterBandNum].Right;
RectNums.Top:= FRectMain.Top;
RectNums.Bottom:= FRectMain.Bottom;
//start scroll timer
FTimerScroll.Enabled:=
(ssLeft in Shift) and
(not PtInRect(ClientRect, P) or FCursorOnGutter);
FMouseAutoScroll:= cDirNone;
if P.Y<FRectMain.Top then FMouseAutoScroll:= cDirUp else
if P.Y>=FRectMain.Bottom then FMouseAutoScroll:= cDirDown else
if P.X<FRectMain.Left then FMouseAutoScroll:= cDirLeft else
if P.X>=FRectMain.Right then FMouseAutoScroll:= cDirRight;
//mouse dragged on numbers
if PtInRect(RectNums, P) then
begin
if Shift=[ssLeft] then
begin
P:= ClientPosToCaretPos(P, bEolPos);
if (P.Y>=0) and (P.X>=0) then
if FMouseDownNumber>=0 then
begin
DoSelect_LineRange(FMouseDownNumber, P);
DoCaretsSort;
DoEventCarets;
Update;
end;
end;
Exit
end;
//mouse dragged on text
if (not FMouseDragDropping) and (FMouseDownPnt.X>=0) then
if PtInRect(FRectMain, P) then
begin
if ssLeft in Shift then
if Carets.Count>0 then
begin
P:= ClientPosToCaretPos(P, bEolPos);
if P.Y>=0 then
begin
//drag w/out button pressed: single selection
if FOptMouseEnableNormalSelection then
if [ssXControl, ssShift, ssAlt]*Shift=[] then
begin
DoCaretSingleAsIs;
if FMouseDownDouble and FOptMouse2ClickDragSelectsWords then
DoSelect_WordRange(0, FMouseDownPnt, P)
else
DoSelect_CharRange(0, P);
end;
//drag with Ctrl pressed: add selection
if Shift=[ssXControl, ssLeft] then
begin
nIndex:= Carets.IndexOfPosXY(FMouseDownPnt.X, FMouseDownPnt.Y, true);
DoSelect_CharRange(nIndex, P);
end;
//drag with Alt pressed
if FOptMouseEnableColumnSelection then
if Shift=[ssAlt, ssLeft] then
begin
DoCaretSingle(FMouseDownPnt.X, FMouseDownPnt.Y);
DoSelect_None;
DoSelect_ColumnBlock(FMouseDownPnt, P);
end;
DoCaretsSort;
DoEventCarets;
Update;
end;
end;
Exit;
end;
//mouse dragged on minimap
if PtInRect(FRectMinimap, P) then
if FMouseDragMinimap then
begin
if Shift=[ssLeft] then
DoMinimapDrag(Y);
Exit
end;
end;
function TATSynEdit.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): boolean;
begin
Result:= DoMouseWheelAction(Shift, false);
end;
function TATSynEdit.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): boolean;
begin
Result:= DoMouseWheelAction(Shift, true);
end;
function TATSynEdit.DoMouseWheelAction(Shift: TShiftState; AUp: boolean): boolean;
begin
if Shift=[ssCtrl] then
begin
DoSizeChange(AUp);
Result:= true;
end
else
Result:= false;
end;
function TATSynEdit.DoHandleClickEvent(AEvent: TATSynEditClickEvent): boolean;
begin
Result:= false;
if Assigned(AEvent) then
AEvent(Self, Result);
end;
procedure TATSynEdit.DblClick;
begin
inherited;
if DoHandleClickEvent(FOnClickDbl) then Exit;
if FOptMouse2ClickSelectsLine then
DoSelect_Line_ByClick
else
begin
FMouseDownDouble:= true;
DoSelect_Word_ByClick;
end;
DoEventCarets;
end;
procedure TATSynEdit.TripleClick;
begin
inherited;
if DoHandleClickEvent(FOnClickTriple) then Exit;
if FOptMouse3ClickSelectsLine then
DoSelect_Line_ByClick;
end;
procedure TATSynEdit.DoSelect_Word_ByClick;
var
P: TPoint;
EolPos: boolean;
begin
P:= ScreenToClient(Mouse.CursorPos);
if PtInRect(FRectMain, P) then
begin
P:= ClientPosToCaretPos(P, EolPos);
if P.Y<0 then Exit;
DoSelect_Word(P);
Update;
end;
end;
function TATSynEdit.GetCaretManyAllowed: boolean;
begin
Result:= Carets.ManyAllowed;
end;
procedure TATSynEdit.SetCaretManyAllowed(AValue: boolean);
begin
Carets.ManyAllowed:= AValue;
if not AValue then
DoCaretSingleAsIs;
end;
procedure TATSynEdit.DoSelect_Line_ByClick;
var
P: TPoint;
EolPos: boolean;
begin
P:= ScreenToClient(Mouse.CursorPos);
if PtInRect(FRectMain, P) then
begin
P:= ClientPosToCaretPos(P, EolPos);
if P.Y<0 then Exit;
DoSelect_Line(P);
Update;
end;
end;
procedure TATSynEdit.Invalidate;
begin
Include(FPaintFlags, cPaintUpdateBitmap);
inherited;
end;
procedure TATSynEdit.TimerBlinkTick(Sender: TObject);
begin
DoPaintCarets(FBitmap.Canvas, true);
end;
procedure TATSynEdit.TimerScrollTick(Sender: TObject);
var
nIndex: integer;
PClient, PCaret: TPoint;
EolPos: boolean;
begin
PClient:= ScreenToClient(Mouse.CursorPos);
PClient.X:= Max(FRectMain.Left, PClient.X);
PClient.Y:= Max(FRectMain.Top, PClient.Y);
PClient.X:= Min(FRectMain.Right, PClient.X);
PClient.Y:= Min(FRectMain.Bottom, PClient.Y);
case FMouseAutoScroll of
cDirUp: DoScrollByDelta(0, -cSpeedScrollAutoVert);
cDirDown: DoScrollByDelta(0, cSpeedScrollAutoVert);
cDirLeft: DoScrollByDelta(-cSpeedScrollAutoHorz, 0);
cDirRight: DoScrollByDelta(cSpeedScrollAutoHorz, 0);
else Exit;
end;
PCaret:= ClientPosToCaretPos(PClient, EolPos);
if (PCaret.X>=0) and (PCaret.Y>=0) then
if FMouseDownNumber>=0 then
begin
DoSelect_LineRange(FMouseDownNumber, PCaret);
end
else
begin
nIndex:= Carets.IndexOfPosXY(FMouseDownPnt.X, FMouseDownPnt.Y, true);
if nIndex>=0 then
Carets[nIndex].SelectToPoint(PCaret.X, PCaret.Y);
end;
DoCaretsSort;
DoEventCarets;
DoEventScroll;
Update;
end;
procedure TATSynEdit.TimerNiceScrollTick(Sender: TObject);
var
Pnt: TPoint;
Dx, Dy: integer;
Dir: TATDirection;
begin
Pnt:= ScreenToClient(Mouse.CursorPos);
if not PtInRect(FRectMain, Pnt) then Exit;
//delta in pixels
Dx:= Pnt.X-FMouseNiceScrollPos.X;
Dy:= Pnt.Y-FMouseNiceScrollPos.Y;
if (Abs(Dx)<=cBitmapNiceScrollRadius) and
(Abs(Dy)<=cBitmapNiceScrollRadius) then
begin
Cursor:= crNiceScrollNone;
Exit;
end;
if (Dy<0) and (Abs(Dy)>Abs(Dx)) then Dir:= cDirUp else
if (Dy>0) and (Abs(Dy)>Abs(Dx)) then Dir:= cDirDown else
if Dx<0 then Dir:= cDirLeft else
Dir:= cDirRight;
case Dir of
cDirLeft: Cursor:= crNiceScrollLeft;
cDirRight: Cursor:= crNiceScrollRight;
cDirUp: Cursor:= crNiceScrollUp;
cDirDown: Cursor:= crNiceScrollDown;
end;
//delta in chars
Dx:= Sign(Dx)*((Abs(Dx)-cBitmapNiceScrollRadius) div FCharSize.X + 1)*cSpeedScrollNiceHorz;
Dy:= Sign(Dy)*((Abs(Dy)-cBitmapNiceScrollRadius) div FCharSize.Y + 1)*cSpeedScrollNiceVert;
if Dir in [cDirLeft, cDirRight] then
DoScrollByDelta(Dx, 0)
else
DoScrollByDelta(0, Dy);
Invalidate;
end;
procedure TATSynEdit.DoPaintCarets(C: TCanvas; AWithInvalidate: boolean);
var
R: TRect;
i: integer;
Item: TATCaretItem;
Shape: TATSynCaretShape;
begin
if IsCaretBlocked then
begin
if not FCaretShown then Exit;
end;
FCaretShown:= not FCaretShown;
if ModeReadOnly then
Shape:= FCaretShapeRO
else
if ModeOverwrite then
Shape:= FCaretShapeOvr
else
Shape:= FCaretShapeIns;
for i:= 0 to FCarets.Count-1 do
begin
Item:= FCarets[i];
R.Left:= Item.CoordX;
R.Top:= Item.CoordY;
R.Right:= R.Left+FCharSize.X;
R.Bottom:= R.Top+FCharSize.Y;
//caret not visible
if R.Left<0 then Continue;
if R.Top<0 then Continue;
case Shape of
cCaretShapeVertPixels1: begin R.Right:= R.Left+1; end;
cCaretShapeVertPixels2: begin R.Right:= R.Left+2; end;
cCaretShapeVertPixels3: begin R.Right:= R.Left+3; end;
cCaretShapeVertPixels4: begin R.Right:= R.Left+4; end;
cCaretShapeVertPercents10: begin R.Right:= R.Left+Trunc(FCharSize.X*0.10); end;
cCaretShapeVertPercents15: begin R.Right:= R.Left+Trunc(FCharSize.X*0.15); end;
cCaretShapeVertPercents20: begin R.Right:= R.Left+Trunc(FCharSize.X*0.20); end;
cCaretShapeVertPercents25: begin R.Right:= R.Left+Trunc(FCharSize.X*0.25); end;
cCaretShapeVertPercents30: begin R.Right:= R.Left+Trunc(FCharSize.X*0.30); end;
cCaretShapeVertPercents35: begin R.Right:= R.Left+Trunc(FCharSize.X*0.35); end;
cCaretShapeVertPercents40: begin R.Right:= R.Left+Trunc(FCharSize.X*0.40); end;
cCaretShapeVertPercents50: begin R.Right:= R.Left+FCharSize.X div 2; end;
cCaretShapeHorzPixels1: begin R.Top:= R.Bottom-1; end;
cCaretShapeHorzPixels2: begin R.Top:= R.Bottom-2; end;
cCaretShapeHorzPixels3: begin R.Top:= R.Bottom-3; end;
cCaretShapeHorzPixels4: begin R.Top:= R.Bottom-4; end;
cCaretShapeHorzPixels5: begin R.Top:= R.Bottom-5; end;
cCaretShapeHorzPercents10: begin R.Top:= R.Bottom-Trunc(FCharSize.Y*0.10); end;
cCaretShapeHorzPercents15: begin R.Top:= R.Bottom-Trunc(FCharSize.Y*0.15); end;
cCaretShapeHorzPercents20: begin R.Top:= R.Bottom-Trunc(FCharSize.Y*0.20); end;
cCaretShapeHorzPercents25: begin R.Top:= R.Bottom-Trunc(FCharSize.Y*0.25); end;
cCaretShapeHorzPercents30: begin R.Top:= R.Bottom-Trunc(FCharSize.Y*0.30); end;
cCaretShapeHorzPercents35: begin R.Top:= R.Bottom-Trunc(FCharSize.Y*0.35); end;
cCaretShapeHorzPercents40: begin R.Top:= R.Bottom-Trunc(FCharSize.Y*0.40); end;
cCaretShapeHorzPercents50: begin R.Top:= R.Bottom-FCharSize.Y div 2; end;
end;
if IntersectRect(R, R, FRectMain) then
begin
CanvasInvertRect(C, R, FColors.Caret);
//frame-shape: invert second time inner area
if Shape=cCaretShapeFrameFull then
CanvasInvertRect(C, Rect(R.Left+1, R.Top+1, R.Right-1, R.Bottom-1), FColors.Caret);
if AWithInvalidate then
InvalidateRect(Handle, @R, false);
end;
end;
end;
procedure TATSynEdit.DoPaintModeStatic;
begin
FPaintStatic:= true;
FTimerBlink.Enabled:= false;
Invalidate;
end;
procedure TATSynEdit.DoPaintModeBlinking;
begin
FPaintStatic:= false;
if Assigned(FTimerBlink) then
begin
FTimerBlink.Enabled:= false;
FTimerBlink.Enabled:= FCaretBlinkEnabled;
end;
end;
procedure TATSynEdit.DoPaintLineIndent(C: TCanvas;
const ARect: TRect;
ACharSize: TPoint;
ACoordY: integer;
AIndentSize: integer;
AColorBG: TColor;
AScrollPos: integer;
AIndentLines: boolean);
var
i: integer;
RBack: TRect;
begin
if AIndentSize=0 then Exit;
RBack:= Rect(0, 0, AIndentSize*ACharSize.X, ACharSize.Y);
OffsetRect(RBack, ARect.Left-AScrollPos*ACharSize.X, ACoordY);
C.Brush.Color:= AColorBG;
C.FillRect(RBack);
if AIndentLines then
for i:= 0 to AIndentSize-1 do
if i mod FTabSize = 0 then
CanvasDottedVertLine_Alt(C,
FColors.IndentVertLines,
ARect.Left + (i-AScrollPos)*ACharSize.X,
ACoordY,
ACoordY+ACharSize.Y);
end;
procedure TATSynEdit.DoPaintSelectedLineBG(C: TCanvas;
ACharSize: TPoint;
const AVisRect: TRect;
APointLeft: TPoint;
APointText: TPoint;
ALineIndex: integer;
AEolSelected: boolean;
const AScrollHorz: TATSynScrollInfo);
var
NLeft, NRight: integer;
begin
if not IsSelRectEmpty then
begin
if (ALineIndex>=FSelRect.Top) and (ALineIndex<=FSelRect.Bottom) then
begin
NLeft:= APointLeft.X+ACharSize.X*(FSelRect.Left-AScrollHorz.NPos);
NRight:= NLeft+ACharSize.X*(FSelRect.Right-FSelRect.Left);
C.Brush.Color:= FColors.TextSelBG;
C.FillRect(
NLeft,
APointLeft.Y,
NRight,
APointLeft.Y+ACharSize.Y);
end;
end
else
if FOptShowFullSel then
if AEolSelected then
begin
C.Brush.Color:= FColors.TextSelBG;
C.FillRect(
APointText.X,
APointText.Y,
AVisRect.Right,
APointText.Y+ACharSize.Y);
end;
end;
procedure TATSynEdit.DoPaintNiceScroll(C: TCanvas);
begin
if MouseNiceScroll then
C.Draw(
FMouseNiceScrollPos.X - cBitmapNiceScrollRadius,
FMouseNiceScrollPos.Y - cBitmapNiceScrollRadius,
cBitmapNiceScroll);
end;
function TATSynEdit.DoEventCommand(ACommand: integer; const AText: string): boolean;
begin
Result:= false;
if Assigned(FOnCommand) then
FOnCommand(Self, ACommand, AText, Result);
end;
function TATSynEdit.GetCaretBlinkTime: integer;
begin
Result:= FTimerBlink.Interval;
end;
function TATSynEdit.GetWrapInfoIndex(AMousePos: TPoint): integer;
var
NPixels: integer;
begin
Result:= -1;
NPixels:= AMousePos.Y - FRectMain.Top;
Result:= FScrollVert.NPos + NPixels div FCharSize.Y;
if not FWrapInfo.IsIndexValid(Result) then
Result:= -1;
end;
procedure TATSynEdit.DoEventCarets;
begin
if Assigned(FAdapterHilite) then
FAdapterHilite.OnEditorCaretMove(Self);
if Assigned(FOnChangeCaretPos) then
FOnChangeCaretPos(Self);
end;
procedure TATSynEdit.DoEventScroll;
begin
if Assigned(FAdapterHilite) then
FAdapterHilite.OnEditorScroll(Self);
if Assigned(FOnScroll) then
FOnScroll(Self);
end;
procedure TATSynEdit.DoEventChange;
begin
if Assigned(FAdapterHilite) then
FAdapterHilite.OnEditorChange(Self);
if Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TATSynEdit.DoEventState;
begin
if Assigned(FOnChangeState) then
FOnChangeState(Self);
end;
procedure TATSynEdit.DoEventClickGutter(ABandIndex, ALineNumber: integer);
begin
if Assigned(FOnClickGutter) then
FOnClickGutter(Self, ABandIndex, ALineNumber);
end;
procedure TATSynEdit.DoEventClickMicromap(AX, AY: integer);
begin
if Assigned(FOnClickMicromap) then
FOnClickMicromap(Self, AX, AY);
end;
procedure TATSynEdit.DoEventDrawBookmarkIcon(C: TCanvas; ALineNumber: integer; const ARect: TRect);
begin
if Assigned(FOnDrawBookmarkIcon) then
FOnDrawBookmarkIcon(Self, C, ALineNumber, ARect);
end;
procedure TATSynEdit.DoEventBeforeCalcHilite;
begin
if Assigned(FAdapterHilite) then
FAdapterHilite.OnEditorBeforeCalcHilite(Self);
if Assigned(FOnBeforeCalcHilite) then
FOnBeforeCalcHilite(Self);
end;
procedure TATSynEdit.OnCanvasFontChanged(Sender: TObject);
const
cCodeM: Widechar = #$4d; //half-width M
cCodeFullM: Widechar = #$ff2d; //full-width M
{$ifdef windows}
var
sizeSmall, sizeFull: single;
a: ABCFLOAT;
{$endif}
begin
ATStringProc.cCharScaleFullwidth:= ATStringProc.cCharScaleFullwidth_Default;
if assigned(Parent) then
begin
{$ifdef windows}
//half width
if GetCharABCWidthsFloatW(Canvas.Handle, Ord(cCodeM), Ord(cCodeM), a) then
sizeSmall:= Max(1.0, a.abcfA+a.abcfB+a.abcfC)
else
sizeSmall:= 1;
//full width
if GetCharABCWidthsFloatW(Canvas.Handle, Ord(cCodeFullM), Ord(cCodeFullM), a) then
sizeFull:= a.abcfA+a.abcfB+a.abcfC
else
sizeFull:= 1;
ATStringProc.cCharScaleFullwidth:= sizeFull/sizeSmall;
{$else}
ATStringProc.cCharScaleFullwidth:=
Canvas.TextWidth(Utf8Encode(cCodeFullM)) /
Canvas.TextWidth(Utf8Encode(cCodeM));
{$endif}
end;
end;
procedure TATSynEdit.DoSendShowHideToInterface;
begin
inherited DoSendShowHideToInterface;
Canvas.Font.OnChange:=@OnCanvasFontChanged;
OnCanvasFontChanged(Canvas.Font);
end;
procedure TATSynEdit.DoScrollByDelta(Dx, Dy: integer);
begin
with FScrollHorz do
NPos:= Max(0, Min(NPosLast, NPos+Dx));
with FScrollVert do
NPos:= Max(0, Min(NPosLast, NPos+Dy));
end;
procedure TATSynEdit.MenuClick(Sender: TObject);
var
Cmd: integer;
begin
Cmd:= (Sender as TMenuItem).Tag;
if Cmd>0 then
begin
DoCommand(Cmd);
Update;
end;
end;
procedure TATSynEdit.MenuPopup(Sender: TObject);
var
i: integer;
begin
for i:= 0 to FMenuStd.Items.Count-1 do
with FMenuStd.Items[i] do
begin
if Assigned(FKeymap) then
ShortCut:= FKeymap.GetShortcutFromCommand(Tag);
//separator items: hide if read-only, nicer menu
if Caption='-' then
Visible:= not ModeReadOnly;
case Tag of
cCommand_ClipboardCut:
begin
Enabled:= not ModeReadOnly;
Visible:= not ModeReadOnly;
end;
cCommand_ClipboardPaste:
begin
Enabled:= not ModeReadOnly and Clipboard.HasFormat(CF_Text);
Visible:= not ModeReadOnly;
end;
cCommand_TextDeleteSelection:
begin
Enabled:= not ModeReadOnly and Carets.IsSelection;
Visible:= not ModeReadOnly;
end;
cCommand_Undo:
begin
Enabled:= not ModeReadOnly and (UndoCount>0);
Visible:= not ModeReadOnly;
end;
cCommand_Redo:
begin
Enabled:= not ModeReadOnly and (RedoCount>0);
Visible:= not ModeReadOnly;
end;
end;
end;
end;
procedure TATSynEdit.DoInitPopupMenu;
//
procedure Add(const SName: string; Cmd: integer);
var
MI: TMenuItem;
begin
MI:= TMenuItem.Create(FMenuStd);
MI.Caption:= SName;
MI.Tag:= Cmd;
MI.OnClick:= @MenuClick;
FMenuStd.Items.Add(MI);
end;
//
begin
FMenuStd.OnPopup:= @MenuPopup;
Add('Undo', cCommand_Undo);
Add('Redo', cCommand_Redo);
Add('-', 0);
Add('Cut', cCommand_ClipboardCut);
Add('Copy', cCommand_ClipboardCopy);
Add('Paste', cCommand_ClipboardPaste);
Add('Delete', cCommand_TextDeleteSelection);
Add('-', 0);
Add('Select all', cCommand_SelectAll);
end;
//drop selection of 1st caret into mouse-pos
procedure TATSynEdit.DoDropText;
var
P, PosAfter, Shift: TPoint;
X1, Y1, X2, Y2: integer;
bSel, bEolPos: boolean;
Str: atString;
Relation: TATPosRelation;
begin
if Carets.Count<>1 then Exit; //allow only 1 caret
Carets[0].GetRange(X1, Y1, X2, Y2, bSel);
if not bSel then Exit;
DoSelect_None;
//calc insert-pos
P:= ScreenToClient(Mouse.CursorPos);
P:= ClientPosToCaretPos(P, bEolPos);
if P.Y<0 then
begin Beep; Exit end;
//can't drop into selection
Relation:= IsPosInRange(P.X, P.Y, X1, Y1, X2, Y2);
if Relation=cRelateInside then
begin Beep; Exit end;
Str:= Strings.TextSubstring(X1, Y1, X2, Y2);
if Str='' then
begin Beep; Exit end;
//insert before selection?
if Relation=cRelateBefore then
begin
Strings.TextDeleteRange(X1, Y1, X2, Y2, Shift, PosAfter);
Strings.TextInsert(P.X, P.Y, Str, false, Shift, PosAfter);
//select moved text
DoCaretSingle(0, 0);
with Carets[0] do
begin
PosX:= PosAfter.X;
PosY:= PosAfter.Y;
EndX:= P.X;
EndY:= P.Y;
end;
end
else
begin
Strings.TextInsert(P.X, P.Y, Str, false, Shift, PosAfter);
//select moved text
DoCaretSingle(0, 0);
with Carets[0] do
begin
PosX:= PosAfter.X;
PosY:= PosAfter.Y;
EndX:= P.X;
EndY:= P.Y;
end;
Strings.TextDeleteRange(X1, Y1, X2, Y2, Shift, PosAfter);
DoCaretsShift(X1, Y1, Shift.X, Shift.Y, PosAfter);
end;
Update(true);
end;
function TATSynEdit.GetAutoIndentString(APosX, APosY: integer): atString;
var
Str: atString;
NChars, NSpaces: integer;
begin
if not FOptAutoIndent then
begin Result:= ''; Exit end;
Str:= Strings.Lines[APosY];
NChars:= SGetIndentChars(Str); //count of chars in indent
NChars:= Min(APosX, NChars); //limit indent by x-pos
Str:= Copy(Str, 1, NChars);
NSpaces:= Length(STabsToSpaces(Str, FTabSize));
case FOptAutoIndentKind of
cIndentAsIs:
Result:= Str;
cIndentSpaces:
Result:= StringOfChar(' ', NSpaces);
cIndentTabsOnly:
Result:= StringOfChar(#9, NSpaces div FTabSize);
cIndentTabsSpaces:
Result:= StringOfChar(#9, NSpaces div FTabSize) + StringOfChar(' ', NSpaces mod FTabSize);
else
raise Exception.Create('Unknown autoindent-kind');
end;
end;
function TATSynEdit.GetModified: boolean;
begin
Result:= Strings.Modified;
end;
function TATSynEdit.GetOneLine: boolean;
begin
Result:= Strings.OneLine;
end;
function TATSynEdit.GetRedoCount: integer;
begin
Result:= Strings.RedoCount;
end;
function TATSynEdit.GetLinesFromTop: integer;
var
P: TPoint;
begin
if Carets.Count=0 then
begin Result:= 0; Exit end;
with Carets[0] do
P:= Point(PosX, PosY);
P:= CaretPosToClientPos(P);
Result:= (P.Y-FRectMain.Top) div FCharSize.Y;
end;
function TATSynEdit.GetText: atString;
begin
Result:= DoGetTextString;
end;
function TATSynEdit.DoGetTextString: atString;
begin
//TATEdit overrides it
Result:= Strings.TextString;
end;
procedure TATSynEdit.DoMinimapClick(APosY: integer);
var
NItem: integer;
begin
NItem:= (APosY-FRectMinimap.Top) div FCharSizeMinimap.Y + FScrollVertMinimap.NPos;
if FWrapInfo.IsIndexValid(NItem) then
begin
NItem:= Max(0, NItem - GetVisibleLines div 2);
FScrollVert.NPos:= Min(NItem, FScrollVert.NMax);
Update;
end;
end;
procedure TATSynEdit.DoMinimapDrag(APosY: integer);
var
NIndex: integer;
begin
NIndex:= GetMinimapSelTop_PixelsToWrapIndex(APosY);
FScrollVert.NPos:= Max(0, Min(NIndex, FScrollVert.NMax));
Update;
end;
function TATSynEdit.GetUndoLimit: integer;
begin
Result:= Strings.UndoLimit;
end;
procedure TATSynEdit.SetUndoLimit(AValue: integer);
begin
Strings.UndoLimit:= AValue;
end;
function TATSynEdit.GetUndoAfterSave: boolean;
begin
Result:= Strings.UndoAfterSave;
end;
function TATSynEdit.GetUndoCount: integer;
begin
Result:= Strings.UndoCount;
end;
procedure TATSynEdit.SetUndoAfterSave(AValue: boolean);
begin
Strings.UndoAfterSave:= AValue;
end;
procedure TATSynEdit.DoSizeChange(AInc: boolean);
var
NTop: integer;
begin
if not FOptAllowZooming then Exit;
if not AInc then
if Font.Size<=cMinFontSize then Exit;
NTop:= LineTop;
Font.Size:= Font.Size+BoolToPlusMinusOne(AInc);
Update;
AppProcessMessages;
LineTop:= NTop;
Update;
end;
procedure TATSynEdit.BeginUpdate;
begin
Inc(FPaintLocked);
Invalidate;
end;
procedure TATSynEdit.EndUpdate;
begin
Dec(FPaintLocked);
if FPaintLocked=0 then
Invalidate;
end;
function TATSynEdit.TextSelected: atString;
var
X1, Y1, X2, Y2: integer;
bSel: boolean;
begin
Result:= '';
if Carets.Count=0 then Exit;
Carets[0].GetRange(X1, Y1, X2, Y2, bSel);
if bSel then
Result:= Strings.TextSubstring(X1, Y1, X2, Y2);
end;
function TATSynEdit.TextCurrentWord: atString;
var
Str: atString;
Caret: TATCaretItem;
N1, N2: integer;
begin
Result:= '';
if Carets.Count=0 then Exit;
Caret:= Carets[0];
Str:= Strings.Lines[Caret.PosY];
SFindWordBounds(Str, Caret.PosX, N1, N2, OptWordChars);
if N2>N1 then
Result:= Copy(Str, N1+1, N2-N1);
end;
function TATSynEdit.GetMouseNiceScroll: boolean;
begin
Result:= FTimerNiceScroll.Enabled;
end;
procedure TATSynEdit.SetMouseNiceScroll(AValue: boolean);
begin
FTimerNiceScroll.Enabled:= AValue;
if not AValue then
UpdateCursor;
Invalidate;
end;
function TATSynEdit.GetEndOfFilePos: TPoint;
begin
Result.X:= 0;
Result.Y:= 0;
if Strings.Count>0 then
begin
Result.Y:= Strings.Count-1;
Result.X:= Length(Strings.Lines[Result.Y]);
if Strings.LinesEnds[Result.Y]<>cEndNone then
Inc(Result.X);
end;
end;
procedure TATSynEdit.DoPaintGutterFolding(C: TCanvas;
AWrapItemIndex: integer;
ACoordX1, ACoordX2, ACoordY1, ACoordY2: integer);
var
List: TATIntArray;
State: (cFoldbarNone, cFoldbarBegin, cFoldbarEnd, cFoldbarMiddle);
CoordXM, CoordYM: integer;
WrapItem: TATSynWrapItem;
LineIndex: integer;
IsPlus, IsLineUp, IsLineDown: boolean;
i: integer;
//
procedure DrawUp;
begin
if IsLineUp then
C.Line(
CoordXM,
ACoordY1,
CoordXM,
CoordYM
);
end;
procedure DrawDown;
begin
if IsLineDown then
C.Line(
CoordXM,
CoordYM,
CoordXM,
ACoordY2
);
end;
//
begin
if not FOptGutterShowFoldAlways then
if not FCursorOnGutter then Exit;
WrapItem:= FWrapInfo[AWrapItemIndex];
LineIndex:= WrapItem.NLineIndex;
List:= FFold.FindRangesContainingLines(LineIndex, LineIndex, nil,
false{OnlyFolded}, false{TopLevelOnly}, cRngHasAllLines);
if Length(List)=0 then Exit;
//calc state
State:= cFoldbarNone;
IsPlus:= false;
IsLineUp:= false;
IsLineDown:= false;
for i:= Low(List) to High(List) do
with FFold[List[i]] do
begin
if Y<LineIndex then IsLineUp:= true;
if Y2>LineIndex then IsLineDown:= true;
if Y=LineIndex then
begin
State:= cFoldbarBegin;
//don't override found [+], 2 blocks can start at same pos
if not IsPlus then IsPlus:= Folded;
end;
if Y2=LineIndex then
if State<>cFoldbarBegin then
State:= cFoldbarEnd;
end;
//correct state for wrapped line
if State=cFoldbarBegin then
if not FWrapInfo.IsItemInitial(AWrapItemIndex) then
State:= cFoldbarMiddle;
//correct state for wrapped line
if State=cFoldbarEnd then
if WrapItem.NFinal=cWrapItemMiddle then
State:= cFoldbarMiddle;
C.Pen.Color:= IfThen(FOptGutterShowFoldLines,
FColors.GutterFoldLine,
FColors.GutterFoldBG);
CoordXM:= (ACoordX1+ACoordX2) div 2;
CoordYM:= (ACoordY1+ACoordY2) div 2;
case State of
cFoldbarBegin:
begin
if FOptGutterShowFoldLinesAll then
begin DrawUp; DrawDown; end;
if not IsPlus then
DrawDown;
CanvasPaintPlusMinus(C,
FColors.GutterPlusBorder,
FColors.GutterPlusBG,
Point(CoordXM, CoordYM),
FOptGutterPlusSize,
IsPlus);
end;
cFoldbarEnd:
begin
if FOptGutterShowFoldLinesAll then
begin DrawUp; DrawDown; end;
Dec(ACoordY2, cSizeGutterFoldLineDx);
C.Line(
CoordXM,
ACoordY1,
CoordXM,
ACoordY2
);
C.Line(
CoordXM,
ACoordY2,
CoordXM + FOptGutterPlusSize,
ACoordY2
);
end;
cFoldbarMiddle:
begin
C.Line(
CoordXM,
ACoordY1,
CoordXM,
ACoordY2
);
end;
else
begin
DrawUp;
DrawDown;
end;
end;
end;
procedure TATSynEdit.DoPaintTextHintTo(C: TCanvas);
var
Size: TSize;
Pos: TPoint;
begin
C.Brush.Color:= GetColorTextBG;
C.Font.Color:= FColors.TextHintFont;
C.Font.Style:= FTextHintFontStyle;
Size:= C.TextExtent(FTextHint);
if FTextHintCenter then
begin
Pos:= CenterPoint(FRectMain);
Dec(Pos.X, Size.cx div 2);
Dec(Pos.Y, Size.cy div 2);
end
else
begin
Pos:= FTextOffset;
end;
C.TextOut(Pos.X, Pos.Y, FTextHint);
end;
procedure TATSynEdit.WMGetDlgCode(var Msg: TLMNoParams);
begin
inherited;
Msg.Result:= DLGC_WANTARROWS or DLGC_WANTCHARS or DLGC_WANTALLKEYS;
if FWantTabs and (GetKeyState(VK_CONTROL) >= 0) then
Msg.Result:= Msg.Result or DLGC_WANTTAB;
end;
procedure TATSynEdit.DoPaintStaple(C: TCanvas; const R: TRect; AColor: TColor);
begin
if FOptShowStapleStyle=cLineStyleNone then Exit;
CanvasLineEx(C, AColor, FOptShowStapleStyle, Point(R.Left, R.Top), Point(R.Right, R.Top), false);
CanvasLineEx(C, AColor, FOptShowStapleStyle, Point(R.Left, R.Top), Point(R.Left, R.Bottom), false);
CanvasLineEx(C, AColor, FOptShowStapleStyle, Point(R.Left, R.Bottom), Point(R.Right, R.Bottom), true);
end;
procedure TATSynEdit.DoPaintStaples(C: TCanvas; const ARect: TRect;
ACharSize: TPoint; const AScrollHorz: TATSynScrollInfo);
var
nLineFrom, nLineTo, nIndent: integer;
Indexes: TATIntArray;
Range: TATSynRange;
P1, P2: TPoint;
i: integer;
RSt: TRect;
NColor: TColor;
begin
if FOptShowStapleStyle=cLineStyleNone then Exit;
nLineFrom:= LineTop;
nLineTo:= LineBottom;
Indexes:= FFold.FindRangesContainingLines(nLineFrom, nLineTo, nil,
false{OnlyFolded}, false{TopLevelOnly}, cRngHasAnyOfLines);
//c.font.color:= clblue;
//c.textout(arect.right-150, arect.top, format('staples vis %d', [length(indexes)]));
for i:= 0 to High(Indexes) do
begin
Range:= FFold[Indexes[i]];
if not Range.Staple then Continue;
if Range.Folded then Continue;
if IsLineFolded(Range.Y, true) then Continue;
if IsLineFolded(Range.Y2, true) then Continue;
P1:= CaretPosToClientPos(Point(0, Range.Y));
P2:= CaretPosToClientPos(Point(0, Range.Y2));
if (P1.Y<0) and (Range.Y>=nLineFrom) then Continue;
if (P2.Y<0) and (Range.Y2>=nLineFrom) then Continue;
NIndent:= SGetIndentExpanded(Strings.Lines[Range.Y], FTabSize);
Inc(P1.X, NIndent*ACharSize.X);
Inc(P2.X, NIndent*ACharSize.X);
RSt.Left:= P1.X + FOptShowStapleIndent;
RSt.Top:= P1.Y;
RSt.Right:= RSt.Left+ (ACharSize.X * FOptShowStapleWidthPercent div 100);
RSt.Bottom:= P2.Y + ACharSize.Y-1;
if (RSt.Left>=ARect.Left) and
(RSt.Left<ARect.Right) then
begin
NColor:= Colors.BlockStaple;
if Assigned(FOnCalcStaple) then
FOnCalcStaple(Self, Range.Y, NIndent, NColor);
DoPaintStaple(C, RSt, NColor);
end;
end;
end;
function TATSynEdit.IsCharWord(ch: Widechar): boolean;
begin
Result:= ATStringProc.IsCharWord(ch, OptWordChars);
end;
function TATSynEdit.GetColorTextBG: TColor;
begin
if Enabled then
Result:= Colors.TextBG
else
Result:= Colors.TextDisabledBG;
end;
function TATSynEdit.GetColorTextFont: TColor;
begin
if Enabled then
Result:= Colors.TextFont
else
Result:= Colors.TextDisabledFont;
end;
procedure TATSynEdit.DoPaintMarkersTo(C: TCanvas);
var
M: TATMarkerItem;
i: integer;
begin
for i:= 0 to Markers.Count-1 do
begin
M:= Markers[i];
if M.CoordX<0 then Continue;
if M.CoordY<0 then Continue;
if not PtInRect(FRectMain, Point(M.CoordX, M.CoordY)) then Continue;
C.Brush.Color:= Colors.Markers;
C.Pen.Color:= Colors.Markers;
C.Polygon([
Point(M.CoordX, M.CoordY+FCharSize.Y-FOptMarkersSize-1),
Point(M.CoordX-FOptMarkersSize, M.CoordY+FCharSize.Y-1),
Point(M.CoordX+FOptMarkersSize, M.CoordY+FCharSize.Y-1) ]);
end;
end;
procedure TATSynEdit.DoDebugAddAttribs;
var
p1, p2, p3: TATLinePartClass;
begin
p1:= TATLinePartClass.Create;
p2:= TATLinePartClass.Create;
p3:= TATLinePartClass.Create;
p1.Data.ColorBG:= clgreen;
p1.Data.ColorFont:= clwhite;
p1.data.BorderDown:= cLineStyleDotted;
Attribs.Add(1,1, 0, 4, p1);
p2.Data.ColorBG:= clYellow;
p2.Data.ColorFont:= clBlue;
p2.data.BorderDown:= cLineStyleSolid;
Attribs.Add(2,2, 0, 4, p2);
p3.Data.ColorBG:= clRed;
p3.Data.ColorFont:= clYellow;
Attribs.Add(3,3, 0, 4, p3);
end;
procedure TATSynEdit.DoSetMarkedLines(ALine1, ALine2: integer);
begin
FMarkedRange.Clear;
if (ALine1>=0) and (ALine2>=ALine1) then
begin
FMarkedRange.Add(0, ALine1);
FMarkedRange.Add(0, ALine2);
end;
end;
procedure TATSynEdit.DoGetMarkedLines(out ALine1, ALine2: integer);
begin
ALine1:= -1;
ALine2:= -1;
if FMarkedRange.Count=2 then
begin
ALine1:= FMarkedRange.Items[0].PosY;
ALine2:= FMarkedRange.Items[1].PosY;
end;
end;
{$I atsynedit_carets.inc}
{$I atsynedit_hilite.inc}
{$I atsynedit_sel.inc}
{$I atsynedit_fold.inc}
{$I atsynedit_debug.inc}
{$R res/nicescroll.res}
{$R res/foldbar.res}
{$I atsynedit_cmd_handler.inc}
{$I atsynedit_cmd_keys.inc}
{$I atsynedit_cmd_sel.inc}
{$I atsynedit_cmd_editing.inc}
{$I atsynedit_cmd_clipboard.inc}
{$I atsynedit_cmd_misc.inc}
initialization
InitClipboardFormat;
InitResourcesNicescroll;
finalization
FreeResources;
end.