~ubuntu-branches/ubuntu/saucy/lazarus/saucy

« back to all changes in this revision

Viewing changes to components/synedit/synedit.pp

  • Committer: Package Import Robot
  • Author(s): Paul Gevers, Abou Al Montacir, Bart Martens, Paul Gevers
  • Date: 2013-06-08 14:12:17 UTC
  • mfrom: (1.1.9)
  • Revision ID: package-import@ubuntu.com-20130608141217-7k0cy9id8ifcnutc
Tags: 1.0.8+dfsg-1
[ Abou Al Montacir ]
* New upstream major release and multiple maintenace release offering many
  fixes and new features marking a new milestone for the Lazarus development
  and its stability level.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_fixes_branch
* LCL changes:
  - LCL is now a normal package.
      + Platform independent parts of the LCL are now in the package LCLBase
      + LCL is automatically recompiled when switching the target platform,
        unless pre-compiled binaries for this target are already installed.
      + No impact on existing projects.
      + Linker options needed by LCL are no more added to projects that do
        not use the LCL package.
  - Minor changes in LCL basic classes behaviour
      + TCustomForm.Create raises an exception if a form resource is not
        found.
      + TNotebook and TPage: a new implementation of these classes was added.
      + TDBNavigator: It is now possible to have focusable buttons by setting
        Options = [navFocusableButtons] and TabStop = True, useful for
        accessibility and for devices with neither mouse nor touch screen.
      + Names of TControlBorderSpacing.GetSideSpace and GetSpace were swapped
        and are now consistent. GetSideSpace = Around + GetSpace.
      + TForm.WindowState=wsFullscreen was added
      + TCanvas.TextFitInfo was added to calculate how many characters will
        fit into a specified Width. Useful for word-wrapping calculations.
      + TControl.GetColorResolvingParent and
        TControl.GetRGBColorResolvingParent were added, simplifying the work
        to obtain the final color of the control while resolving clDefault
        and the ParentColor.
      + LCLIntf.GetTextExtentExPoint now has a good default implementation
        which works in any platform not providing a specific implementation.
        However, Widgetset specific implementation is better, when available.
      + TTabControl was reorganized. Now it has the correct class hierarchy
        and inherits from TCustomTabControl as it should.
  - New unit in the LCL:
      + lazdialogs.pas: adds non-native versions of various native dialogs,
        for example TLazOpenDialog, TLazSaveDialog, TLazSelectDirectoryDialog.
        It is used by widgetsets which either do not have a native dialog, or
        do not wish to use it because it is limited. These dialogs can also be
        used by user applications directly.
      + lazdeviceapis.pas: offers an interface to more hardware devices such
        as the accelerometer, GPS, etc. See LazDeviceAPIs
      + lazcanvas.pas: provides a TFPImageCanvas descendent implementing
        drawing in a LCL-compatible way, but 100% in Pascal.
      + lazregions.pas. LazRegions is a wholly Pascal implementation of
        regions for canvas clipping, event clipping, finding in which control
        of a region tree one an event should reach, for drawing polygons, etc.
      + customdrawncontrols.pas, customdrawndrawers.pas,
        customdrawn_common.pas, customdrawn_android.pas and
        customdrawn_winxp.pas: are the Lazarus Custom Drawn Controls -controls
        which imitate the standard LCL ones, but with the difference that they
        are non-native and support skinning.
  - New APIs added to the LCL to improve support of accessibility software
    such as screen readers.
* IDE changes:
  - Many improvments.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/New_IDE_features_since#v1.0_.282012-08-29.29
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes#IDE_Changes
* Debugger / Editor changes:
  - Added pascal sources and breakpoints to the disassembler
  - Added threads dialog.
* Components changes:
  - TAChart: many fixes and new features
  - CodeTool: support Delphi style generics and new syntax extensions.
  - AggPas: removed to honor free licencing. (Closes: Bug#708695)
[Bart Martens]
* New debian/watch file fixing issues with upstream RC release.
[Abou Al Montacir]
* Avoid changing files in .pc hidden directory, these are used by quilt for
  internal purpose and could lead to surprises during build.
[Paul Gevers]
* Updated get-orig-source target and it compinion script orig-tar.sh so that they
  repack the source file, allowing bug 708695 to be fixed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
If you do not delete the provisions above, a recipient may use your version
28
28
of this file under either the MPL or the GPL.
29
29
 
30
 
$Id: synedit.pp 32529 2011-09-27 21:47:07Z juha $
 
30
$Id: synedit.pp 39722 2013-01-02 07:33:59Z martin $
31
31
 
32
32
You may retrieve the latest version of this file at the SynEdit home page,
33
33
located at http://SynEdit.SourceForge.net
38
38
  -Font.CharSet
39
39
  -THintWindow
40
40
  -DragAcceptFiles
41
 
  -Font DBCS / MBCS  double, multi byte character set
42
41
 
43
42
-------------------------------------------------------------------------------}
44
43
 
45
44
unit SynEdit;
46
 
 
 
45
{$IFDEF Windows} {$IFnDEF WINCE}
 
46
  {$IFnDEF WithoutWinIME}
 
47
    {$DEFINE WinIME}
 
48
    {$DEFINE WinIMEFull}
 
49
  {$ENDIF}
 
50
{$ENDIF} {$ENDIF}
47
51
 
48
52
{$I synedit.inc}
49
53
 
 
54
 
50
55
{$IFDEF LCLGTK1}
51
56
{$DEFINE EnableDoubleBuf} // gtk1 does not have double buffering
52
57
{$ENDIF}
57
62
 
58
63
interface
59
64
 
 
65
{ $DEFINE SYNSCROLLDEBUG}
60
66
{ $DEFINE VerboseKeys}
61
67
{ $DEFINE VerboseSynEditInvalidate}
62
68
{ $DEFINE SYNDEBUGPRINT}
 
69
{$IFDEF SynUndoDebug}
 
70
  {$Define SynUndoDebugItems}
 
71
  {$Define SynUndoDebugCalls}
 
72
{$ENDIF}
63
73
 
64
74
uses
 
75
  {$IFDEF WinIME}
 
76
  LazSynIMM,
 
77
  {$ENDIF}
65
78
  {$IFDEF USE_UTF8BIDI_LCL}
66
79
  FreeBIDI, utf8bidi,
67
80
  {$ENDIF}
68
 
  Types, LCLIntf, LCLType, LMessages, LCLProc,
 
81
  Types, LCLIntf, LCLType, LMessages, LazUTF8, LCLProc,
69
82
  SysUtils, Classes, Messages, Controls, Graphics, Forms, StdCtrls, ExtCtrls, Menus,
70
 
  {$IFDEF SYN_MBCSSUPPORT}
71
 
  Imm,
72
 
  {$ENDIF}
73
83
  SynEditTypes, SynEditSearch, SynEditKeyCmds, SynEditMouseCmds, SynEditMiscProcs,
74
84
  SynEditPointClasses, SynBeautifier, SynEditMarks,
 
85
  // Markup
75
86
  SynEditMarkup, SynEditMarkupHighAll, SynEditMarkupBracket, SynEditMarkupWordGroup,
76
87
  SynEditMarkupCtrlMouseLink, SynEditMarkupSpecialLine, SynEditMarkupSelection,
77
 
  SynEditTextBase, SynEditTextTrimmer, SynEditFoldedView, SynEditTextTabExpander,
78
 
  SynEditTextDoubleWidthChars,
 
88
  SynEditMarkupSpecialChar,
 
89
  // Lines
 
90
  SynEditTextBase, LazSynEditText, SynEditTextBuffer, SynEditLines,
 
91
  SynEditTextTrimmer, SynEditTextTabExpander, SynEditTextDoubleWidthChars,
 
92
  SynEditFoldedView,
 
93
  // Gutter
79
94
  SynGutterBase, SynGutter, SynGutterCodeFolding, SynGutterChanges,
80
95
  SynGutterLineNumber, SynGutterMarks, SynGutterLineOverview,
81
 
  SynEditMiscClasses, SynEditTextBuffer, SynEditHighlighter, SynTextDrawer,
82
 
  SynEditLines,
 
96
  SynEditMiscClasses, SynEditHighlighter, LazSynTextArea, SynTextDrawer,
83
97
  LResources, Clipbrd
84
98
  {$IFDEF SYN_COMPILER_4_UP}
85
99
  , StdActns
87
101
  ;
88
102
 
89
103
const
90
 
  DIGIT = ['0'..'9'];
91
 
// ALPHA            = ['A'..'Z', 'a'..'z'];
92
 
// break these up because we exceed the 4 byte limit when combined.
93
 
  ALPHA_UC = ['A'..'Z'];
94
 
  ALPHA_LC = ['a'..'z'];
95
 
 
96
104
  ScrollBarWidth=0;
97
105
 
98
106
  // SynDefaultFont is determined in InitSynDefaultFont()
99
107
  SynDefaultFontName:    String       = '';
100
108
  SynDefaultFontHeight:  Integer      = 13;
 
109
  SynDefaultFontSize:    Integer      = 10;
101
110
  SynDefaultFontPitch:   TFontPitch   = fpFixed;
102
111
  SynDefaultFontQuality: TFontQuality = fqNonAntialiased;
103
112
 
109
118
  // maximum scroll range
110
119
  MAX_SCROLL = 32767;
111
120
 
112
 
{$IFDEF SYN_MBCSSUPPORT}
113
 
{$IFNDEF SYN_COMPILER_4_UP}
114
 
{Windows.pas in D4}
115
 
const
116
 
  C3_NONSPACING = 1;    { nonspacing character }
117
 
  C3_DIACRITIC = 2;     { diacritic mark }
118
 
  C3_VOWELMARK = 4;     { vowel mark }
119
 
  C3_SYMBOL = 8;        { symbols }
120
 
  C3_KATAKANA = $0010;  { katakana character }
121
 
  C3_HIRAGANA = $0020;  { hiragana character }
122
 
  C3_HALFWIDTH = $0040; { half width character }
123
 
  C3_FULLWIDTH = $0080; { full width character }
124
 
  C3_IDEOGRAPH = $0100; { ideographic character }
125
 
  C3_KASHIDA = $0200;   { Arabic kashida character }
126
 
  C3_LEXICAL = $0400;   { lexical character }
127
 
  C3_ALPHA = $8000;     { any linguistic char (C1_ALPHA) }
128
 
  C3_NOTAPPLICABLE = 0; { ctype 3 is not applicable }
129
 
{$ENDIF}
130
 
{$ENDIF}
131
 
 
132
121
type
133
122
  TSynEditMarkupClass = SynEditMarkup.TSynEditMarkupClass;
134
123
  TSynReplaceAction = (raCancel, raSkip, raReplace, raReplaceAll);
140
129
    var Handled: boolean; var Command: TSynEditorCommand;
141
130
    var AChar: TUTF8Char;
142
131
    Data: pointer; HandlerData: pointer) of object;
 
132
  THookedCommandFlag = (
 
133
    hcfInit,     // run before On[User]CommandProcess (outside UndoBlock / should not do execution)
 
134
    hcfPreExec,  // Run before CommandProcessor (unless handled by On[User]CommandProcess)
 
135
    hcfPostExec, // Run after CommandProcessor (unless handled by On[User]CommandProcess)
 
136
    hcfFinish    // Run at the very end
 
137
  );
 
138
  THookedCommandFlags = set of THookedCommandFlag;
143
139
 
144
140
  THookedKeyTranslationEvent = procedure(Sender: TObject;
145
141
    Code: word; SState: TShiftState; var Data: pointer; var IsStartOfCombo: boolean;
164
160
    var AnAction: TSynCopyPasteAction) of object;
165
161
 
166
162
  TSynEditCaretType = SynEditPointClasses.TSynCaretType;
 
163
 
167
164
  TSynCaretAdjustMode = ( // used in TextBetweenPointsEx
168
165
    scamIgnore, // Caret stays at the same numeric values, if text is inserted before caret, the text moves, but the caret stays
169
166
    scamAdjust, // Caret moves with text, if text is inserted
171
168
    scamBegin
172
169
  );
173
170
 
 
171
  (* This is used, if text is *replaced*.
 
172
     What to do with marks in text that is deleted/replaced
 
173
  *)
 
174
  TSynMarksAdjustMode = ( // used in SetTextBetweenPoints
 
175
    smaMoveUp, //
 
176
    smaKeep
 
177
    // smaDrop
 
178
  );
 
179
 
 
180
  TSynEditTextFlag = (
 
181
    setSelect // select the new text
 
182
  );
 
183
  TSynEditTextFlags = set of TSynEditTextFlag;
 
184
 
174
185
  TSynStateFlag = (sfCaretChanged, sfHideCursor,
175
186
    sfEnsureCursorPos, sfEnsureCursorPosAtResize,
176
187
    sfIgnoreNextChar, sfPainting, sfHasScrolled,
180
191
    sfLeftGutterClick, sfRightGutterClick,
181
192
    sfDblClicked, sfTripleClicked, sfQuadClicked,
182
193
    sfWaitForDragging, sfIsDragging, sfWaitForMouseSelecting, sfMouseSelecting, sfMouseDoneSelecting,
183
 
    sfIgnoreUpClick
 
194
    sfIgnoreUpClick,
 
195
    sfSelChanged
184
196
    );                                           //mh 2000-10-30
185
197
  TSynStateFlags = set of TSynStateFlag;
186
198
 
187
199
  TSynEditorOption = (
188
 
    eoAltSetsColumnMode,       // DEPRECATED, now controlled vie MouseActions
189
 
                               // Holding down the Alt Key will put the selection mode into columnar format
190
200
    eoAutoIndent,              // Will indent the caret on new lines with the same amount of leading white space as the preceding line
191
 
    eoAutoSizeMaxScrollWidth,  //TODO Automatically resizes the MaxScrollWidth property when inserting text
192
 
    eoDisableScrollArrows,     //TODO Disables the scroll bar arrow buttons when you can't scroll in that direction any more
193
 
    eoDragDropEditing,         // DEPRECATED, now controlled vie MouseActions
194
 
                               // Allows you to select a block of text and drag it within the document to another location
195
 
    eoDropFiles,               //TODO Allows the editor accept file drops
 
201
    eoBracketHighlight,        // Highlight matching bracket
196
202
    eoEnhanceHomeKey,          // home key jumps to line start if nearer, similar to visual studio
197
203
    eoGroupUndo,               // When undoing/redoing actions, handle all continous changes of the same kind in one call instead undoing/redoing each command separately
198
204
    eoHalfPageScroll,          // When scrolling with page-up and page-down commands, only scroll a half page at a time
199
 
    eoHideShowScrollbars,      //TODO if enabled, then the scrollbars will only show when necessary.  If you have ScrollPastEOL, then it the horizontal bar will always be there (it uses MaxLength instead)
 
205
    eoHideRightMargin,         // Hides the right margin line
200
206
    eoKeepCaretX,              // When moving through lines w/o Cursor Past EOL, keeps the X position of the cursor
201
207
    eoNoCaret,                 // Makes it so the caret is never visible
202
208
    eoNoSelection,             // Disables selecting text
203
 
    eoRightMouseMovesCursor,   // DEPRECATED, now controlled vie MouseActions
204
 
                               // When clicking with the right mouse for a popup menu, move the cursor to that location
 
209
    eoPersistentCaret,         // Do not hide caret when focus lost // TODO: Windows may hide it, if another component sets up a caret
205
210
    eoScrollByOneLess,         // Forces scrolling to be one less
206
 
    eoScrollHintFollows,       //TODO The scroll hint follows the mouse when scrolling vertically
207
211
    eoScrollPastEof,           // Allows the cursor to go past the end of file marker
208
212
    eoScrollPastEol,           // Allows the cursor to go past the last character into the white space at the end of a line
 
213
    eoScrollHintFollows,       // The scroll hint follows the mouse when scrolling vertically
209
214
    eoShowScrollHint,          // Shows a hint of the visible line numbers when scrolling vertically
210
215
    eoShowSpecialChars,        // Shows the special Characters
211
 
    eoSmartTabDelete,          //TODO similar to Smart Tabs, but when you delete characters
212
216
    eoSmartTabs,               // When tabbing, the cursor will go to the next non-white space character of the previous line
213
 
    //eoSpecialLineDefaultFg,    //TODO disables the foreground text color override when using the OnSpecialLineColor event
214
217
    eoTabIndent,               // When active <Tab> and <Shift><Tab> act as block indent, unindent when text is selected
215
218
    eoTabsToSpaces,            // Converts a tab character to a specified number of space characters
216
219
    eoTrimTrailingSpaces,      // Spaces at the end of lines will be trimmed and not saved
217
 
    eoBracketHighlight,        // Highlight matching bracket
218
 
    eoDoubleClickSelectsLine,  // DEPRECATED
219
 
                               // Select line on double click
220
 
    eoHideRightMargin,         // Hides the right margin line
221
 
    eoPersistentCaret,         // Do not hide caret when focus lost // TODO: Windows may hide it, if another component sets up a caret
222
 
    eoShowCtrlMouseLinks,      // DEPRECATED, now controlled vie MouseActions
223
 
                               // Pressing Ctrl (SYNEDIT_LINK_MODIFIER) will highlight the word under the mouse cursor
 
220
 
 
221
    // Not implemented
 
222
    eoAutoSizeMaxScrollWidth,  //TODO Automatically resizes the MaxScrollWidth property when inserting text
 
223
    eoDisableScrollArrows,     //TODO Disables the scroll bar arrow buttons when you can't scroll in that direction any more
 
224
    eoHideShowScrollbars,      //TODO if enabled, then the scrollbars will only show when necessary.  If you have ScrollPastEOL, then it the horizontal bar will always be there (it uses MaxLength instead)
 
225
    eoDropFiles,               //TODO Allows the editor accept file drops
 
226
    eoSmartTabDelete,          //TODO similar to Smart Tabs, but when you delete characters
 
227
    eoSpacesToTabs,            // Converts space characters to tabs and spaces
224
228
    eoAutoIndentOnPaste,       // Indent text inserted from clipboard
225
 
    eoSpacesToTabs             // Converts space characters to tabs and spaces
 
229
    //eoSpecialLineDefaultFg,    //TODO disables the foreground text color override when using the OnSpecialLineColor event
 
230
 
 
231
    // Only for compatibility, moved to TSynEditorMouseOptions
 
232
    // keep in one block
 
233
    eoAltSetsColumnMode,       //
 
234
    eoDragDropEditing,         // Allows you to select a block of text and drag it within the document to another location
 
235
    eoRightMouseMovesCursor,   // When clicking with the right mouse for a popup menu, move the cursor to that location
 
236
    eoDoubleClickSelectsLine,  // Select line on double click
 
237
    eoShowCtrlMouseLinks       // Pressing Ctrl (SYNEDIT_LINK_MODIFIER) will highlight the word under the mouse cursor
226
238
    );
227
239
  TSynEditorOptions = set of TSynEditorOption;
228
240
 
238
250
  );
239
251
  TSynEditorOptions2 = set of TSynEditorOption2;
240
252
 
 
253
  TSynEditorMouseOption = SynEditMouseCmds.TSynEditorMouseOption;
 
254
    //emUseMouseActions,
 
255
    //emAltSetsColumnMode,       // Alt modifier, triggers column mode selection
 
256
    //emDragDropEditing,         // Allows you to select a block of text and drag it within the document to another location
 
257
    //emRightMouseMovesCursor,   // When clicking with the right mouse for a popup menu, move the cursor to that location
 
258
    //emDoubleClickSelectsLine,  // Select line on double click
 
259
    //emShowCtrlMouseLinks       // Pressing Ctrl (SYNEDIT_LINK_MODIFIER) will highlight the word under the mouse cursor
 
260
  TSynEditorMouseOptions = SynEditMouseCmds.TSynEditorMouseOptions;
 
261
 
241
262
  // options for textbuffersharing
242
263
  TSynEditorShareOption = (
243
264
    eosShareMarks              // Shared Editors use the same list of marks
244
265
  );
245
266
  TSynEditorShareOptions = set of TSynEditorShareOption;
246
267
 
 
268
  TSynVisibleSpecialChars = SynEditTypes.TSynVisibleSpecialChars;
 
269
 
247
270
const
248
 
  // MouseAction related options will have no effect (as default), unless they
249
 
  // are also updated in the Constructor of the MouseAction-class
 
271
  // MouseAction related options MUST NOT be included here
250
272
  SYNEDIT_DEFAULT_OPTIONS = [
251
273
    eoAutoIndent,
252
274
    eoScrollPastEol,
263
285
    eoDisableScrollArrows,     //TODO Disables the scroll bar arrow buttons when you can't scroll in that direction any more
264
286
    eoDropFiles,               //TODO Allows the editor accept file drops
265
287
    eoHideShowScrollbars,      //TODO if enabled, then the scrollbars will only show when necessary.  If you have ScrollPastEOL, then it the horizontal bar will always be there (it uses MaxLength instead)
266
 
    eoScrollHintFollows,       //TODO The scroll hint follows the mouse when scrolling vertically
267
288
    eoSmartTabDelete,          //TODO similar to Smart Tabs, but when you delete characters
268
289
    ////eoSpecialLineDefaultFg,    //TODO disables the foreground text color override when using the OnSpecialLineColor event
269
290
    eoAutoIndentOnPaste,       // Indent text inserted from clipboard
270
291
    eoSpacesToTabs             // Converts space characters to tabs and spaces
271
292
  ];
272
293
 
 
294
  SYNEDIT_OLD_MOUSE_OPTIONS = [
 
295
    eoAltSetsColumnMode,       //
 
296
    eoDragDropEditing,         // Allows you to select a block of text and drag it within the document to another location
 
297
    eoRightMouseMovesCursor,   // When clicking with the right mouse for a popup menu, move the cursor to that location
 
298
    eoDoubleClickSelectsLine,  // Select line on double click
 
299
    eoShowCtrlMouseLinks       // Pressing Ctrl (SYNEDIT_LINK_MODIFIER) will highlight the word under the mouse cursor
 
300
  ];
 
301
 
 
302
  SYNEDIT_OLD_MOUSE_OPTIONS_MAP: array [eoAltSetsColumnMode..eoShowCtrlMouseLinks] of TSynEditorMouseOption = (
 
303
    emAltSetsColumnMode,       // eoAltSetsColumnMode
 
304
    emDragDropEditing,         // eoDragDropEditing
 
305
    emRightMouseMovesCursor,   // eoRightMouseMovesCursor
 
306
    emDoubleClickSelectsLine,  // eoDoubleClickSelectsLine
 
307
    emShowCtrlMouseLinks       // eoShowCtrlMouseLinks
 
308
  );
 
309
 
273
310
  SYNEDIT_DEFAULT_SHARE_OPTIONS = [
274
311
    eosShareMarks
275
312
  ];
276
313
 
277
 
  {$IFDEF SYN_LAZARUS}
278
314
  SYNEDIT_DEFAULT_OPTIONS2 = [
279
315
    eoFoldedCopyPaste,
280
316
    eoOverwriteBlock
281
317
  ];
282
 
  {$ENDIF}
 
318
 
 
319
  SYNEDIT_DEFAULT_MOUSE_OPTIONS = [];
 
320
 
 
321
  SYNEDIT_DEFAULT_VISIBLESPECIALCHARS = [
 
322
    vscSpace,
 
323
    vscTabAtLast
 
324
  ];
283
325
 
284
326
type
285
327
// use scAll to update a statusbar when another TCustomSynEdit got the focus
294
336
  TSynLineState = (slsNone, slsSaved, slsUnsaved);
295
337
 
296
338
 
297
 
  { TSynEditPlugin }
 
339
  { TLazSynEditPlugin }
298
340
 
299
 
  TSynEditPlugin = class(TSynEditFriend)
 
341
  TLazSynEditPlugin = class(TSynEditFriend)
300
342
  protected
 
343
    procedure BeforeEditorChange; virtual;
 
344
    procedure AfterEditorChange; virtual;
 
345
    procedure RegisterToEditor(AValue: TCustomSynEdit);
 
346
    procedure UnRegisterFromEditor(AValue: TCustomSynEdit);
301
347
    procedure SetEditor(const AValue: TCustomSynEdit); virtual;
302
 
    function GetEditor: TCustomSynEdit;
303
 
    function OwnedByEditor: Boolean; virtual; // if true, this will be destroyed by synedit
 
348
    function  GetEditor: TCustomSynEdit;
 
349
    function  OwnedByEditor: Boolean; virtual; // if true, this will be destroyed by synedit
 
350
    procedure DoEditorDestroyed(const AValue: TCustomSynEdit); virtual;
 
351
 
 
352
    procedure DoEditorAdded(AValue: TCustomSynEdit); virtual;
 
353
    procedure DoEditorRemoving(AValue: TCustomSynEdit); virtual;
304
354
  public
305
355
    constructor Create(AOwner: TComponent); override;
306
356
    destructor Destroy; override;
314
364
    procedure CallHookedKeyTranslationHandlers(Sender: TObject;
315
365
      Code: word; SState: TShiftState; var Data: pointer;
316
366
      var IsStartOfCombo: boolean; var Handled: boolean;
317
 
      var Command: TSynEditorCommand; var ComboKeyStrokes: TSynEditKeyStrokes);
318
 
  end;
 
367
      var Command: TSynEditorCommand;
 
368
      // ComboKeyStrokes decides, either FinishComboOnly, or new stroke
 
369
      var ComboKeyStrokes: TSynEditKeyStrokes
 
370
    );
 
371
  end;
 
372
 
 
373
  { TLazSynKeyDownEventList }
 
374
 
 
375
  { TLazSynMouseDownEventList }
 
376
 
 
377
  TLazSynMouseDownEventList = Class(TMethodList)
 
378
  public
 
379
    procedure CallMouseDownHandlers(Sender: TObject; Button: TMouseButton;
 
380
                                    Shift: TShiftState; X, Y: Integer);
 
381
  end;
 
382
 
 
383
  { TLazSynKeyDownEventList }
 
384
 
 
385
  TLazSynKeyDownEventList = Class(TMethodList)
 
386
  public
 
387
    procedure CallKeyDownHandlers(Sender: TObject; var Key: Word; Shift: TShiftState);
 
388
  end;
 
389
 
 
390
  { TLazSynKeyPressEventList }
 
391
 
 
392
  TLazSynKeyPressEventList = Class(TMethodList)
 
393
  public
 
394
    procedure CallKeyPressHandlers(Sender: TObject; var Key: char);
 
395
  end;
 
396
 
 
397
  { TLazSynUtf8KeyPressEventList }
 
398
 
 
399
  TLazSynUtf8KeyPressEventList = Class(TMethodList)
 
400
  public
 
401
    procedure CallUtf8KeyPressHandlers(Sender: TObject; var UTF8Key: TUTF8Char);
 
402
  end;
 
403
 
319
404
 
320
405
  TSynMouseLinkEvent = procedure (
321
406
    Sender: TObject; X, Y: Integer; var AllowMouseLink: Boolean) of object;
322
407
 
323
408
  TSynHomeMode = (synhmDefault, synhmFirstWord);
 
409
 
 
410
  TSynCoordinateMappingFlag = SynEditTypes.TSynCoordinateMappingFlag;
 
411
  TSynCoordinateMappingFlags = SynEditTypes.TSynCoordinateMappingFlags;
 
412
 
 
413
  TLazSynWordBoundary = (
 
414
    swbWordBegin,
 
415
    swbWordEnd,
 
416
    swbTokenBegin,
 
417
    swbTokenEnd,
 
418
    swbCaseChange
 
419
  );
 
420
 
324
421
  { TCustomSynEdit }
325
422
 
326
423
  TCustomSynEdit = class(TSynEditBase)
 
424
    procedure SelAvailChange(Sender: TObject);
 
425
  {$IFDEF WinIME}
 
426
  private
 
427
    FImeHandler: LazSynIme;
 
428
    procedure SetImeHandler(AValue: LazSynIme);
 
429
    procedure WMImeRequest(var Msg: TMessage); message WM_IME_REQUEST;
 
430
    procedure WMImeNotify(var Msg: TMessage); message WM_IME_NOTIFY;
 
431
    procedure WMImeStartComposition(var Msg: TMessage); message WM_IME_STARTCOMPOSITION;
 
432
    procedure WMImeComposition(var Msg: TMessage); message WM_IME_COMPOSITION;
 
433
    procedure WMImeEndComposition(var Msg: TMessage); message WM_IME_ENDCOMPOSITION;
 
434
  protected
 
435
    // SynEdit takes ownership
 
436
    property ImeHandler: LazSynIme read FImeHandler write SetImeHandler;
 
437
  {$ENDIF}
327
438
  private
328
439
    procedure WMDropFiles(var Msg: TMessage); message WM_DROPFILES;
329
440
    procedure WMEraseBkgnd(var Msg: TMessage); message WM_ERASEBKGND;
330
441
    procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE;
331
442
    procedure WMHScroll(var Msg: {$IFDEF SYN_LAZARUS}TLMScroll{$ELSE}TWMScroll{$ENDIF}); message WM_HSCROLL;
332
 
    {$IFDEF SYN_MBCSSUPPORT}
333
 
    procedure WMImeComposition(var Msg: TMessage); message WM_IME_COMPOSITION;
334
 
    procedure WMImeNotify(var Msg: TMessage); message WM_IME_NOTIFY;
335
 
    {$ENDIF}
336
443
    procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
337
444
    procedure WMExit(var Message: TLMExit); message LM_EXIT;
338
 
    {$IFNDEF SYN_LAZARUS}
339
 
    procedure WMMouseWheel(var Msg: TMessage); message WM_MOUSEWHEEL;
340
 
    {$ENDIF}
341
 
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
 
445
    procedure WMMouseWheel(var Message: TLMMouseEvent); message LM_MOUSEWHEEL;
 
446
    //procedure WMMouseWheel(var Msg: TMessage); message WM_MOUSEWHEEL;
 
447
    procedure WMSetFocus(var Msg: TLMSetFocus); message WM_SETFOCUS;
342
448
    procedure WMVScroll(var Msg: {$IFDEF SYN_LAZARUS}TLMScroll{$ELSE}TWMScroll{$ENDIF}); message WM_VSCROLL;
 
449
  protected
 
450
    procedure CMWantSpecialKey(var Message: TLMessage); message CM_WANTSPECIALKEY;
343
451
  private
344
452
    FBlockIndent: integer;
 
453
    FBlockTabIndent: integer;
345
454
    FCaret: TSynEditCaret;
346
455
    FInternalCaret: TSynEditCaret;
347
456
    FScreenCaret: TSynEditScreenCaret;
348
457
    FInternalBlockSelection: TSynEditSelection;
349
458
    FOnChangeUpdating: TChangeUpdatingEvent;
350
459
    FMouseSelectionMode: TSynSelectionMode;
351
 
    fCtrlMouseActive: boolean;                                                  // deprecated since 0.9.29
352
460
    fMarkupManager : TSynEditMarkupManager;
353
461
    fMarkupHighAll : TSynEditMarkupHighlightAll;
354
462
    fMarkupHighCaret : TSynEditMarkupHighlightAllCaret;
357
465
    fMarkupCtrlMouse : TSynEditMarkupCtrlMouseLink;
358
466
    fMarkupSpecialLine : TSynEditMarkupSpecialLine;
359
467
    fMarkupSelection : TSynEditMarkupSelection;
360
 
    fCharsInWindow: Integer;
361
 
    fCharWidth: Integer;
 
468
    fMarkupSpecialChar : TSynEditMarkupSpecialChar;
362
469
    fFontDummy: TFont;
363
 
    {$IFDEF SYN_MBCSSUPPORT}
364
 
    fImeCount: Integer;
365
 
    fMBCSStepAside: Boolean;
366
 
    {$ENDIF}
 
470
    FLastSetFontSize: Integer;
367
471
    fInserting: Boolean;
368
472
    fLastMouseCaret: TPoint;  // Char; physical (screen)
369
473
    FLastMousePoint: TPoint;  // Pixel
374
478
 
375
479
    FFoldedLinesView:  TSynEditFoldedView;
376
480
    FShareOptions: TSynEditorShareOptions;
 
481
    FVisibleSpecialChars: TSynVisibleSpecialChars;
377
482
    FTrimmedLinesView: TSynEditStringTrimmingList;
378
483
    FDoubleWidthChrLinesView: SynEditStringDoubleWidthChars;
379
484
    FTabbedLinesView:  TSynEditStringTabExpander;
381
486
    FLines: TSynEditStrings;          // The real (un-mapped) line-buffer
382
487
    FStrings: TStrings;               // External TStrings based interface to the Textbuffer
383
488
    FTopLinesView: TSynEditStrings;   // The linesview that holds the real line-buffer/FLines
 
489
    FDisplayView: TLazSynDisplayView;
384
490
 
385
491
    fExtraCharSpacing: integer;
386
 
    fLinesInWindow: Integer;// MG: fully visible lines in window
387
 
    fLeftChar: Integer;    // first visible screen column
388
492
    fMaxLeftChar: Integer; // 1024
389
493
    FOldWidth, FOldHeight: Integer;
390
494
 
391
495
    FPaintLock: Integer;
392
496
    FPaintLockOwnerCnt: Integer;
 
497
    FUndoBlockAtPaintLock: Integer;
393
498
    FScrollBarUpdateLock: Integer;
394
499
    FInvalidateRect: TRect;
395
500
    FIsInDecPaintLock: Boolean;
396
501
    fReadOnly: Boolean;
397
 
    fRightEdge: Integer;
398
 
    fRightEdgeColor: TColor;
399
502
    FScrollBars: TScrollStyle;
400
 
    fTextHeight: Integer;
401
 
    fTextOffset: Integer;
402
 
    fTopLine: Integer;
403
 
    FOldTopLine, FOldTopView: Integer;
 
503
    FOldTopView: Integer;
404
504
    FLastTextChangeStamp: Int64;
405
505
    fHighlighter: TSynCustomHighlighter;
406
506
    fUndoList: TSynEditUndoList;
409
509
    fMouseDownX: integer;
410
510
    fMouseDownY: integer;
411
511
    fBookMarkOpt: TSynBookMarkOpt;
412
 
    {$ifndef SYN_LAZARUS}
413
 
    fMouseWheelAccumulator: integer;
414
 
    {$endif}
 
512
    FMouseWheelAccumulator, FMouseWheelLinesAccumulator: integer;
415
513
    fHideSelection: boolean;
416
514
    fOverwriteCaret: TSynEditCaretType;
417
515
    fInsertCaret: TSynEditCaretType;
418
 
    FKeyStrokes, FLastKeyStrokes: TSynEditKeyStrokes;
419
 
    FMouseActions, FMouseSelActions: TSynEditMouseActions;
 
516
    FKeyStrokes: TSynEditKeyStrokes;
 
517
    FCurrentComboKeyStrokes: TSynEditKeyStrokes; // Holding info about the keystroke(s) already received for a mult-stroke-combo
 
518
    FMouseActions, FMouseSelActions, FMouseTextActions: TSynEditMouseInternalActions;
420
519
    FMouseActionSearchHandlerList: TSynEditMouseActionSearchList;
421
520
    FMouseActionExecHandlerList: TSynEditMouseActionExecList;
422
521
    FMarkList: TSynEditMarkList;
428
527
    fTextDrawer: TheTextDrawer;
429
528
    FPaintLineColor, FPaintLineColor2: TSynSelectedColor;
430
529
    fStateFlags: TSynStateFlags;
431
 
    fOptions: TSynEditorOptions;
432
 
    fOptions2: TSynEditorOptions2;
 
530
    FOptions: TSynEditorOptions;
 
531
    FOptions2: TSynEditorOptions2;
 
532
    FMouseOptions: TSynEditorMouseOptions;
433
533
    fStatusChanges: TSynStatusChanges;
434
534
    fTSearch: TSynEditSearch;
435
535
    fHookedCommandHandlers: TList;
436
536
    FHookedKeyTranslationList: TSynHookedKeyTranslationList;
 
537
    FMouseDownEventList: TLazSynMouseDownEventList;
 
538
    FKeyDownEventList: TLazSynKeyDownEventList;
 
539
    FKeyPressEventList: TLazSynKeyPressEventList;
 
540
    FUtf8KeyPressEventList: TLazSynUtf8KeyPressEventList;
437
541
    FStatusChangedList: TObject;
438
542
    FPlugins: TList;
439
543
    fScrollTimer: TTimer;
440
 
    fScrollDeltaX, fScrollDeltaY: Integer;
 
544
    FScrollDeltaX, FScrollDeltaY: Integer;
441
545
    FInMouseClickEvent: Boolean;
442
546
    FMouseClickDoPopUp: Boolean;
443
547
    // event handlers
461
565
 
462
566
    procedure AquirePrimarySelection;
463
567
    function GetChangeStamp: int64;
 
568
    function GetCharsInWindow: Integer;
 
569
    function GetCharWidth: integer;
464
570
    function GetDefSelectionMode: TSynSelectionMode;
465
571
    function GetFoldState: String;
466
 
    function GetGutterWidth: Integer; deprecated; // deprecated in 0.9.29 (08/2010)
 
572
    function GetLeftChar: Integer;
 
573
    function GetLineHeight: integer;
 
574
    function GetLinesInWindow: Integer;
467
575
    function GetModified: Boolean;
 
576
    function GetMouseActions: TSynEditMouseActions;
 
577
    function GetMouseSelActions: TSynEditMouseActions;
 
578
    function GetMouseTextActions: TSynEditMouseActions;
468
579
    function GetPaintLockOwner: TSynEditBase;
469
 
    function GetPlugin(Index: Integer): TSynEditPlugin;
 
580
    function GetPlugin(Index: Integer): TLazSynEditPlugin;
 
581
    function GetRightEdge: Integer;
 
582
    function GetRightEdgeColor: TColor;
470
583
    function GetTextBetweenPoints(aStartPoint, aEndPoint: TPoint): String;
471
 
    function GetDividerDrawLevel: Integer; deprecated;
 
584
    function GetTopLine: Integer;
 
585
    procedure SetBlockTabIndent(AValue: integer);
 
586
    procedure SetBracketMatchColor(AValue: TSynSelectedColor);
472
587
    procedure SetDefSelectionMode(const AValue: TSynSelectionMode);
473
 
    procedure SetDividerDrawLevel(const AValue: Integer); deprecated;
 
588
    procedure SetFoldedCodeColor(AValue: TSynSelectedColor);
474
589
    procedure SetFoldState(const AValue: String);
 
590
    procedure SetHighlightAllColor(AValue: TSynSelectedColor);
 
591
    procedure SetIncrementColor(AValue: TSynSelectedColor);
 
592
    procedure SetLineHighlightColor(AValue: TSynSelectedColor);
475
593
    procedure SetMouseActions(const AValue: TSynEditMouseActions);
 
594
    procedure SetMouseLinkColor(AValue: TSynSelectedColor);
476
595
    procedure SetMouseSelActions(const AValue: TSynEditMouseActions);
 
596
    procedure SetMouseTextActions(AValue: TSynEditMouseActions);
477
597
    procedure SetPaintLockOwner(const AValue: TSynEditBase);
478
598
    procedure SetShareOptions(const AValue: TSynEditorShareOptions);
479
 
    procedure SetTextBetweenPoints(aStartPoint, aEndPoint: TPoint; const AValue: String);
 
599
    procedure SetTextBetweenPointsSimple(aStartPoint, aEndPoint: TPoint; const AValue: String);
480
600
    procedure SetTextBetweenPointsEx(aStartPoint, aEndPoint: TPoint;
481
601
      aCaretMode: TSynCaretAdjustMode; const AValue: String);
 
602
    procedure SetVisibleSpecialChars(AValue: TSynVisibleSpecialChars);
482
603
    procedure SurrenderPrimarySelection;
483
604
    procedure BookMarkOptionsChanged(Sender: TObject);
484
605
    procedure ComputeCaret(X, Y: Integer);
571
692
    procedure UpdateOptions;
572
693
    procedure SetOptions2(const Value: TSynEditorOptions2);
573
694
    procedure UpdateOptions2;
 
695
    procedure SetMouseOptions(AValue: TSynEditorMouseOptions);
 
696
    procedure UpdateMouseOptions;
574
697
    procedure SetOverwriteCaret(const Value: TSynEditCaretType);
575
698
    procedure SetRightEdge(Value: Integer);
576
699
    procedure SetRightEdgeColor(Value: TColor);
580
703
    procedure SetSelTextExternal(const Value: string);
581
704
    procedure SetTabWidth(Value: integer);
582
705
    procedure SynSetText(const Value: string);
583
 
    function  CurrentMaxTopLine: Integer;
 
706
    function  CurrentMaxTopView: Integer;
584
707
    procedure SetTopLine(Value: Integer);
585
708
    procedure ScrollAfterTopLineChanged;
586
709
    procedure SetWantTabs(const Value: boolean);
587
710
    procedure SetWordBlock(Value: TPoint);
588
711
    procedure SetLineBlock(Value: TPoint; WithLeadSpaces: Boolean = True);
589
712
    procedure SetParagraphBlock(Value: TPoint);
590
 
    procedure SizeOrFontChanged(bFont: boolean);
591
713
    procedure RecalcCharsAndLinesInWin(CheckCaret: Boolean);
592
714
    procedure StatusChanged(AChanges: TSynStatusChanges);
593
715
    procedure UndoRedoAdded(Sender: TObject);
604
726
    procedure InternalBeginUndoBlock(aList: TSynEditUndoList = nil); // includes paintlock
605
727
    procedure InternalEndUndoBlock(aList: TSynEditUndoList = nil);
606
728
  protected
 
729
    {$IFDEF EnableDoubleBuf}
 
730
    BufferBitmap: TBitmap; // the double buffer
 
731
    SavedCanvas: TCanvas; // the normal TCustomControl canvas during paint
 
732
    {$ENDIF}
 
733
    FTextArea: TLazSynTextArea;
 
734
    FLeftGutterArea, FRightGutterArea: TLazSynGutterArea;
 
735
    FPaintArea: TLazSynSurfaceManager;
 
736
 
 
737
    procedure Paint; override;
 
738
    procedure StartPaintBuffer(const ClipRect: TRect);
 
739
    procedure EndPaintBuffer(const ClipRect: TRect);
 
740
    procedure DoOnPaint; virtual;
 
741
 
 
742
    procedure IncPaintLock;
 
743
    procedure DecPaintLock;
 
744
    procedure DoIncPaintLock(Sender: TObject);
 
745
    procedure DoDecPaintLock(Sender: TObject);
 
746
    procedure DoIncForeignPaintLock(Sender: TObject);
 
747
    procedure DoDecForeignPaintLock(Sender: TObject);
 
748
    procedure SetUpdateState(NewUpdating: Boolean; Sender: TObject); virtual;      // Called *before* paintlock, and *after* paintlock
 
749
 
 
750
    property PaintLockOwner: TSynEditBase read GetPaintLockOwner write SetPaintLockOwner;
 
751
    property TextDrawer: TheTextDrawer read fTextDrawer;
 
752
 
 
753
  protected
607
754
    procedure CreateHandle; override;
608
755
    procedure CreateParams(var Params: TCreateParams); override;
609
756
    procedure CreateWnd; override;
 
757
    procedure DestroyWnd; override;
 
758
    procedure Loaded; override;
 
759
    function  GetChildOwner: TComponent; override;
 
760
    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
 
761
 
 
762
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
 
763
    procedure UTF8KeyPress(var Key: TUTF8Char); override;
 
764
    procedure KeyPress(var Key: Char); override;
 
765
    procedure KeyUp(var Key : Word; Shift : TShiftState); override;
610
766
 
611
767
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y:
612
768
      Integer); override;
614
770
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
615
771
      override;
616
772
    procedure ScrollTimerHandler(Sender: TObject);
617
 
    procedure DoContextPopup(const MousePos: TPoint; var Handled: Boolean); override;
618
 
 
619
 
    procedure FindAndHandleMouseAction(AButton: TMouseButton; AShift: TShiftState;
 
773
    procedure DoContextPopup(MousePos: TPoint; var Handled: Boolean); override;
 
774
    procedure FindAndHandleMouseAction(AButton: TSynMouseButton; AShift: TShiftState;
620
775
                                X, Y: Integer; ACCount:TSynMAClickCount;
621
 
                                ADir: TSynMAClickDir);
 
776
                                ADir: TSynMAClickDir;
 
777
                                AWheelDelta: Integer = 0);
622
778
    function DoHandleMouseAction(AnActionList: TSynEditMouseActions;
623
779
                                 AnInfo: TSynEditMouseActionInfo): Boolean;
624
780
 
625
 
    procedure Resize; override;
 
781
  protected
 
782
    procedure SetColor(Value: TColor); override;
 
783
    procedure DragOver(Source: TObject; X, Y: Integer;
 
784
      State: TDragState; var Accept: Boolean); override;
 
785
    procedure DoOnResize; override;
626
786
    function  RealGetText: TCaption; override;
627
787
    procedure RealSetText(const Value: TCaption); override;
628
788
    function GetLines: TStrings; override;
632
792
    procedure SetLines(Value: TStrings);  override;
633
793
    function GetMarkupMgr: TObject; override;
634
794
    function GetCaretObj: TSynEditCaret; override;
635
 
    procedure IncPaintLock;
636
 
    procedure DecPaintLock;
637
 
    procedure DoIncPaintLock(Sender: TObject);
638
 
    procedure DoDecPaintLock(Sender: TObject);
639
 
    procedure DoIncForeignPaintLock(Sender: TObject);
640
 
    procedure DoDecForeignPaintLock(Sender: TObject);
641
 
    procedure SetUpdateState(NewUpdating: Boolean; Sender: TObject); virtual;      // Called *before* paintlock, and *after* paintlock
642
 
    procedure DestroyWnd; override;
643
 
    procedure DragOver(Source: TObject; X, Y: Integer;
644
 
      State: TDragState; var Accept: Boolean); override;
645
 
    procedure FontChanged(Sender: TObject); {$IFDEF SYN_LAZARUS}override;{$ENDIF}
 
795
    procedure FontChanged(Sender: TObject); override;
646
796
    function GetReadOnly: boolean; virtual;
647
797
    procedure HighlighterAttrChanged(Sender: TObject);
648
798
    // note: FirstLine and LastLine don't need to be in correct order
649
799
    procedure InvalidateGutterLines(FirstLine, LastLine: integer);
650
800
    procedure InvalidateLines(FirstLine, LastLine: integer);
651
 
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
652
 
    procedure UTF8KeyPress(var Key: TUTF8Char); override;
653
 
    procedure KeyPress(var Key: Char); override;
654
 
    procedure KeyUp(var Key : Word; Shift : TShiftState); override;
655
801
    Procedure LineCountChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
656
802
    Procedure LineTextChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
 
803
    procedure SizeOrFontChanged(bFont: boolean);
657
804
    procedure DoHighlightChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
658
805
    procedure ListCleared(Sender: TObject);
659
806
    procedure FoldChanged(Index: integer);
660
 
    function GetTopView : Integer;
661
 
    procedure SetTopView(const AValue : Integer);
662
 
    procedure Loaded; override;
 
807
    function  GetTopView : Integer;
 
808
    procedure SetTopView(AValue : Integer);
663
809
    procedure MarkListChange(Sender: TSynEditMark; Changes: TSynEditMarkChangeReasons);
664
 
{$IFDEF SYN_MBCSSUPPORT}
665
 
    procedure MBCSGetSelRangeInLineWhenColumnSelectionMode(const s: string;
666
 
      var ColFrom, ColTo: Integer);
667
 
{$ENDIF}
668
 
    procedure NotifyHookedCommandHandlers(AfterProcessing: boolean;
669
 
      var Command: TSynEditorCommand;
670
 
      var AChar: TUTF8Char;
671
 
      Data: pointer); virtual;
672
 
    procedure Paint; override;
673
 
    procedure PaintTextLines(AClip: TRect; FirstLine, LastLine,
674
 
      FirstCol, LastCol: integer); virtual;
675
 
    procedure StartPaintBuffer(const ClipRect: TRect);
676
 
    procedure EndPaintBuffer(const ClipRect: TRect);
677
 
    function NextWordLogicalPos(WordEndForDelete : Boolean = false): TPoint;
678
 
    function PrevWordLogicalPos: TPoint;
 
810
    procedure NotifyHookedCommandHandlers(var Command: TSynEditorCommand;
 
811
      var AChar: TUTF8Char; Data: pointer; ATime: THookedCommandFlag); virtual;
 
812
    function NextWordLogicalPos(ABoundary: TLazSynWordBoundary = swbWordBegin; WordEndForDelete : Boolean = false): TPoint;
 
813
    function PrevWordLogicalPos(ABoundary: TLazSynWordBoundary = swbWordBegin): TPoint;
679
814
    procedure RecalcCharExtent;
680
815
    procedure RedoItem(Item: TSynEditUndoItem);
681
 
    procedure SetCaretXY(Value: TPoint); virtual;
 
816
    procedure SetCaretXY(Value: TPoint);
682
817
    procedure CaretChanged(Sender: TObject);
683
818
    procedure SetName(const Value: TComponentName); override;
684
819
    procedure SetReadOnly(Value: boolean); virtual;
686
821
      AddToUndoList: Boolean = false);
687
822
    procedure UndoItem(Item: TSynEditUndoItem);
688
823
    procedure UpdateCursor;
689
 
    property PaintLockOwner: TSynEditBase read GetPaintLockOwner write SetPaintLockOwner;
690
 
  protected
691
 
    {$IFDEF EnableDoubleBuf}
692
 
    BufferBitmap: TBitmap; // the double buffer
693
 
    {$ENDIF}
694
 
    SavedCanvas: TCanvas; // the normal TCustomControl canvas during paint
695
 
    function GetChildOwner: TComponent; override;
696
 
    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
697
824
    procedure DoOnCommandProcessed(Command: TSynEditorCommand;
698
825
      AChar: TUTF8Char;
699
826
      Data: pointer); virtual;
700
827
    // no method DoOnDropFiles, intercept the WM_DROPFILES instead
701
 
    procedure DoOnPaint; virtual;
702
828
    procedure DoOnProcessCommand(var Command: TSynEditorCommand;
703
829
      var AChar: TUTF8Char;
704
830
      Data: pointer); virtual;
705
831
    function DoOnReplaceText(const ASearch, AReplace: string;
706
832
      Line, Column: integer): TSynReplaceAction; virtual;
707
 
    {$IFNDEF SYN_LAZARUS}
708
 
    function DoOnSpecialLineColors(Line: integer;
709
 
      var Foreground, Background: TColor): boolean; virtual;
710
 
    {$ENDIF}
711
833
    procedure DoOnStatusChange(Changes: TSynStatusChanges); virtual;
712
834
    property LastMouseCaret: TPoint read FLastMouseCaret write SetLastMouseCaret;
713
 
    {$IFDEF SYN_LAZARUS}
714
835
    function GetSelEnd: integer;                                                 //L505
715
836
    function GetSelStart: integer;
716
837
    procedure SetSelEnd(const Value: integer);
717
838
    procedure SetSelStart(const Value: integer);
718
839
    property TextView : TSynEditFoldedView read FFoldedLinesView;
719
840
    property TopView: Integer read GetTopView write SetTopView;  // TopLine converted into Visible(View) lines
720
 
    {$ENDIF}
721
841
    function PasteFromClipboardEx(ClipHelper: TSynClipboardStream): Boolean;
722
842
    function FindNextUnfoldedLine(iLine: integer; Down: boolean): Integer;
723
843
    // Todo: Reduce the argument list of Creategutter
724
844
    function CreateGutter(AOwner : TSynEditBase; ASide: TSynGutterSide;
725
845
                          ATextDrawer: TheTextDrawer): TSynGutter; virtual;
726
846
  public
727
 
    procedure FindMatchingBracket; virtual;
728
 
    function FindMatchingBracket(PhysStartBracket: TPoint;
729
 
                                 StartIncludeNeighborChars, MoveCaret,
730
 
                                 SelectBrackets, OnlyVisible: Boolean
731
 
                                 ): TPoint; virtual;
732
 
    //code fold
733
 
    procedure CodeFoldAction(iLine: integer); deprecated;
734
 
    procedure UnfoldAll;
735
 
    procedure FoldAll(StartLevel : Integer = 0; IgnoreNested : Boolean = False);
736
 
    procedure EraseBackground(DC: HDC); override;
737
 
 
738
 
    procedure AddKey(Command: TSynEditorCommand; Key1: word; SS1: TShiftState;
739
 
      Key2: word; SS2: TShiftState);
 
847
    constructor Create(AOwner: TComponent); override;
 
848
    destructor Destroy; override;
740
849
    procedure AfterLoadFromFile;
741
 
    procedure BeginUndoBlock;
742
 
    procedure BeginUpdate;
 
850
 
 
851
    procedure BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}(ACaller: String = ''){$ENDIF};
 
852
    procedure BeginUpdate(WithUndoBlock: Boolean = True);
 
853
    procedure EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}(ACaller: String = ''){$ENDIF};
 
854
    procedure EndUpdate;
 
855
 
 
856
  public
 
857
    // Caret
743
858
    function CaretXPix: Integer;
744
859
    function CaretYPix: Integer;
 
860
    procedure EnsureCursorPosVisible;
 
861
    procedure MoveCaretToVisibleArea;
 
862
    procedure MoveCaretIgnoreEOL(const NewCaret: TPoint);
 
863
    procedure MoveLogicalCaretIgnoreEOL(const NewLogCaret: TPoint);
 
864
 
 
865
    property CaretX: Integer read GetCaretX write SetCaretX;
 
866
    property CaretY: Integer read GetCaretY write SetCaretY;
 
867
    property CaretXY: TPoint read GetCaretXY write SetCaretXY;// screen position
 
868
    property LogicalCaretXY: TPoint read GetLogicalCaretXY write SetLogicalCaretXY;
 
869
 
 
870
    // Selection
 
871
    procedure ClearSelection;
 
872
    procedure SelectAll;
 
873
    procedure SelectToBrace;
 
874
    procedure SelectWord;
 
875
    procedure SelectLine(WithLeadSpaces: Boolean = True);
 
876
    procedure SelectParagraph;
 
877
 
 
878
    property BlockBegin: TPoint read GetBlockBegin write SetBlockBegin;         // Set Blockbegin. For none persistent also sets Blockend. Setting Caret may undo this and should be done before setting block
 
879
    property BlockEnd: TPoint read GetBlockEnd write SetBlockEnd;
 
880
    property SelStart: Integer read GetSelStart write SetSelStart;
 
881
    property SelEnd: Integer read GetSelEnd write SetSelEnd;
 
882
    property SelAvail: Boolean read GetSelAvail;
 
883
    property SelText: string read GetSelText write SetSelTextExternal;
 
884
 
 
885
    // Text
745
886
    procedure ClearAll;
 
887
    procedure InsertTextAtCaret(aText: String; aCaretMode : TSynCaretAdjustMode = scamEnd);
 
888
 
 
889
    property TextBetweenPoints[aStartPoint, aEndPoint: TPoint]: String              // Logical Points
 
890
      read GetTextBetweenPoints write SetTextBetweenPointsSimple;
 
891
    property TextBetweenPointsEx[aStartPoint, aEndPoint: TPoint; CaretMode: TSynCaretAdjustMode]: String
 
892
      write SetTextBetweenPointsEx;
 
893
    procedure SetTextBetweenPoints(aStartPoint, aEndPoint: TPoint;
 
894
                                   const AValue: String;
 
895
                                   aFlags: TSynEditTextFlags = [];
 
896
                                   aCaretMode: TSynCaretAdjustMode = scamIgnore;
 
897
                                   aMarksMode: TSynMarksAdjustMode = smaMoveUp;
 
898
                                   aSelectionMode: TSynSelectionMode = smNormal
 
899
                                  );
 
900
 
 
901
    property LineText: string read GetLineText write SetLineText;
 
902
    property Text: string read SynGetText write SynSetText;                     // No uncommited (trailing/trimmable) spaces
 
903
 
 
904
    function GetLineState(ALine: Integer): TSynLineState;
 
905
    procedure MarkTextAsSaved;
 
906
 
 
907
    // BoorMark
746
908
    procedure ClearBookMark(BookMark: Integer);
747
 
    procedure ClearSelection;
748
 
    procedure CommandProcessor(Command:TSynEditorCommand;
749
 
      AChar: TUTF8Char;
750
 
      Data:pointer); virtual;
 
909
    function  GetBookMark(BookMark: integer; var X, Y: integer): boolean;
 
910
    procedure GotoBookMark(BookMark: Integer);
 
911
    function  IsBookmark(BookMark: integer): boolean;
 
912
    procedure SetBookMark(BookMark: Integer; X: Integer; Y: Integer);
 
913
    property Marks: TSynEditMarkList read fMarkList;
 
914
 
 
915
    // Undo/Redo
751
916
    procedure ClearUndo;
 
917
    procedure Redo;
 
918
    procedure Undo;
 
919
    property CanRedo: boolean read GetCanRedo;
 
920
    property CanUndo: boolean read GetCanUndo;
 
921
 
 
922
    // Clipboard
752
923
    procedure CopyToClipboard;
753
 
    constructor Create(AOwner: TComponent); override;
754
924
    procedure CutToClipboard;
755
 
    destructor Destroy; override;
 
925
    procedure PasteFromClipboard;
756
926
    procedure DoCopyToClipboard(SText: string; FoldInfo: String = '');
 
927
    property CanPaste: Boolean read GetCanPaste;
 
928
 
757
929
    procedure DragDrop(Source: TObject; X, Y: Integer); override;
758
 
    procedure EndUndoBlock;
759
 
    procedure EndUpdate;
760
 
    procedure EnsureCursorPosVisible;
761
930
{$IFDEF SYN_COMPILER_4_UP}
762
931
    function ExecuteAction(ExeAction: TBasicAction): boolean; override;
763
932
{$ENDIF}
 
933
    procedure CommandProcessor(Command:TSynEditorCommand;
 
934
      AChar: TUTF8Char;
 
935
      Data:pointer); virtual;
764
936
    procedure ExecuteCommand(Command: TSynEditorCommand;
765
937
      const AChar: TUTF8Char; Data: pointer); virtual;
766
 
    function GetBookMark(BookMark: integer; var X, Y: integer): boolean;
767
 
    function GetHighlighterAttriAtRowCol(XY: TPoint; var Token: string;
768
 
      var Attri: TSynHighlighterAttributes): boolean;
769
 
    function GetHighlighterAttriAtRowColEx(XY: TPoint; var Token: string;
770
 
      var TokenType, Start: Integer;
771
 
      var Attri: TSynHighlighterAttributes): boolean;                           //L505
772
938
 
773
 
    procedure GetWordBoundsAtRowCol(const XY: TPoint; var StartX, EndX: integer);
 
939
    function GetHighlighterAttriAtRowCol(XY: TPoint; out Token: string;
 
940
      out Attri: TSynHighlighterAttributes): boolean;
 
941
    function GetHighlighterAttriAtRowColEx(XY: TPoint; out Token: string;
 
942
      out TokenType, Start: Integer;
 
943
      out Attri: TSynHighlighterAttributes): boolean;                           //L505
 
944
    procedure GetWordBoundsAtRowCol(const XY: TPoint; out StartX, EndX: integer);
774
945
    function GetWordAtRowCol(XY: TPoint): string;
775
946
    function NextTokenPos: TPoint; virtual; deprecated; // use next word pos instead
776
947
    function NextWordPos: TPoint; virtual;
779
950
    function IsIdentChar(const c: TUTF8Char): boolean;
780
951
 
781
952
    function IsLinkable(Y, X1, X2: Integer): Boolean;
782
 
    procedure GotoBookMark(BookMark: Integer);
783
953
    procedure InvalidateGutter;
784
954
    procedure InvalidateLine(Line: integer);
785
 
    function IsBookmark(BookMark: integer): boolean;
786
 
    procedure MarkTextAsSaved;
787
 
    {$IFDEF SYN_LAZARUS}
 
955
 
788
956
    // Byte to Char
789
957
    function LogicalToPhysicalPos(const p: TPoint): TPoint;
790
958
    function LogicalToPhysicalCol(const Line: String; Index, LogicalPos
794
962
    function PhysicalToLogicalCol(const Line: string;
795
963
                                  Index, PhysicalPos: integer): integer;
796
964
    function PhysicalLineLength(Line: String; Index: integer): integer;
 
965
 
 
966
    // Pixel
797
967
    function ScreenColumnToXValue(Col: integer): integer;  // map screen column to screen pixel
798
 
    procedure MoveCaretToVisibleArea;
799
 
    procedure MoveCaretIgnoreEOL(const NewCaret: TPoint);
800
 
    procedure MoveLogicalCaretIgnoreEOL(const NewLogCaret: TPoint);
801
 
    {$ELSE}
802
 
    function LogicalToPhysicalPos(p: TPoint): TPoint;
803
 
    {$ENDIF}
 
968
    // RowColumnToPixels: Physical coords
 
969
    function RowColumnToPixels(RowCol: TPoint): TPoint;
 
970
    function PixelsToRowColumn(Pixels: TPoint; aFlags: TSynCoordinateMappingFlags = [scmLimitToLines]): TPoint;
 
971
    function PixelsToLogicalPos(const Pixels: TPoint): TPoint;
 
972
    //
 
973
    function ScreenRowToRow(ScreenRow: integer; LimitToLines: Boolean = True): integer;
 
974
    function RowToScreenRow(PhysicalRow: integer): integer;
 
975
 
804
976
    procedure Notification(AComponent: TComponent;
805
977
      Operation: TOperation); override;
806
 
    procedure PasteFromClipboard;
807
 
    function PixelsToRowColumn(Pixels: TPoint): TPoint;
808
 
    {$IFDEF SYN_LAZARUS}
809
 
    function PixelsToLogicalPos(const Pixels: TPoint): TPoint;
810
 
    function ScreenRowToRow(ScreenRow: integer): integer;
811
 
    function RowToScreenRow(PhysicalRow: integer): integer;
812
 
    {$ENDIF}
813
 
    procedure Redo;
814
978
    procedure RegisterCommandHandler(AHandlerProc: THookedCommandEvent;
815
 
      AHandlerData: pointer);
 
979
      AHandlerData: pointer; AFlags: THookedCommandFlags = [hcfPreExec, hcfPostExec]);
816
980
    procedure UnregisterCommandHandler(AHandlerProc: THookedCommandEvent);
817
981
 
818
982
    procedure RegisterMouseActionSearchHandler(AHandlerProc: TSynEditMouseActionSearchProc);
826
990
    procedure RegisterStatusChangedHandler(AStatusChangeProc: TStatusChangeEvent; AChanges: TSynStatusChanges);
827
991
    procedure UnRegisterStatusChangedHandler(AStatusChangeProc: TStatusChangeEvent);
828
992
 
829
 
    // RowColumnToPixels: Physical coords
830
 
    function RowColumnToPixels(
831
 
                      {$IFDEF SYN_LAZARUS}const {$ENDIF}RowCol: TPoint): TPoint;
 
993
    procedure RegisterBeforeMouseDownHandler(AHandlerProc: TMouseEvent);
 
994
    procedure UnregisterBeforeMouseDownHandler(AHandlerProc: TMouseEvent);
 
995
 
 
996
    procedure RegisterBeforeKeyDownHandler(AHandlerProc: TKeyEvent);
 
997
    procedure UnregisterBeforeKeyDownHandler(AHandlerProc: TKeyEvent);
 
998
    procedure RegisterBeforeKeyPressHandler(AHandlerProc: TKeyPressEvent);
 
999
    procedure UnregisterBeforeKeyPressHandler(AHandlerProc: TKeyPressEvent);
 
1000
    procedure RegisterBeforeUtf8KeyPressHandler(AHandlerProc: TUTF8KeyPressEvent);
 
1001
    procedure UnregisterBeforeUtf8KeyPressHandler(AHandlerProc: TUTF8KeyPressEvent);
 
1002
 
832
1003
    function SearchReplace(const ASearch, AReplace: string;
833
1004
      AOptions: TSynSearchOptions): integer;
834
1005
    function SearchReplaceEx(const ASearch, AReplace: string;
835
1006
      AOptions: TSynSearchOptions; AStart: TPoint): integer;
836
 
    procedure SelectAll;
837
 
    Procedure SetHighlightSearch(const ASearch: String; AOptions: TSynSearchOptions);
838
 
    procedure SelectToBrace;
839
 
    procedure SetSelWord; deprecated;
840
 
    procedure SelectWord;
841
 
    procedure SelectLine(WithLeadSpaces: Boolean = True);
842
 
    procedure SelectParagraph;
 
1007
 
843
1008
    procedure SetUseIncrementalColor(const AValue : Boolean);
844
 
    procedure SetBookMark(BookMark: Integer; X: Integer; Y: Integer);
845
1009
    procedure SetDefaultKeystrokes; virtual;
 
1010
    procedure ResetMouseActions;  // set mouse-actions according to current Options / may clear them
846
1011
    procedure SetOptionFlag(Flag: TSynEditorOption; Value: boolean);
847
 
    procedure Undo;
848
 
    function GetLineState(ALine: Integer): TSynLineState;
 
1012
    Procedure SetHighlightSearch(const ASearch: String; AOptions: TSynSearchOptions);
849
1013
{$IFDEF SYN_COMPILER_4_UP}
850
1014
    function UpdateAction(TheAction: TBasicAction): boolean; override;
851
1015
{$ENDIF}
852
1016
    procedure WndProc(var Msg: TMessage); override;
 
1017
    procedure EraseBackground(DC: HDC); override;
853
1018
  public
854
 
    procedure InsertTextAtCaret(aText: String; aCaretMode : TSynCaretAdjustMode = scamEnd);
855
 
    property BlockBegin: TPoint read GetBlockBegin write SetBlockBegin;         // Set Blockbegin. For none persistent also sets Blockend. Setting Caret may undo this and should be done before setting block
856
 
    property BlockEnd: TPoint read GetBlockEnd write SetBlockEnd;
 
1019
    procedure FindMatchingBracket; virtual;
 
1020
    function FindMatchingBracket(PhysStartBracket: TPoint;
 
1021
                                 StartIncludeNeighborChars, MoveCaret,
 
1022
                                 SelectBrackets, OnlyVisible: Boolean
 
1023
                                 ): TPoint; virtual;
 
1024
    //code fold
 
1025
    procedure CodeFoldAction(iLine: integer); deprecated;
 
1026
    procedure UnfoldAll;
 
1027
    procedure FoldAll(StartLevel : Integer = 0; IgnoreNested : Boolean = False);
857
1028
    property FoldState: String read GetFoldState write SetFoldState;
858
 
    property CanPaste: Boolean read GetCanPaste;
859
 
    property CanRedo: boolean read GetCanRedo;
860
 
    property CanUndo: boolean read GetCanUndo;
861
 
    property CaretX: Integer read GetCaretX write SetCaretX;
862
 
    property CaretY: Integer read GetCaretY write SetCaretY;
863
 
    property CaretXY: TPoint read GetCaretXY write SetCaretXY;// screen position
864
 
    property LogicalCaretXY: TPoint read GetLogicalCaretXY write SetLogicalCaretXY;
865
 
    property CharsInWindow: Integer read fCharsInWindow;
866
 
    property CharWidth: integer read fCharWidth;
867
 
    property Color default clWhite;
868
 
    property Beautifier: TSynCustomBeautifier read fBeautifier write SetBeautifier;
869
 
    {$IFDEF SYN_LAZARUS}
870
 
    property CtrlMouseActive: boolean read fCtrlMouseActive; deprecated;        // deprecated in 0.9.29
871
 
    {$ENDIF}
872
 
    {$IFDEF SYN_LAZARUS}
873
 
    property SelStart: Integer read GetSelStart write SetSelStart;
874
 
    property SelEnd: Integer read GetSelEnd write SetSelEnd;
875
 
    property UseIncrementalColor : Boolean write SetUseIncrementalColor;
876
 
    {$ENDIF}
877
 
    property GutterWidth: Integer read GetGutterWidth; deprecated; // deprecated in 0.9.29 (08/2010)
878
 
    property Highlighter: TSynCustomHighlighter
879
 
      read fHighlighter write SetHighlighter;
880
 
    property LeftChar: Integer read fLeftChar write SetLeftChar;
881
 
    property LineHeight: integer read fTextHeight;
882
 
    property LinesInWindow: Integer read fLinesInWindow; // MG: fully visible lines
883
 
    property LineText: string read GetLineText write SetLineText;
884
 
    property Text: string read SynGetText write SynSetText;                     // No uncommited (trailing/trimmable) spaces
885
 
    property Marks: TSynEditMarkList read fMarkList;
 
1029
 
 
1030
    procedure AddKey(Command: TSynEditorCommand; Key1: word; SS1: TShiftState;
 
1031
      Key2: word; SS2: TShiftState);
 
1032
  public
 
1033
    property CharsInWindow: Integer read GetCharsInWindow;
 
1034
    property CharWidth: integer read GetCharWidth;
 
1035
    property LeftChar: Integer read GetLeftChar write SetLeftChar;
 
1036
    property LineHeight: integer read GetLineHeight;
 
1037
    property LinesInWindow: Integer read GetLinesInWindow;
886
1038
    property MaxLeftChar: integer read fMaxLeftChar write SetMaxLeftChar
887
1039
      default 1024;
 
1040
    property TopLine: Integer read GetTopLine write SetTopLine;
 
1041
 
 
1042
    property UseIncrementalColor : Boolean write SetUseIncrementalColor;
888
1043
    property Modified: Boolean read GetModified write SetModified;
889
1044
    property PaintLock: Integer read fPaintLock;
890
 
    property ReadOnly: Boolean read GetReadOnly write SetReadOnly default FALSE;
891
 
    property SelAvail: Boolean read GetSelAvail;
892
 
    property SelText: string read GetSelText write SetSelTextExternal;
893
 
    // Logical Points
894
 
    property TextBetweenPoints[aStartPoint, aEndPoint: TPoint]: String
895
 
      read GetTextBetweenPoints write SetTextBetweenPoints;
896
 
    property TextBetweenPointsEx[aStartPoint, aEndPoint: TPoint; CaretMode: TSynCaretAdjustMode]: String
897
 
      write SetTextBetweenPointsEx;
898
 
    property TopLine: Integer read fTopLine write SetTopLine;
899
 
    {$IFDEF SYN_LAZARUS}
 
1045
 
900
1046
    property UseUTF8: boolean read FUseUTF8;
901
 
    procedure Update; override;
902
1047
    procedure Invalidate; override;
903
1048
    property ChangeStamp: int64 read GetChangeStamp;
904
 
    {$ENDIF}
905
1049
    procedure ShareTextBufferFrom(AShareEditor: TCustomSynEdit);
906
1050
    procedure UnShareTextBuffer;
907
 
  public
908
 
    property OnKeyDown;
909
 
    property OnKeyPress;
910
 
    property OnProcessCommand: TProcessCommandEvent
911
 
      read FOnProcessCommand write FOnProcessCommand;
 
1051
 
912
1052
    function PluginCount: Integer;
913
 
    property Plugin[Index: Integer]: TSynEditPlugin read GetPlugin;
 
1053
    property Plugin[Index: Integer]: TLazSynEditPlugin read GetPlugin;
914
1054
    function MarkupCount: Integer;
915
1055
    property Markup[Index: integer]: TSynEditMarkup read GetMarkup;
916
1056
    property MarkupByClass[Index: TSynEditMarkupClass]: TSynEditMarkup
917
1057
      read GetMarkupByClass;
918
1058
    property TrimSpaceType: TSynEditStringTrimmingType
919
1059
      read GetTrimSpaceType write SetTrimSpaceType;
920
 
  protected
921
 
    property BookMarkOptions: TSynBookMarkOpt
922
 
      read fBookMarkOpt write fBookMarkOpt;
923
 
    property BlockIndent: integer read fBlockIndent write SetBlockIndent default 2;
924
 
    property ExtraCharSpacing: integer
925
 
      read fExtraCharSpacing write SetExtraCharSpacing default 0;
926
 
    property ExtraLineSpacing: integer
927
 
      read fExtraLineSpacing write SetExtraLineSpacing default 0;
 
1060
  public
 
1061
    // Caret
 
1062
    property InsertCaret: TSynEditCaretType read FInsertCaret write SetInsertCaret default ctVerticalLine;
 
1063
    property OverwriteCaret: TSynEditCaretType read FOverwriteCaret write SetOverwriteCaret default ctBlock;
 
1064
 
 
1065
    // Selection
 
1066
    property HideSelection: boolean read fHideSelection write SetHideSelection default false;
 
1067
    property DefaultSelectionMode: TSynSelectionMode read GetDefSelectionMode write SetDefSelectionMode default smNormal;
 
1068
    property SelectionMode: TSynSelectionMode read GetSelectionMode write SetSelectionMode default smNormal;
 
1069
    property SelectedColor: TSynSelectedColor read GetSelectedColor write SetSelectedColor;
 
1070
 
 
1071
    // Colors
 
1072
    property Color default clWhite;
 
1073
    property IncrementColor: TSynSelectedColor read GetIncrementColor write SetIncrementColor;
 
1074
    property HighlightAllColor: TSynSelectedColor read GetHighlightAllColor write SetHighlightAllColor;
 
1075
    property BracketMatchColor: TSynSelectedColor read GetBracketMatchColor write SetBracketMatchColor;
 
1076
    property MouseLinkColor: TSynSelectedColor read GetMouseLinkColor write SetMouseLinkColor;
 
1077
    property LineHighlightColor: TSynSelectedColor read GetLineHighlightColor write SetLineHighlightColor;
 
1078
    property FoldedCodeColor: TSynSelectedColor read GetFoldedCodeColor write SetFoldedCodeColor;
 
1079
 
 
1080
    property Beautifier: TSynCustomBeautifier read fBeautifier write SetBeautifier;
 
1081
    property BookMarkOptions: TSynBookMarkOpt read fBookMarkOpt write fBookMarkOpt;
 
1082
    property BlockIndent: integer read FBlockIndent write SetBlockIndent default 2;
 
1083
    property BlockTabIndent: integer read FBlockTabIndent write SetBlockTabIndent default 0;
 
1084
    property ExtraCharSpacing: integer read fExtraCharSpacing write SetExtraCharSpacing default 0;
 
1085
    property ExtraLineSpacing: integer read fExtraLineSpacing write SetExtraLineSpacing default 0;
 
1086
    property Highlighter: TSynCustomHighlighter read fHighlighter write SetHighlighter;
928
1087
    property Gutter: TSynGutter read FLeftGutter write SetGutter;
929
1088
    property RightGutter: TSynGutter read FRightGutter write SetRightGutter;
930
 
    property HideSelection: boolean read fHideSelection write SetHideSelection
931
 
      default false;
932
 
    property InsertCaret: TSynEditCaretType read FInsertCaret
933
 
      write SetInsertCaret default ctVerticalLine;
934
1089
    property InsertMode: boolean read fInserting write SetInsertMode
935
1090
      default true;
936
1091
    property Keystrokes: TSynEditKeyStrokes
937
1092
      read FKeystrokes write SetKeystrokes;
938
1093
    property MouseActions: TSynEditMouseActions
939
 
      read FMouseActions write SetMouseActions;
 
1094
      read GetMouseActions write SetMouseActions;
 
1095
    property MouseTextActions: TSynEditMouseActions
 
1096
      read GetMouseTextActions write SetMouseTextActions;
940
1097
    property MouseSelActions: TSynEditMouseActions // Mouseactions, if mouse is over selection => fallback to normal
941
 
      read FMouseSelActions write SetMouseSelActions;
 
1098
      read GetMouseSelActions write SetMouseSelActions;
942
1099
    property MaxUndo: Integer read GetMaxUndo write SetMaxUndo default 1024;
943
 
    property Options: TSynEditorOptions read fOptions write SetOptions          // See SYNEDIT_UNIMPLEMENTED_OPTIONS for deprecated Values
 
1100
    property Options: TSynEditorOptions read FOptions write SetOptions          // See SYNEDIT_UNIMPLEMENTED_OPTIONS for deprecated Values
944
1101
      default SYNEDIT_DEFAULT_OPTIONS;
945
 
    property Options2: TSynEditorOptions2 read fOptions2 write SetOptions2
 
1102
    property Options2: TSynEditorOptions2 read FOptions2 write SetOptions2
946
1103
      default SYNEDIT_DEFAULT_OPTIONS2;
 
1104
    property MouseOptions: TSynEditorMouseOptions read FMouseOptions write SetMouseOptions
 
1105
      default SYNEDIT_DEFAULT_MOUSE_OPTIONS;
947
1106
    property ShareOptions: TSynEditorShareOptions read FShareOptions write SetShareOptions
948
1107
      default SYNEDIT_DEFAULT_SHARE_OPTIONS; experimental;
949
 
    property OverwriteCaret: TSynEditCaretType read FOverwriteCaret
950
 
      write SetOverwriteCaret default ctBlock;
951
 
    property RightEdge: Integer read fRightEdge write SetRightEdge default 80;
952
 
    property RightEdgeColor: TColor
953
 
      read fRightEdgeColor write SetRightEdgeColor default clSilver;
 
1108
    property VisibleSpecialChars: TSynVisibleSpecialChars read FVisibleSpecialChars write SetVisibleSpecialChars;
 
1109
    property ReadOnly: Boolean read GetReadOnly write SetReadOnly default FALSE;
 
1110
    property RightEdge: Integer read GetRightEdge write SetRightEdge default 80;
 
1111
    property RightEdgeColor: TColor read GetRightEdgeColor write SetRightEdgeColor default clSilver;
954
1112
    property ScrollBars: TScrollStyle
955
1113
      read FScrollBars write SetScrollBars default ssBoth;
956
 
    property SelectedColor: TSynSelectedColor
957
 
    read GetSelectedColor write SetSelectedColor;  // Setter for compatibility
958
 
    property IncrementColor: TSynSelectedColor read GetIncrementColor;
959
 
    property HighlightAllColor: TSynSelectedColor read GetHighlightAllColor;
960
 
    property BracketMatchColor: TSynSelectedColor read GetBracketMatchColor;
961
 
    property MouseLinkColor: TSynSelectedColor read GetMouseLinkColor;
962
 
    property LineHighlightColor: TSynSelectedColor read GetLineHighlightColor;
963
 
    property FoldedCodeColor: TSynSelectedColor read GetFoldedCodeColor;
964
1114
    property BracketHighlightStyle: TSynEditBracketHighlightStyle
965
1115
      read GetBracketHighlightStyle write SetBracketHighlightStyle;
966
 
    property DefaultSelectionMode: TSynSelectionMode
967
 
      read GetDefSelectionMode write SetDefSelectionMode default smNormal;
968
 
    property SelectionMode: TSynSelectionMode
969
 
      read GetSelectionMode write SetSelectionMode default smNormal;
970
 
    // See Highlighter for new methods
971
 
    property CFDividerDrawLevel: Integer
972
 
      read GetDividerDrawLevel write SetDividerDrawLevel; deprecated;
973
1116
    property TabWidth: integer read fTabWidth write SetTabWidth default 8;
974
 
    property WantTabs: boolean read fWantTabs write SetWantTabs default FALSE;
 
1117
    property WantTabs: boolean read fWantTabs write SetWantTabs default True;
 
1118
 
 
1119
    // Events
975
1120
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
976
1121
    property OnChangeUpdating: TChangeUpdatingEvent read FOnChangeUpdating write FOnChangeUpdating;
977
1122
    property OnCutCopy: TSynCopyPasteEvent read FOnCutCopy write FOnCutCopy;
978
1123
    property OnPaste: TSynCopyPasteEvent read FOnPaste write FOnPaste;
979
 
    property OnCommandProcessed: TProcessCommandEvent
980
 
      read fOnCommandProcessed write fOnCommandProcessed;
981
1124
    property OnDropFiles: TSynDropFilesEvent read fOnDropFiles write fOnDropFiles;
982
 
    property OnGutterClick: TGutterClickEvent
983
 
      read GetOnGutterClick write SetOnGutterClick;
 
1125
    property OnGutterClick: TGutterClickEvent read GetOnGutterClick write SetOnGutterClick;
984
1126
    property OnPaint: TPaintEvent read fOnPaint write fOnPaint;
985
1127
    // OnPlaceBookmark only triggers for Bookmarks
986
1128
    property OnPlaceBookmark: TPlaceMarkEvent read FOnPlaceMark write FOnPlaceMark;
987
1129
    // OnClearBookmark only triggers for Bookmarks
988
1130
    property OnClearBookmark: TPlaceMarkEvent read FOnClearMark write FOnClearMark;
989
 
    property OnProcessUserCommand: TProcessCommandEvent
990
 
      read FOnProcessUserCommand write FOnProcessUserCommand;
991
 
    property OnReplaceText: TReplaceTextEvent read fOnReplaceText
992
 
      write fOnReplaceText;
993
 
    {$IFDEF SYN_LAZARUS}
994
 
    property OnSpecialLineColors: TSpecialLineColorsEvent
995
 
      read FOnSpecialLineColors write SetSpecialLineColors;  deprecated;
996
 
    {$ELSE}
997
 
    property OnSpecialLineColors: TSpecialLineColorsEvent
998
 
      read fOnSpecialLineColors write fOnSpecialLineColors;
999
 
    {$ENDIF}
1000
 
    {$IFDEF SYN_LAZARUS}
1001
 
    property OnSpecialLineMarkup: TSpecialLineMarkupEvent
1002
 
      read FOnSpecialLineMarkup write SetSpecialLineMarkup;
1003
 
    {$ENDIF}
1004
 
    property OnStatusChange: TStatusChangeEvent
1005
 
      read fOnStatusChange write fOnStatusChange;
 
1131
    property OnKeyDown;
 
1132
    property OnKeyPress;
 
1133
    property OnProcessCommand: TProcessCommandEvent read FOnProcessCommand write FOnProcessCommand;
 
1134
    property OnProcessUserCommand: TProcessCommandEvent  read FOnProcessUserCommand write FOnProcessUserCommand;
 
1135
    property OnCommandProcessed: TProcessCommandEvent read fOnCommandProcessed write fOnCommandProcessed;
 
1136
    property OnReplaceText: TReplaceTextEvent read fOnReplaceText write fOnReplaceText;
 
1137
    property OnSpecialLineColors: TSpecialLineColorsEvent read FOnSpecialLineColors write SetSpecialLineColors;  deprecated;
 
1138
    property OnSpecialLineMarkup: TSpecialLineMarkupEvent read FOnSpecialLineMarkup write SetSpecialLineMarkup;
 
1139
    property OnStatusChange: TStatusChangeEvent read fOnStatusChange write fOnStatusChange;
1006
1140
  end;
1007
1141
 
1008
1142
  TSynEdit = class(TCustomSynEdit)
1009
 
  public
1010
 
    property ShareOptions;
1011
1143
  published
1012
1144
    // inherited properties
1013
1145
    property Align;
1014
1146
    property Beautifier;
1015
1147
    property BlockIndent;
 
1148
    property BlockTabIndent;
1016
1149
    property BorderSpacing;
1017
 
{$IFNDEF SYN_LAZARUS}
1018
 
    property Ctl3D;
1019
 
    property ParentCtl3D;
1020
 
{$ENDIF}
1021
1150
{$IFDEF SYN_COMPILER_4_UP}
1022
1151
    property Anchors;
1023
1152
    property Constraints;
1024
1153
{$ENDIF}
1025
1154
    property Color;
1026
 
    {$IFDEF SYN_LAZARUS}
1027
1155
    property Cursor default crIBeam;
1028
 
    {$ENDIF}
1029
1156
    property Enabled;
1030
1157
    property Font;
1031
1158
    property Height;
1043
1170
    // inherited events
1044
1171
    property OnClick;
1045
1172
    property OnDblClick;
1046
 
    {$IFDEF SYN_LAZARUS}
1047
1173
    property OnTripleClick;
1048
1174
    property OnQuadClick;
1049
 
    {$ENDIF}
1050
1175
    property OnDragDrop;
1051
1176
    property OnDragOver;
1052
1177
{$IFDEF SYN_COMPILER_4_UP}
1062
1187
    property OnMouseDown;
1063
1188
    property OnMouseMove;
1064
1189
    property OnMouseUp;
1065
 
    {$IFDEF SYN_LAZARUS}
1066
1190
    property OnClickLink : TMouseEvent read FOnClickLink write FOnClickLink;
1067
1191
    property OnMouseLink: TSynMouseLinkEvent read FOnMouseLink write FOnMouseLink;
1068
1192
    property OnMouseEnter;
1069
1193
    property OnMouseLeave;
1070
 
    {$ENDIF}
1071
1194
{$IFDEF SYN_COMPILER_4_UP}
1072
1195
// ToDo Docking
1073
1196
    property OnStartDock;
1092
1215
    property MaxUndo;
1093
1216
    property Options;
1094
1217
    property Options2;
 
1218
    property MouseOptions;
 
1219
    property VisibleSpecialChars;
1095
1220
    property OverwriteCaret;
1096
1221
    property ReadOnly;
1097
1222
    property RightEdge;
1098
1223
    property RightEdgeColor;
1099
1224
    property ScrollBars;
1100
1225
    property SelectedColor;
1101
 
    {$IFDEF SYN_LAZARUS}
1102
1226
    property IncrementColor;
1103
1227
    property HighlightAllColor;
1104
1228
    property BracketHighlightStyle;
1106
1230
    property FoldedCodeColor;
1107
1231
    property MouseLinkColor;
1108
1232
    property LineHighlightColor;
1109
 
    {$ENDIF}
1110
1233
    property DefaultSelectionMode;
1111
1234
    property SelectionMode;
1112
1235
    property TabWidth;
1125
1248
    property OnProcessCommand;
1126
1249
    property OnProcessUserCommand;
1127
1250
    property OnReplaceText;
 
1251
    property OnShowHint;
1128
1252
    property OnSpecialLineColors; deprecated;
1129
 
    {$IFDEF SYN_LAZARUS}
1130
1253
    property OnSpecialLineMarkup;
1131
 
    {$ENDIF}
1132
1254
    property OnStatusChange;
1133
1255
  end;
1134
1256
 
1167
1289
    FCaretPos: TPoint;
1168
1290
  protected
1169
1291
    function IsEqualContent(AnItem: TSynEditUndoItem): Boolean; override;
 
1292
    function DebugString: String; override;
1170
1293
  public
1171
1294
    constructor Create(CaretPos: TPoint);
1172
1295
    function IsCaretInfo: Boolean; override;
1181
1304
    FBlockMode: TSynSelectionMode;
1182
1305
  protected
1183
1306
    function IsEqualContent(AnItem: TSynEditUndoItem): Boolean; override;
 
1307
    function DebugString: String; override;
1184
1308
  public
1185
1309
    function IsCaretInfo: Boolean; override;
1186
1310
    constructor Create(CaretPos, BeginPos, EndPos: TPoint; BlockMode: TSynSelectionMode);
1191
1315
 
1192
1316
  TSynEditUndoIndent = class(TSynEditUndoItem)
1193
1317
  public
1194
 
    FPosY1, FPosY2, FCnt: Integer;
 
1318
    FPosY1, FPosY2, FCnt, FTabCnt: Integer;
1195
1319
  public
1196
 
    constructor Create(APosY, EPosY, ACnt: Integer);
 
1320
    constructor Create(APosY, EPosY, ACnt, ATabCnt: Integer);
1197
1321
    function PerformUndo(Caller: TObject): Boolean; override;
1198
1322
  end;
1199
1323
 
1208
1332
    function PerformUndo(Caller: TObject): Boolean; override;
1209
1333
  end;
1210
1334
 
 
1335
  { TSynEditMouseGlobalActions }
 
1336
 
 
1337
  TSynEditMouseGlobalActions = class(TSynEditMouseInternalActions)
 
1338
  protected
 
1339
    procedure InitForOptions(AnOptions: TSynEditorMouseOptions); override;
 
1340
  end;
 
1341
 
 
1342
  { TSynEditMouseTextActions }
 
1343
 
 
1344
  TSynEditMouseTextActions = class(TSynEditMouseInternalActions)
 
1345
  protected
 
1346
    procedure InitForOptions(AnOptions: TSynEditorMouseOptions); override;
 
1347
  end;
 
1348
 
 
1349
  { TSynEditMouseSelActions }
 
1350
 
 
1351
  TSynEditMouseSelActions = class(TSynEditMouseInternalActions)
 
1352
  protected
 
1353
    procedure InitForOptions(AnOptions: TSynEditorMouseOptions); override;
 
1354
  end;
 
1355
 
 
1356
  { THookedCommandHandlerEntry }
 
1357
 
 
1358
  THookedCommandHandlerEntry = class(TObject)
 
1359
  private
 
1360
    FEvent: THookedCommandEvent;
 
1361
    FData: pointer;
 
1362
    FFlags: THookedCommandFlags;
 
1363
    function Equals(AEvent: THookedCommandEvent): boolean; reintroduce;
 
1364
  public
 
1365
    constructor Create(AEvent: THookedCommandEvent; AData: pointer; AFlags: THookedCommandFlags);
 
1366
  end;
 
1367
 
1211
1368
{ TSynEditUndoCaret }
1212
1369
 
1213
1370
function TSynEditUndoCaret.IsEqualContent(AnItem: TSynEditUndoItem): Boolean;
1216
1373
        and (FCaretPos.y = TSynEditUndoCaret(AnItem).FCaretPos.y);
1217
1374
end;
1218
1375
 
 
1376
function TSynEditUndoCaret.DebugString: String;
 
1377
begin
 
1378
  Result := 'CaretPos='+dbgs(FCaretPos);
 
1379
end;
 
1380
 
1219
1381
constructor TSynEditUndoCaret.Create(CaretPos: TPoint);
1220
1382
begin
1221
1383
  FCaretPos := CaretPos;
 
1384
  {$IFDEF SynUndoDebugItems}debugln(['---  Undo Insert ',DbgSName(self), ' ', dbgs(Self), ' - ', DebugString]);{$ENDIF}
1222
1385
end;
1223
1386
 
1224
1387
function TSynEditUndoCaret.IsCaretInfo: Boolean;
1228
1391
 
1229
1392
function TSynEditUndoCaret.PerformUndo(Caller: TObject): Boolean;
1230
1393
begin
1231
 
  Result := Caller is TSynEdit;
 
1394
  Result := Caller is TCustomSynEdit;
1232
1395
  if Result then
1233
 
    with TSynEdit(Caller) do begin
 
1396
    {$IFDEF SynUndoDebugItems}debugln(['---  Undo Perform ',DbgSName(self), ' ', dbgs(Self), ' - ', DebugString]);{$ENDIF}
 
1397
    with TCustomSynEdit(Caller) do begin
1234
1398
      FCaret.LineCharPos := FCaretPos;
1235
1399
      FTheLinesView.CurUndoList.AddChange(TSynEditUndoCaret.Create(FCaretPos));
1236
1400
    end;
1245
1409
  FBeginPos := BeginPos;
1246
1410
  FEndPos   := EndPos;
1247
1411
  FBlockMode := BlockMode;
 
1412
  {$IFDEF SynUndoDebugItems}debugln(['---  Undo Insert ',DbgSName(self), ' ', dbgs(Self), ' - ', DebugString]);{$ENDIF}
1248
1413
end;
1249
1414
 
1250
1415
function TSynEditUndoSelCaret.IsEqualContent(AnItem: TSynEditUndoItem): Boolean;
1258
1423
        and (FBlockMode = TSynEditUndoSelCaret(AnItem).FBlockMode);
1259
1424
end;
1260
1425
 
 
1426
function TSynEditUndoSelCaret.DebugString: String;
 
1427
begin
 
1428
  Result := 'CaretPos='+dbgs(FCaretPos) + ' Begin=' + dbgs(FBeginPos) + ' End=' + dbgs(FEndPos) + ' Mode=' + dbgs(ord(FBlockMode));
 
1429
end;
 
1430
 
1261
1431
function TSynEditUndoSelCaret.IsCaretInfo: Boolean;
1262
1432
begin
1263
1433
  Result := True;
1265
1435
 
1266
1436
function TSynEditUndoSelCaret.PerformUndo(Caller: TObject): Boolean;
1267
1437
begin
1268
 
  Result := Caller is TSynEdit;
 
1438
  Result := Caller is TCustomSynEdit;
1269
1439
  if Result then
1270
 
    with TSynEdit(Caller) do begin
 
1440
    {$IFDEF SynUndoDebugItems}debugln(['---  Undo Perform ',DbgSName(self), ' ', dbgs(Self), ' - ', DebugString]);{$ENDIF}
 
1441
    with TCustomSynEdit(Caller) do begin
1271
1442
      SetCaretAndSelection(FCaretPos, FBeginPos, FEndPos, FBlockMode, True);
1272
1443
      FTheLinesView.CurUndoList.AddChange(TSynEditUndoSelCaret.Create(FCaretPos, FBeginPos,
1273
1444
                                                     FEndPos, FBlockMode));
1276
1447
 
1277
1448
{ TSynEditUndoIndent }
1278
1449
 
1279
 
constructor TSynEditUndoIndent.Create(APosY, EPosY, ACnt: Integer);
 
1450
constructor TSynEditUndoIndent.Create(APosY, EPosY, ACnt, ATabCnt: Integer);
1280
1451
begin
1281
1452
  FPosY1 := APosY;
1282
1453
  FPosY2 := EPosY;
1283
 
  FCnt :=  ACnt;
 
1454
  FCnt    :=  ACnt;
 
1455
  FTabCnt := ATabCnt;
1284
1456
end;
1285
1457
 
1286
1458
function TSynEditUndoIndent.PerformUndo(Caller: TObject): Boolean;
1311
1483
  end;
1312
1484
end;
1313
1485
 
 
1486
{ TSynEditMouseGlobalActions }
 
1487
 
 
1488
procedure TSynEditMouseGlobalActions.InitForOptions(AnOptions: TSynEditorMouseOptions);
 
1489
begin
 
1490
  AddCommand(emcWheelScrollDown,       False,  mbXWheelDown, ccAny, cdDown, [], []);
 
1491
  AddCommand(emcWheelScrollUp,         False,  mbXWheelUp, ccAny, cdDown, [], []);
 
1492
 
 
1493
  if emCtrlWheelZoom in AnOptions then begin
 
1494
    AddCommand(emcWheelZoomOut,        False,  mbXWheelDown, ccAny, cdDown, [ssCtrl], [ssCtrl]);
 
1495
    AddCommand(emcWheelZoomIn,         False,  mbXWheelUp,   ccAny, cdDown, [ssCtrl], [ssCtrl]);
 
1496
  end;
 
1497
end;
 
1498
 
 
1499
{ TSynEditMouseTextActions }
 
1500
 
 
1501
procedure TSynEditMouseTextActions.InitForOptions(AnOptions: TSynEditorMouseOptions);
 
1502
var
 
1503
  rmc: Boolean;
 
1504
begin
 
1505
  Clear;
 
1506
  rmc := (emRightMouseMovesCursor in AnOptions);
 
1507
  //// eoRightMouseMovesCursor
 
1508
  //if (eoRightMouseMovesCursor in ChangedOptions) then begin
 
1509
  //  for i := FMouseActions.Count-1 downto 0 do
 
1510
  //    if FMouseActions[i].Button = mbXRight then
 
1511
  //      FMouseActions[i].MoveCaret := (eoRightMouseMovesCursor in fOptions);
 
1512
  //end;
 
1513
 
 
1514
  AddCommand(emcStartSelections,       True,  mbXLeft, ccSingle, cdDown, [],        [ssShift, ssAlt], emcoSelectionStart);
 
1515
  AddCommand(emcStartSelections,       True,  mbXLeft, ccSingle, cdDown, [ssShift], [ssShift, ssAlt], emcoSelectionContinue);
 
1516
  if (emAltSetsColumnMode in AnOptions) then begin
 
1517
    AddCommand(emcStartColumnSelections, True,  mbXLeft, ccSingle, cdDown, [ssAlt],          [ssShift, ssAlt], emcoSelectionStart);
 
1518
    AddCommand(emcStartColumnSelections, True,  mbXLeft, ccSingle, cdDown, [ssShift, ssAlt], [ssShift, ssAlt], emcoSelectionContinue);
 
1519
  end;
 
1520
  if (emShowCtrlMouseLinks in AnOptions) then
 
1521
    AddCommand(emcMouseLink,             False, mbXLeft, ccSingle, cdUp, [SYNEDIT_LINK_MODIFIER], [ssShift, ssAlt, ssCtrl]);
 
1522
 
 
1523
  if (emDoubleClickSelectsLine in AnOptions) then begin
 
1524
    AddCommand(emcSelectLine,            True,  mbXLeft, ccDouble, cdDown, [], []);
 
1525
    AddCommand(emcSelectPara,            True,  mbXLeft, ccTriple, cdDown, [], []);
 
1526
  end
 
1527
  else begin
 
1528
    AddCommand(emcSelectWord,            True,  mbXLeft, ccDouble, cdDown, [], []);
 
1529
    AddCommand(emcSelectLine,            True,  mbXLeft, ccTriple, cdDown, [], []);
 
1530
  end;
 
1531
  AddCommand(emcSelectPara,            True,  mbXLeft, ccQuad,   cdDown, [], []);
 
1532
 
 
1533
  AddCommand(emcContextMenu,           rmc,   mbXRight, ccSingle, cdUp, [], [], emcoSelectionCaretMoveNever);
 
1534
 
 
1535
  AddCommand(emcPasteSelection,        True,  mbXMiddle, ccSingle, cdDown, [], []);
 
1536
end;
 
1537
 
 
1538
{ TSynEditMouseSelActions }
 
1539
 
 
1540
procedure TSynEditMouseSelActions.InitForOptions(AnOptions: TSynEditorMouseOptions);
 
1541
begin
 
1542
  Clear;
 
1543
  //rmc := (eoRightMouseMovesCursor in AnOptions);
 
1544
 
 
1545
  if (emDragDropEditing in AnOptions) then
 
1546
    AddCommand(emcStartDragMove, False, mbXLeft, ccSingle, cdDown, [], []);
 
1547
end;
 
1548
 
1314
1549
{ THookedCommandHandlerEntry }
1315
1550
 
1316
 
type
1317
 
  THookedCommandHandlerEntry = class(TObject)
1318
 
  private
1319
 
    fEvent: THookedCommandEvent;
1320
 
    fData: pointer;
1321
 
    function Equals(AEvent: THookedCommandEvent): boolean; reintroduce;
1322
 
  {$IFDEF SYN_LAZARUS}
1323
 
  public
1324
 
  {$ENDIF}
1325
 
    constructor Create(AEvent: THookedCommandEvent; AData: pointer);
1326
 
  end;
1327
 
 
1328
 
constructor THookedCommandHandlerEntry.Create(AEvent: THookedCommandEvent;
1329
 
  AData: pointer);
 
1551
constructor THookedCommandHandlerEntry.Create(AEvent: THookedCommandEvent; AData: pointer;
 
1552
  AFlags: THookedCommandFlags);
1330
1553
begin
1331
1554
  inherited Create;
1332
1555
  fEvent := AEvent;
1333
1556
  fData := AData;
 
1557
  FFlags := AFlags;
1334
1558
end;
1335
1559
 
1336
1560
function THookedCommandHandlerEntry.Equals(AEvent: THookedCommandEvent): boolean;
1349
1573
    SynDefaultFontHeight := 14;
1350
1574
    {$DEFINE SynDefaultFont}
1351
1575
  {$ENDIF}
1352
 
  {$IFDEF LCLgtk2}
1353
 
    SynDefaultFontName   := 'Courier New';
1354
 
    SynDefaultFontHeight := -13;
1355
 
    if Screen.Fonts.IndexOf(SynDefaultFontName) >= 0 then
1356
 
      exit;
1357
 
    SynDefaultFontName   := '-misc-dejavu sans mono-medium-r-normal-*-*-90-*-*-*-*-iso10646-1';
1358
 
    SynDefaultFontHeight := 9;
1359
 
    {$DEFINE SynDefaultFont}
1360
 
  {$ENDIF}
1361
1576
  {$IFDEF LCLcarbon}
1362
1577
    SynDefaultFontName   := 'Monaco'; // Note: carbon is case sensitive
1363
1578
    SynDefaultFontHeight := 12;
1364
1579
    {$DEFINE SynDefaultFont}
1365
1580
  {$ENDIF}
 
1581
  // LCLgtk2 and LCLQt use default settings
1366
1582
  {$IFnDEF SynDefaultFont}
1367
1583
    SynDefaultFontName   := 'Courier New';
1368
1584
    SynDefaultFontHeight := -13;
1397
1613
  Result := TSynEditStringList(FLines).TextChangeStamp;
1398
1614
end;
1399
1615
 
 
1616
function TCustomSynEdit.GetCharsInWindow: Integer;
 
1617
begin
 
1618
  Result := FTextArea.CharsInWindow;
 
1619
end;
 
1620
 
 
1621
function TCustomSynEdit.GetCharWidth: integer;
 
1622
begin
 
1623
  Result := FTextArea.CharWidth;
 
1624
end;
 
1625
 
1400
1626
function TCustomSynEdit.GetDefSelectionMode: TSynSelectionMode;
1401
1627
begin
1402
1628
  Result := FBlockSelection.SelectionMode;
1407
1633
  Result := FFoldedLinesView.GetFoldDescription(0, 0, -1, -1, True);
1408
1634
end;
1409
1635
 
1410
 
function TCustomSynEdit.GetGutterWidth: Integer;
1411
 
begin
1412
 
  Result := FLeftGutter.Width;
 
1636
function TCustomSynEdit.GetLeftChar: Integer;
 
1637
begin
 
1638
  Result := FTextArea.LeftChar;
 
1639
end;
 
1640
 
 
1641
function TCustomSynEdit.GetLineHeight: integer;
 
1642
begin
 
1643
  Result := FTextArea.LineHeight;
 
1644
end;
 
1645
 
 
1646
function TCustomSynEdit.GetLinesInWindow: Integer;
 
1647
begin
 
1648
  Result := FTextArea.LinesInWindow;
1413
1649
end;
1414
1650
 
1415
1651
function TCustomSynEdit.GetModified: Boolean;
1417
1653
  Result := TSynEditStringList(FLines).Modified;
1418
1654
end;
1419
1655
 
 
1656
function TCustomSynEdit.GetMouseActions: TSynEditMouseActions;
 
1657
begin
 
1658
  Result := FMouseActions.UserActions;
 
1659
end;
 
1660
 
 
1661
function TCustomSynEdit.GetMouseSelActions: TSynEditMouseActions;
 
1662
begin
 
1663
  Result := FMouseSelActions.UserActions;
 
1664
end;
 
1665
 
 
1666
function TCustomSynEdit.GetMouseTextActions: TSynEditMouseActions;
 
1667
begin
 
1668
  Result := FMouseTextActions.UserActions;
 
1669
end;
 
1670
 
1420
1671
function TCustomSynEdit.GetPaintLockOwner: TSynEditBase;
1421
1672
begin
1422
1673
  Result := TSynEditStringList(FLines).PaintLockOwner;
1423
1674
end;
1424
1675
 
1425
 
function TCustomSynEdit.GetPlugin(Index: Integer): TSynEditPlugin;
1426
 
begin
1427
 
  Result := TSynEditPlugin(fPlugins[Index]);
 
1676
function TCustomSynEdit.GetPlugin(Index: Integer): TLazSynEditPlugin;
 
1677
begin
 
1678
  Result := TLazSynEditPlugin(fPlugins[Index]);
 
1679
end;
 
1680
 
 
1681
function TCustomSynEdit.GetRightEdge: Integer;
 
1682
begin
 
1683
  Result := FTextArea.RightEdgeColumn;
 
1684
end;
 
1685
 
 
1686
function TCustomSynEdit.GetRightEdgeColor: TColor;
 
1687
begin
 
1688
  Result := FTextArea.RightEdgeColor;
1428
1689
end;
1429
1690
 
1430
1691
function TCustomSynEdit.GetTextBetweenPoints(aStartPoint, aEndPoint: TPoint): String;
1435
1696
  Result := FInternalBlockSelection.SelText;
1436
1697
end;
1437
1698
 
1438
 
function TCustomSynEdit.GetDividerDrawLevel: Integer;
1439
 
begin
1440
 
  Result := fHighlighter.DrawDividerLevel;
 
1699
function TCustomSynEdit.GetTopLine: Integer;
 
1700
begin
 
1701
  Result := FFoldedLinesView.ViewPosToTextIndex(FTextArea.TopLine) + 1;
 
1702
end;
 
1703
 
 
1704
procedure TCustomSynEdit.SetBlockTabIndent(AValue: integer);
 
1705
begin
 
1706
  if FBlockTabIndent = AValue then Exit;
 
1707
  FBlockTabIndent := AValue;
 
1708
end;
 
1709
 
 
1710
procedure TCustomSynEdit.SetBracketMatchColor(AValue: TSynSelectedColor);
 
1711
begin
 
1712
  fMarkupBracket.MarkupInfo.Assign(AValue);
1441
1713
end;
1442
1714
 
1443
1715
procedure TCustomSynEdit.SetDefSelectionMode(const AValue: TSynSelectionMode);
1445
1717
  FBlockSelection.SelectionMode := AValue; // Includes active
1446
1718
end;
1447
1719
 
 
1720
procedure TCustomSynEdit.SetFoldedCodeColor(AValue: TSynSelectedColor);
 
1721
begin
 
1722
  FFoldedLinesView.MarkupInfoFoldedCode.Assign(AValue);
 
1723
end;
 
1724
 
1448
1725
procedure TCustomSynEdit.SurrenderPrimarySelection;
1449
1726
begin
1450
1727
  if PrimarySelection.OnRequest=@PrimarySelectionRequest then
1451
1728
    PrimarySelection.OnRequest:=nil;
1452
1729
end;
1453
1730
 
1454
 
function TCustomSynEdit.PixelsToRowColumn(Pixels: TPoint): TPoint;
 
1731
function TCustomSynEdit.PixelsToRowColumn(Pixels: TPoint; aFlags: TSynCoordinateMappingFlags = [scmLimitToLines]): TPoint;
1455
1732
// converts the client area coordinate
1456
 
// to Caret position (screen position, (1,1) based)
1457
 
// To get the text/physical position use PixelsToLogicalPos
1458
 
var
1459
 
  f: Single;
 
1733
// to Caret position (physical position, (1,1) based)
 
1734
// To get the text/logical position use PixelsToLogicalPos
1460
1735
begin
1461
 
  f := ( (Pixels.X
1462
 
          + (fLeftChar-1) * fCharWidth
1463
 
          - TextLeftPixelOffset
1464
 
         ) / fCharWidth
1465
 
       )+1;
1466
 
  // don't return a partially visible last line
1467
 
  if Pixels.Y >= fLinesInWindow * fTextHeight then begin
1468
 
    Pixels.Y := fLinesInWindow * fTextHeight - 1;
1469
 
    if Pixels.Y < 0 then Pixels.Y := 0;
1470
 
  end;
1471
 
  Result := Point(RoundOff(f), ScreenRowToRow(Pixels.Y div fTextHeight));
1472
 
  {$IFDEF SYN_MBCSSUPPORT}
1473
 
  if (Result.Y >= 1) and (Result.Y <= Lines.Count) then begin
1474
 
    s := Lines[Result.Y - 1];
1475
 
    if (Length(s) >= Result.x) and (ByteType(s, Result.X) = mbTrailByte) then
1476
 
      if Frac(f) >= 0.5 then
1477
 
        Dec(Result.X)
1478
 
      else
1479
 
        Inc(Result.X);
1480
 
  end;
1481
 
  fMBCSStepAside := False;
1482
 
  {$ENDIF}
 
1736
  Result := FTextArea.PixelsToRowColumn(Pixels, aFlags);
 
1737
  Result := Point(Result.X, ScreenRowToRow(Result.Y, scmLimitToLines in aFlags));
1483
1738
end;
1484
1739
 
1485
 
{$IFDEF SYN_LAZARUS}
1486
1740
function TCustomSynEdit.PixelsToLogicalPos(const Pixels: TPoint): TPoint;
1487
1741
begin
1488
1742
  Result:=PhysicalToLogicalPos(PixelsToRowColumn(Pixels));
1489
1743
end;
1490
1744
 
1491
 
function TCustomSynEdit.ScreenRowToRow(ScreenRow: integer): integer;
 
1745
function TCustomSynEdit.ScreenRowToRow(ScreenRow: integer; LimitToLines: Boolean = True): integer;
1492
1746
// ScreenRow is 0-base
1493
1747
// result is 1-based
1494
1748
begin
1495
1749
  Result := FFoldedLinesView.ScreenLineToTextIndex(ScreenRow)+1;
 
1750
  if LimitToLines and (Result >= Lines.Count) then
 
1751
    Result := Lines.Count;
1496
1752
//  DebugLn(['=== SrceenRow TO Row   In:',ScreenRow,'  out:',Result, ' topline=',TopLine, '  view topline=',FFoldedLinesView.TopLine]);
1497
1753
end;
1498
1754
 
1507
1763
  if Result > LinesInWindow+1 then Result := LinesInWindow+1;
1508
1764
//  DebugLn(['=== Row TO ScreenRow   In:',PhysicalRow,'  out:',Result]);
1509
1765
end;
1510
 
{$ENDIF}
1511
1766
 
1512
 
function TCustomSynEdit.RowColumnToPixels(
1513
 
  {$IFDEF SYN_LAZARUS}const {$ENDIF}RowCol: TPoint): TPoint;
 
1767
function TCustomSynEdit.RowColumnToPixels(RowCol: TPoint): TPoint;
1514
1768
// converts screen position (1,1) based
1515
1769
// to client area coordinate (0,0 based on canvas)
1516
1770
begin
1517
 
  Result:=RowCol;
1518
 
  Result.X := (Result.X - 1) * fCharWidth + fTextOffset;
1519
 
  {$IFDEF SYN_LAZARUS}
1520
 
  Result.Y := RowToScreenRow(RowCol.Y) * fTextHeight;
1521
 
  {$ELSE}
1522
 
  Result.Y := (Result.Y - fTopLine) * fTextHeight;
1523
 
  {$ENDIF}
 
1771
  RowCol.Y := RowToScreenRow(RowCol.Y);
 
1772
  Result := FTextArea.RowColumnToPixels(RowCol);
1524
1773
end;
1525
1774
 
1526
1775
procedure TCustomSynEdit.ComputeCaret(X, Y: Integer);
1598
1847
  SetInline(True);
1599
1848
  ControlStyle:=ControlStyle+[csOwnedChildrenNotSelectable];
1600
1849
  FScrollBarUpdateLock := 0;
 
1850
  FPaintLock := 0;
 
1851
  FUndoBlockAtPaintLock := 0;
1601
1852
 
1602
1853
  FStatusChangedList := TSynStatusChangedHandlerList.Create;
1603
1854
 
1622
1873
  // ftab, currently has LengthOfLongestLine, therefore must be after DoubleWidthChar
1623
1874
  FTabbedLinesView := TSynEditStringTabExpander.Create(FDoubleWidthChrLinesView);
1624
1875
 
1625
 
  FFoldedLinesView := TSynEditFoldedView.Create(FTabbedLinesView, fCaret);
1626
 
  FFoldedLinesView.OnFoldChanged := {$IFDEF FPC}@{$ENDIF}FoldChanged;
1627
 
 
1628
1876
  // Pointer to the First/Lowest View
1629
1877
  // TODO: this should be Folded...
1630
1878
  FTheLinesView := FTabbedLinesView;
1631
1879
  FTopLinesView := FTrimmedLinesView;
 
1880
 
 
1881
  FFoldedLinesView := TSynEditFoldedView.Create(FTheLinesView, fCaret);
 
1882
  FFoldedLinesView.OnFoldChanged := {$IFDEF FPC}@{$ENDIF}FoldChanged;
 
1883
  FFoldedLinesView.OnLineInvalidate := {$IFDEF FPC}@{$ENDIF}InvalidateGutterLines;
 
1884
  FFoldedLinesView.DisplayView.NextView := FTheLinesView.DisplayView;
 
1885
 
 
1886
  FDisplayView := FFoldedLinesView.DisplayView;
 
1887
 
1632
1888
  // External Accessor
1633
1889
  FStrings := TSynEditLines.Create(TSynEditStringList(FLines), {$IFDEF FPC}@{$ENDIF}MarkTextAsSaved);
1634
1890
 
1657
1913
  FUndoList := TSynEditStringList(fLines).UndoList;
1658
1914
  FRedoList := TSynEditStringList(fLines).RedoList;
1659
1915
  FUndoList.OnNeedCaretUndo := {$IFDEF FPC}@{$ENDIF}GetCaretUndo;
 
1916
  {$IFDEF SynUndoDebugCalls}
 
1917
  fUndoList.DebugName := 'UNDO';
 
1918
  fRedoList.DebugName := 'REDO';
 
1919
  {$ENDIF}
1660
1920
 
1661
1921
  FBlockSelection := TSynEditSelection.Create(FTheLinesView, True);
1662
1922
  FBlockSelection.Caret := FCaret;
1667
1927
  FInternalBlockSelection.InvalidateLinesMethod := {$IFDEF FPC}@{$ENDIF}InvalidateLines;
1668
1928
  // No need for caret, on interanl block
1669
1929
 
 
1930
  FFoldedLinesView.BlockSelection := FBlockSelection;
 
1931
 
1670
1932
  FWordBreaker := TSynWordBreaker.Create;
1671
1933
 
1672
1934
  RecreateMarkList;
1673
1935
 
1674
 
{$IFDEF SYN_COMPILER_4_UP}
1675
 
{$IFNDEF SYN_LAZARUS}
1676
 
// ToDo DoubleBuffered
1677
 
  DoubleBuffered := false;
1678
 
{$ENDIF}
1679
 
{$ENDIF}
1680
1936
  {$IFNDEF EnableDoubleBuf}
1681
1937
  DoubleBuffered := True;
1682
1938
  {$ENDIF}
1686
1942
  FPaintLineColor2 := TSynSelectedColor.Create;
1687
1943
  fBookMarkOpt := TSynBookMarkOpt.Create(Self);
1688
1944
  fBookMarkOpt.OnChange := {$IFDEF FPC}@{$ENDIF}BookMarkOptionsChanged;
1689
 
// fRightEdge has to be set before FontChanged is called for the first time
1690
 
  fRightEdge := 80;
 
1945
 
1691
1946
  FLeftGutter := CreateGutter(self, gsLeft, FTextDrawer);
1692
 
  FLeftGutter.OnChange := {$IFDEF FPC}@{$ENDIF}GutterChanged;
1693
 
  FLeftGutter.OnResize := {$IFDEF FPC}@{$ENDIF}GutterResized;
 
1947
  FLeftGutter.RegisterChangeHandler({$IFDEF FPC}@{$ENDIF}GutterChanged);
 
1948
  FLeftGutter.RegisterResizeHandler({$IFDEF FPC}@{$ENDIF}GutterResized);
1694
1949
  FRightGutter := CreateGutter(self, gsRight, FTextDrawer);
1695
 
  FRightGutter.OnChange := {$IFDEF FPC}@{$ENDIF}GutterChanged;
1696
 
  FRightGutter.OnResize := {$IFDEF FPC}@{$ENDIF}GutterResized;
1697
 
 
1698
 
  fTextOffset := TextLeftPixelOffset;
1699
 
 
1700
 
  ControlStyle := ControlStyle + [csOpaque, csSetCaption
1701
 
                    {$IFDEF SYN_LAZARUS}, csTripleClicks, csQuadClicks{$ENDIF}];
 
1950
  FRightGutter.RegisterChangeHandler({$IFDEF FPC}@{$ENDIF}GutterChanged);
 
1951
  FRightGutter.RegisterResizeHandler({$IFDEF FPC}@{$ENDIF}GutterResized);
 
1952
 
 
1953
  ControlStyle := ControlStyle + [csOpaque, csSetCaption, csTripleClicks, csQuadClicks];
1702
1954
  Height := 150;
1703
1955
  Width := 200;
1704
1956
  Cursor := crIBeam;
1705
1957
  fPlugins := TList.Create;
1706
1958
  FHookedKeyTranslationList := TSynHookedKeyTranslationList.Create;
1707
 
{$IFDEF SYN_LAZARUS}
1708
1959
  // needed before setting color
1709
1960
  fMarkupHighCaret := TSynEditMarkupHighlightAllCaret.Create(self);
1710
1961
  fMarkupHighCaret.Selection := FBlockSelection;
1714
1965
  fMarkupCtrlMouse := TSynEditMarkupCtrlMouseLink.Create(self);
1715
1966
  fMarkupSpecialLine := TSynEditMarkupSpecialLine.Create(self);
1716
1967
  fMarkupSelection := TSynEditMarkupSelection.Create(self, FBlockSelection);
 
1968
  fMarkupSpecialChar := TSynEditMarkupSpecialChar.Create(self);
 
1969
 
 
1970
  fMarkupSelection.MarkupInfoSeletion.SetAllPriorities(50);
1717
1971
 
1718
1972
  fMarkupManager := TSynEditMarkupManager.Create(self);
 
1973
  fMarkupManager.AddMarkUp(fMarkupSpecialChar);
1719
1974
  fMarkupManager.AddMarkUp(fMarkupSpecialLine);
1720
1975
  fMarkupManager.AddMarkUp(fMarkupHighCaret);
1721
1976
  fMarkupManager.AddMarkUp(fMarkupHighAll);
1727
1982
  fMarkupManager.Caret := FCaret;
1728
1983
  fMarkupManager.InvalidateLinesMethod := @InvalidateLines;
1729
1984
 
1730
 
  Color := clWhite;
 
1985
  {$IFDEF WinIME}
 
1986
  {$IFDEF WinIMEFull}
 
1987
  FImeHandler := LazSynImeFull.Create(Self);
 
1988
  {$ELSE}
 
1989
  FImeHandler := LazSynImeSimple.Create(Self);
 
1990
  LazSynImeSimple(FImeHandler).TextDrawer := FTextDrawer;
 
1991
  {$ENDIF}
 
1992
  FImeHandler.InvalidateLinesMethod := @InvalidateLines;
 
1993
  {$ENDIF}
 
1994
 
1731
1995
  fFontDummy.Name := SynDefaultFontName;
1732
1996
  fFontDummy.Height := SynDefaultFontHeight;
1733
1997
  fFontDummy.Pitch := SynDefaultFontPitch;
1734
1998
  fFontDummy.Quality := SynDefaultFontQuality;
 
1999
  FLastSetFontSize := fFontDummy.Height;
1735
2000
  fLastMouseCaret := Point(-1,-1);
1736
2001
  FLastMousePoint := Point(-1,-1);
1737
2002
  fBlockIndent := 2;
1738
 
{$ELSE}
1739
 
  Color := clWindow;
1740
 
  fFontDummy.Name := 'Courier New';
1741
 
  fFontDummy.Size := 10;
1742
 
{$IFDEF SYN_COMPILER_3_UP}
1743
 
// ToDo Font CharSet
1744
 
  fFontDummy.CharSet := DEFAULT_CHARSET;
1745
 
{$ENDIF}
1746
 
{$ENDIF}
 
2003
 
 
2004
  FTextArea := TLazSynTextArea.Create(Self, FTextDrawer);
 
2005
  FTextArea.RightEdgeVisible := not(eoHideRightMargin in SYNEDIT_DEFAULT_OPTIONS);
 
2006
  FTextArea.ExtraCharSpacing := 0;
 
2007
  FTextArea.ExtraLineSpacing := 0;
 
2008
  FTextArea.MarkupManager := fMarkupManager;
 
2009
  FTextArea.TheLinesView := FTheLinesView;
 
2010
  FTextArea.Highlighter := nil;
 
2011
 
 
2012
  FLeftGutterArea := TLazSynGutterArea.Create(Self);
 
2013
  FLeftGutterArea.TextArea := FTextArea;
 
2014
  FLeftGutterArea.Gutter := FLeftGutter;
 
2015
 
 
2016
  FRightGutterArea := TLazSynGutterArea.Create(Self);
 
2017
  FRightGutterArea.TextArea := FTextArea;
 
2018
  FRightGutterArea.Gutter := FRightGutter;
 
2019
 
 
2020
  FPaintArea := TLazSynSurfaceManager.Create(Self);
 
2021
  FPaintArea.TextArea := FTextArea;
 
2022
  FPaintArea.LeftGutterArea := FLeftGutterArea;
 
2023
  FPaintArea.RightGutterArea := FRightGutterArea;
 
2024
  FPaintArea.DisplayView := FDisplayView;
 
2025
 
 
2026
  Color := clWhite;
1747
2027
  Font.Assign(fFontDummy);
1748
2028
  Font.OnChange := {$IFDEF FPC}@{$ENDIF}FontChanged;
1749
2029
  FontChanged(nil);
1757
2037
  fInsertCaret := ctVerticalLine;
1758
2038
  fOverwriteCaret := ctBlock;
1759
2039
  FKeystrokes := TSynEditKeyStrokes.Create(Self);
1760
 
  FLastKeyStrokes := nil;
 
2040
  FCurrentComboKeyStrokes := nil;
1761
2041
  if assigned(Owner) and not (csLoading in Owner.ComponentState) then begin
1762
2042
    SetDefaultKeystrokes;
1763
2043
  end;
1764
 
  FMouseActions := TSynEditMouseTextActions.Create(Self);
1765
 
  FMouseSelActions := TSynEditMouseSelActions.Create(Self);
1766
 
  FMouseActions.ResetDefaults;
1767
 
  FMouseSelActions.ResetDefaults;
 
2044
 
 
2045
  FMouseActions     := TSynEditMouseGlobalActions.Create(Self);
 
2046
  FMouseSelActions  := TSynEditMouseSelActions.Create(Self);
 
2047
  FMouseTextActions := TSynEditMouseTextActions.Create(Self);
1768
2048
  FMouseActionSearchHandlerList := TSynEditMouseActionSearchList.Create;
1769
 
  FMouseActionExecHandlerList := TSynEditMouseActionExecList.Create;
 
2049
  FMouseActionExecHandlerList  := TSynEditMouseActionExecList.Create;
1770
2050
 
1771
 
  fRightEdgeColor := clSilver;
1772
 
{$IFDEF SYN_MBCSSUPPORT}
1773
 
  fImeCount := 0;
1774
 
  fMBCSStepAside := False;
1775
 
{$ENDIF}
1776
 
  fWantTabs := False;
 
2051
  fWantTabs := True;
1777
2052
  fTabWidth := 8;
1778
 
  fLeftChar := 1;
1779
 
  fTopLine := 1;
1780
 
  FOldTopLine := 1;
1781
2053
  FOldTopView := 1;
1782
2054
  FFoldedLinesView.TopLine := 1;
1783
2055
  // find / replace
1784
2056
  fTSearch := TSynEditSearch.Create;
1785
2057
  FOptions := SYNEDIT_DEFAULT_OPTIONS;
1786
2058
  FOptions2 := SYNEDIT_DEFAULT_OPTIONS2;
 
2059
  FMouseOptions := SYNEDIT_DEFAULT_MOUSE_OPTIONS;
1787
2060
  FShareOptions := SYNEDIT_DEFAULT_SHARE_OPTIONS;
 
2061
  FVisibleSpecialChars := SYNEDIT_DEFAULT_VISIBLESPECIALCHARS;
 
2062
  fMarkupSpecialChar.VisibleSpecialChars := SYNEDIT_DEFAULT_VISIBLESPECIALCHARS;
1788
2063
  UpdateOptions;
1789
2064
  UpdateOptions2;
 
2065
  UpdateMouseOptions;
 
2066
  UpdateCaret;
1790
2067
  fScrollTimer := TTimer.Create(Self);
1791
2068
  fScrollTimer.Enabled := False;
1792
2069
  fScrollTimer.Interval := 100;
1793
2070
  fScrollTimer.OnTimer := {$IFDEF FPC}@{$ENDIF}ScrollTimerHandler;
 
2071
 
 
2072
  // Accessibility
 
2073
  AccessibleRole := larTextEditorMultiline;
 
2074
  AccessibleValue := Self.Text;
 
2075
  AccessibleDescription := 'source code editor';
1794
2076
end;
1795
2077
 
1796
2078
function TCustomSynEdit.GetChildOwner: TComponent;
1884
2166
  if FPaintLock = 0 then begin
1885
2167
    SetUpdateState(True, Self);
1886
2168
    FInvalidateRect := Rect(-1, -1, -2, -2);
1887
 
    FOldTopLine := FTopLine;
1888
2169
    FOldTopView := TopView;
1889
2170
    FLastTextChangeStamp := TSynEditStringList(FLines).TextChangeStamp;
1890
2171
  end;
1892
2173
  FMarkupManager.IncPaintLock;
1893
2174
  FFoldedLinesView.Lock; //DecPaintLock triggers ScanFrom, and folds must wait
1894
2175
  FTrimmedLinesView.Lock; // Lock before caret
 
2176
  FBlockSelection.Lock;
1895
2177
  FCaret.Lock;
1896
2178
  FScreenCaret.Lock;
1897
2179
end;
1901
2183
  if FIsInDecPaintLock then exit;
1902
2184
  FIsInDecPaintLock := True;
1903
2185
  try
 
2186
    if (FUndoBlockAtPaintLock >= FPaintLock) then begin
 
2187
      if (FUndoBlockAtPaintLock > FPaintLock) then
 
2188
        debugln(['***** SYNEDIT: Fixing auto-undo-block FUndoBlockAtPaintLock=',FUndoBlockAtPaintLock,' FPaintLock=',FPaintLock]);
 
2189
      FUndoBlockAtPaintLock := 0;
 
2190
      EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TCustomSynEdit.DoDecPaintLock'){$ENDIF};
 
2191
    end;
1904
2192
    if (FPaintLock=1) and HandleAllocated then begin
1905
2193
      ScanRanges(FLastTextChangeStamp <> TSynEditStringList(FLines).TextChangeStamp);
1906
2194
      if sfAfterLoadFromFileNeeded in fStateFlags then
1913
2201
      FChangedLinesEnd:=0;
1914
2202
    end;
1915
2203
    FCaret.Unlock;            // Maybe after FFoldedLinesView
 
2204
    FBlockSelection.Unlock;
1916
2205
    FTrimmedLinesView.UnLock; // Must be unlocked after caret // May Change lines
1917
2206
    FFoldedLinesView.UnLock;  // after ScanFrom, but before UpdateCaret
1918
2207
    FMarkupManager.DecPaintLock;
1952
2241
        DumpStack;
1953
2242
        {$ENDIF}
1954
2243
      end;
 
2244
      if sfSelChanged in FStateFlags then
 
2245
        SelAvailChange(nil);
1955
2246
    end;
1956
2247
  end;
1957
2248
end;
1959
2250
destructor TCustomSynEdit.Destroy;
1960
2251
var
1961
2252
  i: integer;
 
2253
  p: TList;
1962
2254
begin
1963
2255
  Application.RemoveOnIdleHandler(@IdleScanRanges);
1964
2256
  SurrenderPrimarySelection;
1965
2257
  Highlighter := nil;
1966
2258
  Beautifier:=nil;
 
2259
  FFoldedLinesView.BlockSelection := nil;
 
2260
 
 
2261
  if fPlugins <> nil then begin
 
2262
    p := FPlugins;
 
2263
    FPlugins := nil;
 
2264
    for i := p.Count - 1 downto 0 do
 
2265
      TLazSynEditPlugin(p[i]).DoEditorDestroyed(Self);
 
2266
    p.Free;
 
2267
  end;
 
2268
 
1967
2269
  // free listeners while other fields are still valid
1968
2270
  if Assigned(fHookedCommandHandlers) then begin
1969
2271
    for i := 0 to fHookedCommandHandlers.Count - 1 do
1970
2272
      THookedCommandHandlerEntry(fHookedCommandHandlers[i]).Free;
1971
2273
    FreeAndNil(fHookedCommandHandlers);
1972
2274
  end;
1973
 
  if fPlugins <> nil then begin
1974
 
    for i := fPlugins.Count - 1 downto 0 do
1975
 
      if TSynEditPlugin(fPlugins[i]).OwnedByEditor then
1976
 
        TSynEditPlugin(fPlugins[i]).Free
1977
 
      else
1978
 
        TSynEditPlugin(fPlugins[i]).Editor := nil;
1979
 
    FreeAndNil(fPlugins);
1980
 
  end;
 
2275
 
1981
2276
  RemoveHandlers;
 
2277
  FLeftGutter.UnRegisterChangeHandler({$IFDEF FPC}@{$ENDIF}GutterChanged);
 
2278
  FLeftGutter.UnRegisterResizeHandler({$IFDEF FPC}@{$ENDIF}GutterResized);
 
2279
  FRightGutter.UnRegisterChangeHandler({$IFDEF FPC}@{$ENDIF}GutterChanged);
 
2280
  FRightGutter.UnRegisterResizeHandler({$IFDEF FPC}@{$ENDIF}GutterResized);
1982
2281
 
1983
2282
  FreeAndNil(FHookedKeyTranslationList);
1984
2283
  fHookedCommandHandlers:=nil;
1986
2285
  FCaret.Lines := nil;
1987
2286
  FInternalCaret.Lines := nil;
1988
2287
  FMarkList.UnRegisterChangeHandler({$IFDEF FPC}@{$ENDIF}MarkListChange);
 
2288
  FreeAndNil(FPaintArea);
 
2289
  FreeAndNil(FLeftGutterArea);
 
2290
  FreeAndNil(FRightGutterArea);
 
2291
  FreeAndNil(FTextArea);
1989
2292
  FreeAndNil(fTSearch);
1990
2293
  FreeAndNil(fMarkupManager);
1991
2294
  FreeAndNil(fBookMarkOpt);
1994
2297
  FreeAndNil(FMouseActionExecHandlerList);
1995
2298
  FreeAndNil(FMouseActions);
1996
2299
  FreeAndNil(FMouseSelActions);
 
2300
  FreeAndNil(FMouseTextActions);
1997
2301
  FreeAndNil(FLeftGutter);
1998
2302
  FreeAndNil(FRightGutter);
1999
2303
  FreeAndNil(FPaintLineColor);
2000
2304
  FreeAndNil(FPaintLineColor2);
 
2305
  {$IFDEF WinIME}
 
2306
  FreeAndNil(FImeHandler);
 
2307
  {$ENDIF}
2001
2308
  FreeAndNil(fTextDrawer);
2002
2309
  FreeAndNil(fFontDummy);
2003
2310
  DestroyMarkList; // before detach from FLines
2018
2325
  FreeAndNil(FStatusChangedList);
2019
2326
  FBeautifier := nil;
2020
2327
  FreeAndNil(FDefaultBeautifier);
 
2328
  FreeAndNil(FKeyDownEventList);
 
2329
  FreeAndNil(FMouseDownEventList);
 
2330
  FreeAndNil(FKeyPressEventList);
 
2331
  FreeAndNil(FUtf8KeyPressEventList);
2021
2332
  inherited Destroy;
2022
2333
end;
2023
2334
 
2050
2361
end;
2051
2362
 
2052
2363
procedure TCustomSynEdit.FontChanged(Sender: TObject);
2053
 
begin
 
2364
begin // TODO: inherited ?
 
2365
  FPaintArea.ForegroundColor := Font.Color;
 
2366
  FLastSetFontSize := Font.Height;
2054
2367
  RecalcCharExtent;
2055
 
  SizeOrFontChanged(TRUE);
2056
2368
end;
2057
2369
 
2058
2370
function TCustomSynEdit.GetTextBuffer: TSynEditStrings;
2070
2382
  Result := fMarkupManager.MarkupByClass[Index];
2071
2383
end;
2072
2384
 
2073
 
{$IFDEF SYN_LAZARUS}
2074
2385
function TCustomSynEdit.GetHighlightAllColor : TSynSelectedColor;
2075
2386
begin
2076
2387
  result := fMarkupHighAll.MarkupInfo;
2153
2464
begin
2154
2465
  fMarkupSelection.UseIncrementalColor:=AValue;
2155
2466
end;
2156
 
{$ENDIF}
2157
2467
 
2158
2468
function TCustomSynEdit.GetCharLen(const Line: string; CharStartPos: integer
2159
2469
  ): integer;
2212
2522
    Result := '';
2213
2523
end;
2214
2524
 
2215
 
{$IFDEF SYN_MBCSSUPPORT}
 
2525
{$IFDEF WinIME}
 
2526
procedure TCustomSynEdit.WMImeRequest(var Msg: TMessage);
 
2527
begin
 
2528
  FImeHandler.WMImeRequest(Msg);
 
2529
end;
 
2530
 
 
2531
procedure TCustomSynEdit.SetImeHandler(AValue: LazSynIme);
 
2532
begin
 
2533
  if FImeHandler = AValue then Exit;
 
2534
  FreeAndNil(FImeHandler);
 
2535
  FImeHandler := AValue;
 
2536
end;
 
2537
 
 
2538
procedure TCustomSynEdit.WMImeNotify(var Msg: TMessage);
 
2539
begin
 
2540
    FImeHandler.WMImeNotify(Msg);
 
2541
end;
 
2542
 
2216
2543
procedure TCustomSynEdit.WMImeComposition(var Msg: TMessage);
2217
 
var
2218
 
  imc: HIMC;
2219
 
  p: PChar;
2220
 
begin
2221
 
  if ((Msg.LParam and GCS_RESULTSTR) <> 0) then begin
2222
 
    imc := ImmGetContext(Handle);
2223
 
    try
2224
 
      fImeCount := ImmGetCompositionString(imc, GCS_RESULTSTR, nil, 0);
2225
 
      GetMem(p, fImeCount + 1);
2226
 
      try
2227
 
        ImmGetCompositionString(imc, GCS_RESULTSTR, p, fImeCount + 1);
2228
 
        p[fImeCount] := #0;
2229
 
        CommandProcessor(ecImeStr, #0, p);
2230
 
      finally
2231
 
        FreeMem(p, fImeCount + 1);
2232
 
      end;
2233
 
    finally
2234
 
      ImmReleaseContext(Handle, imc);
2235
 
    end;
2236
 
  end;
2237
 
  inherited;
2238
 
end;
2239
 
 
2240
 
procedure TCustomSynEdit.WMImeNotify(var Msg: TMessage);
2241
 
var
2242
 
  imc: HIMC;
2243
 
  logFont: TLogFont;
2244
 
begin
2245
 
  with Msg do begin
2246
 
    case WParam of
2247
 
      IMN_SETOPENSTATUS:
2248
 
        begin
2249
 
          imc := ImmGetContext(Handle);
2250
 
          if (imc <> 0) then begin
2251
 
            GetObject(Font.Handle, SizeOf(TLogFont), @logFont);
2252
 
            ImmSetCompositionFont(imc, @logFont);
2253
 
 
2254
 
            ImmReleaseContext(Handle, imc);
2255
 
          end;
2256
 
        end;
2257
 
    end;
2258
 
  end;
2259
 
  inherited;
 
2544
begin
 
2545
  FImeHandler.WMImeComposition(Msg);
 
2546
end;
 
2547
 
 
2548
procedure TCustomSynEdit.WMImeStartComposition(var Msg: TMessage);
 
2549
begin
 
2550
  FImeHandler.WMImeStartComposition(Msg);
 
2551
end;
 
2552
 
 
2553
procedure TCustomSynEdit.WMImeEndComposition(var Msg: TMessage);
 
2554
begin
 
2555
  FImeHandler.WMImeEndComposition(Msg);
2260
2556
end;
2261
2557
{$ENDIF}
2262
2558
 
2267
2563
 
2268
2564
procedure TCustomSynEdit.InvalidateGutterLines(FirstLine, LastLine: integer);   // Todo: move to gutter
2269
2565
var
2270
 
  rcInval: TRect;
2271
2566
  TopFoldLine: LongInt;
2272
2567
begin
2273
2568
  if sfPainting in fStateFlags then exit;
2274
 
  if Visible and HandleAllocated then
 
2569
  if Visible and HandleAllocated then begin
 
2570
    {$IFDEF VerboseSynEditInvalidate}
 
2571
    DebugLnEnter(['TCustomSynEdit.InvalidateGutterLines ',DbgSName(self), ' FirstLine=',FirstLine, ' LastLine=',LastLine]);
 
2572
    {$ENDIF}
2275
2573
    if (FirstLine = -1) and (LastLine = -1) then begin
2276
 
      if FLeftGutter.Visible then begin;
2277
 
        rcInval := Rect(0, 0, FLeftGutter.Width, ClientHeight - ScrollBarWidth);
2278
 
        {$IFDEF VerboseSynEditInvalidate}
2279
 
        DebugLn(['TCustomSynEdit.InvalidateGutterLines ',DbgSName(self),' ALL ',dbgs(rcInval)]);
2280
 
        {$ENDIF}
2281
 
        InvalidateRect(Handle, @rcInval, FALSE);
2282
 
      end;
2283
 
      // right gutter
2284
 
      if FRightGutter.Visible then begin
2285
 
        rcInval := Rect(ClientWidth - FRightGutter.Width - ScrollBarWidth, 0,
2286
 
                        ClientWidth - ScrollBarWidth, ClientHeight - ScrollBarWidth);
2287
 
        {$IFDEF VerboseSynEditInvalidate}
2288
 
        DebugLn(['TCustomSynEdit.InvalidateGutterLines ',DbgSName(self),' ALL ',dbgs(rcInval)]);
2289
 
        {$ENDIF}
2290
 
        InvalidateRect(Handle, @rcInval, FALSE);
2291
 
      end;
 
2574
      FPaintArea.InvalidateGutterLines(-1, -1);
2292
2575
    end else begin
2293
2576
      // pretend we haven't scrolled
2294
2577
      TopFoldLine := FFoldedLinesView.TopLine;
2295
 
      if FOldTopLine <> FTopLine then
2296
 
        FFoldedLinesView.TopTextIndex := FOldTopLine - 1;
2297
 
 
2298
 
      { find the visible lines first }
2299
 
      if LastLine >= 0 then begin
2300
 
        if (LastLine < FirstLine) then SwapInt(LastLine, FirstLine);
2301
 
        LastLine := RowToScreenRow(Min(LastLine, ScreenRowToRow(LinesInWindow)))+1;
2302
 
        LastLine := LastLine;
2303
 
      end
2304
 
      else
2305
 
        LastLine := LinesInWindow + 1;
2306
 
      FirstLine := RowToScreenRow(Max(FirstLine, TopLine));
2307
 
      FirstLine := Max(0, FirstLine);
2308
 
      { any line visible? }
2309
 
      if (LastLine >= FirstLine) then begin
2310
 
        if FLeftGutter.Visible then begin;
2311
 
          rcInval := Rect(0, fTextHeight * FirstLine,
2312
 
            FLeftGutter.Width, fTextHeight * LastLine);
2313
 
          {$IFDEF VerboseSynEditInvalidate}
2314
 
          DebugLn(['TCustomSynEdit.InvalidateGutterLines ',DbgSName(self),' PART ',dbgs(rcInval)]);
2315
 
          {$ENDIF}
2316
 
          InvalidateRect(Handle, @rcInval, FALSE);
2317
 
        end;
2318
 
        // right gutter
2319
 
        if FRightGutter.Visible then begin
2320
 
          rcInval.Left := ClientWidth - FRightGutter.Width - ScrollBarWidth;
2321
 
          rcInval.Right := ClientWidth - ScrollBarWidth;
2322
 
          {$IFDEF VerboseSynEditInvalidate}
2323
 
          DebugLn(['TCustomSynEdit.InvalidateGutterLines ',DbgSName(self),' PART ',dbgs(rcInval)]);
2324
 
          {$ENDIF}
2325
 
          InvalidateRect(Handle, @rcInval, FALSE);
2326
 
        end;
2327
 
      end;
 
2578
      if FOldTopView <> TopView then
 
2579
        FFoldedLinesView.TopLine := FOldTopView;
 
2580
 
 
2581
      if (LastLine <> -1) and (LastLine < FirstLine) then
 
2582
        SwapInt(FirstLine, LastLine);
 
2583
 
 
2584
      FPaintArea.InvalidateGutterLines(FirstLine-1, LastLine-1);
2328
2585
 
2329
2586
      FFoldedLinesView.TopLine := TopFoldLine;
2330
2587
    end;
 
2588
    {$IFDEF VerboseSynEditInvalidate}
 
2589
    DebugLnExit(['TCustomSynEdit.InvalidateGutterLines ',DbgSName(self)]);
 
2590
    {$ENDIF}
 
2591
    end;
2331
2592
end;
2332
2593
 
2333
2594
procedure TCustomSynEdit.InvalidateLines(FirstLine, LastLine: integer);
2334
2595
var
2335
 
  rcInval: TRect;
2336
 
  f, l: Integer;
2337
2596
  TopFoldLine: LongInt;
2338
2597
begin
2339
2598
  if sfPainting in fStateFlags then exit;
2340
 
  if Visible and HandleAllocated then
 
2599
  if Visible and HandleAllocated then begin
 
2600
    {$IFDEF VerboseSynEditInvalidate}
 
2601
    DebugLnEnter(['TCustomSynEdit.InvalidateTextLines ',DbgSName(self), ' FirstLine=',FirstLine, ' LastLine=',LastLine]);
 
2602
    {$ENDIF}
2341
2603
    if (FirstLine = -1) and (LastLine = -1) then begin
2342
 
      rcInval := ClientRect;
2343
 
      rcInval.Left := TextLeftPixelOffset(False);
2344
 
      rcInval.Right := ClientWidth - TextRightPixelOffset - ScrollBarWidth;
2345
 
      {$IFDEF VerboseSynEditInvalidate}
2346
 
      DebugLn(['TCustomSynEdit.InvalidateLines ',DbgSName(self),' ALL ',dbgs(rcInval)]);
2347
 
      {$ENDIF}
2348
 
      InvalidateRect(Handle, @rcInval, FALSE);
 
2604
      FPaintArea.InvalidateTextLines(-1, -1);
2349
2605
    end else begin
2350
2606
      // pretend we haven't scrolled
2351
2607
      TopFoldLine := FFoldedLinesView.TopLine;
2352
 
      if FOldTopLine <> FTopLine then
2353
 
        FFoldedLinesView.TopTextIndex := FOldTopLine - 1;
2354
 
 
2355
 
      { find the visible lines first }
2356
 
      if LastLine >= 0 then begin
2357
 
        if (LastLine < FirstLine) then SwapInt(LastLine, FirstLine);
2358
 
        l := RowToScreenRow(Min(LastLine, ScreenRowToRow(LinesInWindow)))+1;
2359
 
        l := l;
2360
 
      end
2361
 
      else
2362
 
        l := LinesInWindow + 1;
2363
 
      f := RowToScreenRow(Max(FirstLine, TopLine));
2364
 
      f := Max(0, f);
2365
 
      { any line visible? }
2366
 
      if (l >= f) then begin
2367
 
        rcInval := Rect(TextLeftPixelOffset(False), fTextHeight * f,
2368
 
          ClientWidth - TextRightPixelOffset - ScrollBarWidth, fTextHeight * l);
2369
 
        {$IFDEF VerboseSynEditInvalidate}
2370
 
        DebugLn(['TCustomSynEdit.InvalidateLines ',DbgSName(self),' PART ',dbgs(rcInval)]);
2371
 
        {$ENDIF}
2372
 
        InvalidateRect(Handle, @rcInval, FALSE);
2373
 
      end;
 
2608
      if FOldTopView <> TopView then
 
2609
        FFoldedLinesView.TopLine := FOldTopView;
 
2610
 
 
2611
      if (LastLine <> -1) and (LastLine < FirstLine) then
 
2612
        SwapInt(FirstLine, LastLine);
 
2613
 
 
2614
      FPaintArea.InvalidateTextLines(FirstLine-1, LastLine-1);
2374
2615
 
2375
2616
      FFoldedLinesView.TopLine := TopFoldLine;
2376
2617
    end;
 
2618
    {$IFDEF VerboseSynEditInvalidate}
 
2619
    DebugLnExit(['TCustomSynEdit.InvalidateTextLines ',DbgSName(self)]);
 
2620
    {$ENDIF}
 
2621
  end;
2377
2622
end;
2378
2623
 
2379
2624
procedure TCustomSynEdit.KeyDown(var Key: Word; Shift: TShiftState);
2387
2632
  {$IFDEF VerboseKeys}
2388
2633
  DebugLn('[TCustomSynEdit.KeyDown] ',dbgs(Key),' ',dbgs(Shift));
2389
2634
  {$ENDIF}
 
2635
 
 
2636
  if (not WantTabs) and (Key = VK_TAB) and ((Shift - [ssShift]) = []) then begin
 
2637
    inherited KeyDown(Key, Shift);
 
2638
    exit;
 
2639
  end;
 
2640
 
 
2641
  // Run even before OnKeyDown
 
2642
  if FKeyDownEventList <> nil then
 
2643
    FKeyDownEventList.CallKeyDownHandlers(Self, Key, Shift);
 
2644
  if Key=0 then exit;
 
2645
 
2390
2646
  inherited;
2391
2647
  if assigned(fMarkupCtrlMouse) then
2392
2648
    fMarkupCtrlMouse.UpdateCtrlState(Shift);
 
2649
 
 
2650
  if Key in [VK_SHIFT, VK_CONTROL, VK_MENU,
 
2651
             VK_LSHIFT, VK_LCONTROL, VK_LMENU,
 
2652
             VK_RSHIFT, VK_RCONTROL, VK_RMENU,
 
2653
             VK_LWIN, VK_RWIN]
 
2654
  then
 
2655
    exit;
 
2656
 
2393
2657
  Data := nil;
2394
2658
  C := #0;
2395
2659
  try
 
2660
    // If the translations requires Data, memory will be allocated for it via a
 
2661
    // GetMem call.  The client must call FreeMem on Data if it is not NIL.
2396
2662
    IsStartOfCombo := False;
2397
2663
    Handled := False;
2398
 
    // If the translations requires Data, memory will be allocated for it via a
2399
 
    // GetMem call.  The client must call FreeMem on Data if it is not NIL.
2400
 
    if FLastKeyStrokes = FKeyStrokes then begin
2401
 
      Cmd := KeyStrokes.FindKeycodeEx(Key, Shift, Data, IsStartOfCombo, True);
2402
 
      Handled := Cmd <> ecNone;
2403
 
    end;
2404
 
    // Hooked
2405
 
    if not Handled then
2406
 
      FHookedKeyTranslationList.CallHookedKeyTranslationHandlers(self,
2407
 
        Key, Shift, Data, IsStartOfCombo, Handled, Cmd, FLastKeyStrokes);
2408
 
    if not Handled then begin
 
2664
 
 
2665
    // Check 2nd stroke in SynEdit.KeyStrokes
 
2666
    if FCurrentComboKeyStrokes <> nil then begin
 
2667
      // Run hooked first, it might want to "steal" the key(s)
 
2668
      Cmd := 0;
 
2669
      FHookedKeyTranslationList.CallHookedKeyTranslationHandlers(self,
 
2670
        Key, Shift, Data, IsStartOfCombo, Handled, Cmd, FCurrentComboKeyStrokes);
 
2671
 
 
2672
      if not Handled then begin
 
2673
        Cmd := KeyStrokes.FindKeycodeEx(Key, Shift, Data, IsStartOfCombo, True, FCurrentComboKeyStrokes);
 
2674
        if IsStartOfCombo then
 
2675
          FCurrentComboKeyStrokes := FKeyStrokes;
 
2676
        Handled := (Cmd <> ecNone) or IsStartOfCombo;
 
2677
      end;
 
2678
 
 
2679
      if not IsStartOfCombo then begin
 
2680
        FCurrentComboKeyStrokes.ResetKeyCombo;
 
2681
        FCurrentComboKeyStrokes := nil;
 
2682
      end;
 
2683
    end;
 
2684
    assert(Handled or (FCurrentComboKeyStrokes=nil), 'FCurrentComboKeyStrokes<>nil, should be handled');
 
2685
 
 
2686
    // Check 1st/single stroke in Hooked KeyStrokes
 
2687
    if not Handled then begin
 
2688
      FCurrentComboKeyStrokes := nil;
 
2689
      FHookedKeyTranslationList.CallHookedKeyTranslationHandlers(self,
 
2690
        Key, Shift, Data, IsStartOfCombo, Handled, Cmd, FCurrentComboKeyStrokes);
 
2691
      if (not IsStartOfCombo) and (FCurrentComboKeyStrokes <> nil) then
 
2692
        FCurrentComboKeyStrokes.ResetKeyCombo; // should not happen
 
2693
    end;
 
2694
    // Check 1st/single stroke in SynEdit.KeyStrokes
 
2695
    if not Handled then begin
 
2696
      FKeyStrokes.ResetKeyCombo;
2409
2697
      Cmd := KeyStrokes.FindKeycodeEx(Key, Shift, Data, IsStartOfCombo);
2410
2698
      if IsStartOfCombo then
2411
 
        FLastKeyStrokes := FKeyStrokes;
 
2699
        FCurrentComboKeyStrokes := FKeyStrokes;
2412
2700
    end;
2413
2701
 
2414
2702
    if Cmd <> ecNone then begin
 
2703
      // Reset FCurrentComboKeyStrokes => no open combo
 
2704
      assert(FCurrentComboKeyStrokes=nil, 'FCurrentComboKeyStrokes<>nil, should be ecNone');
 
2705
      if FCurrentComboKeyStrokes <> nil then
 
2706
        FCurrentComboKeyStrokes.ResetKeyCombo;
 
2707
      FCurrentComboKeyStrokes := nil;
 
2708
 
2415
2709
      Include(FStateFlags, sfHideCursor);
2416
2710
      LastMouseCaret := Point(-1,-1);                                           // includes update cursor
2417
2711
      //DebugLn(['[TCustomSynEdit.KeyDown] key translated ',cmd]);
2429
2723
      FreeMem(Data);
2430
2724
  end;
2431
2725
  UpdateCursor;
 
2726
  SelAvailChange(nil);
2432
2727
  //DebugLn('[TCustomSynEdit.KeyDown] END ',dbgs(Key),' ',dbgs(Shift));
2433
2728
end;
2434
2729
 
2452
2747
procedure TCustomSynEdit.Loaded;
2453
2748
begin
2454
2749
  inherited Loaded;
 
2750
  UpdateCaret;
2455
2751
end;
2456
2752
 
2457
2753
procedure TCustomSynEdit.UTF8KeyPress(var Key: TUTF8Char);
2458
2754
begin
2459
2755
  if Key='' then exit;
 
2756
 
 
2757
  // Run even before OnKeyPress
 
2758
  if FUtf8KeyPressEventList <> nil then
 
2759
    FUtf8KeyPressEventList.CallUtf8KeyPressHandlers(Self, Key);
 
2760
  if Key='' then exit;
 
2761
 
2460
2762
  // don't fire the event if key is to be ignored
2461
2763
  if not (sfIgnoreNextChar in fStateFlags) then begin
2462
2764
    Include(FStateFlags, sfHideCursor);
2483
2785
procedure TCustomSynEdit.KeyPress(var Key: Char);
2484
2786
begin
2485
2787
  if Key=#0 then exit;
 
2788
 
 
2789
  // Run even before OnKeyPress
 
2790
  if FKeyPressEventList <> nil then
 
2791
    FKeyPressEventList.CallKeyPressHandlers(Self, Key);
 
2792
  if Key=#0 then exit;
 
2793
 
2486
2794
  // don't fire the event if key is to be ignored
2487
2795
  if not (sfIgnoreNextChar in fStateFlags) then begin
2488
2796
    Include(FStateFlags, sfHideCursor);
2506
2814
  AnInfo: TSynEditMouseActionInfo): Boolean;
2507
2815
var
2508
2816
  CaretDone: Boolean;
 
2817
  AnAction: TSynEditMouseAction;
2509
2818
 
2510
2819
  procedure MoveCaret;
2511
2820
  begin
2513
2822
   CaretDone := True;
2514
2823
  end;
2515
2824
 
 
2825
  function GetWheelScrollAmount(APageSize: integer): integer;
 
2826
  const
 
2827
    WHEEL_DELTA = 120;
 
2828
    //WHEEL_PAGESCROLL = MAXDWORD;
 
2829
  var
 
2830
    WClicks, WLines: Integer;
 
2831
  begin
 
2832
    Inc(FMouseWheelAccumulator, AnInfo.WheelDelta);
 
2833
    Inc(FMouseWheelLinesAccumulator, MinMax(Mouse.WheelScrollLines, 1, APageSize) * AnInfo.WheelDelta);
 
2834
    WClicks := FMouseWheelAccumulator div WHEEL_DELTA;
 
2835
    WLines  := FMouseWheelLinesAccumulator div WHEEL_DELTA;
 
2836
    dec(FMouseWheelAccumulator, WClicks * WHEEL_DELTA);
 
2837
    dec(FMouseWheelLinesAccumulator, WLines * WHEEL_DELTA);
 
2838
 
 
2839
    case AnAction.Option of
 
2840
      emcoWheelScrollSystem:
 
2841
        begin
 
2842
          Result := Abs(WLines);
 
2843
        end;
 
2844
      emcoWheelScrollLines:
 
2845
        begin
 
2846
          Result := Abs(WClicks);
 
2847
          If Result = 0 then
 
2848
            exit;
 
2849
          if AnAction.Option2 > 0 then
 
2850
            Result := Result * AnAction.Option2;
 
2851
          if (Result > APageSize) then
 
2852
            Result := APageSize;
 
2853
          exit;
 
2854
        end;
 
2855
      emcoWheelScrollPages:
 
2856
          Result := Abs(WClicks) * APageSize;
 
2857
      emcoWheelScrollPagesLessOne:
 
2858
          Result := Abs(WClicks) * (APageSize - 1);
 
2859
      else
 
2860
        begin
 
2861
          Result := Abs(WLines);
 
2862
          exit;
 
2863
        end;
 
2864
    end;
 
2865
 
 
2866
    If Result = 0 then
 
2867
      exit;
 
2868
 
 
2869
    if AnAction.Option2 > 0 then
 
2870
      Result := MulDiv(Result, AnAction.Option2, 100);
 
2871
    if (Result > APageSize) then
 
2872
      Result := APageSize;
 
2873
    if (Result < 1) then
 
2874
      Result := 1;
 
2875
  end;
 
2876
 
2516
2877
var
2517
2878
  ACommand: TSynEditorMouseCommand;
2518
2879
  Handled: Boolean;
2519
 
  AnAction: TSynEditMouseAction;
2520
2880
  ClipHelper: TSynClipboardStream;
 
2881
  i, j: integer;
2521
2882
begin
2522
2883
  AnAction := nil;
2523
2884
  Result := False;
2550
2911
    // Gutter
2551
2912
    if not Result then
2552
2913
      Result := FLeftGutter.DoHandleMouseAction(AnAction, AnInfo);
 
2914
    if not Result then
 
2915
      Result := FRightGutter.DoHandleMouseAction(AnAction, AnInfo);
2553
2916
 
2554
2917
    if Result then begin
2555
2918
      if (not AnInfo.CaretDone) and AnAction.MoveCaret then
2556
2919
        MoveCaret;
 
2920
      if (AnAction.IgnoreUpClick) then
 
2921
        AnInfo.IgnoreUpClick := True;
2557
2922
      exit;
2558
2923
    end;
2559
2924
 
2561
2926
    CaretDone := AnInfo.CaretDone;
2562
2927
    MouseCapture := False;
2563
2928
 
 
2929
    if (ACommand = emcWheelScrollDown)
 
2930
    then begin
 
2931
      // sroll dependant on visible scrollbar / or not at all
 
2932
      if  (fStateFlags * [sfVertScrollbarVisible, sfHorizScrollbarVisible] = [sfHorizScrollbarVisible])
 
2933
      then ACommand := emcWheelHorizScrollDown
 
2934
      else ACommand := emcWheelVertScrollDown;
 
2935
    end;
 
2936
 
 
2937
    if (ACommand = emcWheelScrollUp)
 
2938
    then begin
 
2939
      // sroll dependant on visible scrollbar / or not at all
 
2940
      if  (fStateFlags * [sfVertScrollbarVisible, sfHorizScrollbarVisible] = [sfHorizScrollbarVisible])
 
2941
      then ACommand := emcWheelHorizScrollUp
 
2942
      else ACommand := emcWheelVertScrollUp;
 
2943
    end;
 
2944
 
2564
2945
    case ACommand of
2565
2946
      emcNone: ; // do nothing, but result := true
2566
2947
      emcStartSelections, emcStartColumnSelections, emcStartLineSelections:
2572
2953
            emcStartColumnSelections:
2573
2954
              FMouseSelectionMode := smColumn;
2574
2955
            emcStartLineSelections:
2575
 
              begin
2576
 
                if ACommand = emcStartLineSelections then
2577
 
                  SetLineBlock(AnInfo.NewCaret.LineBytePos, True);
2578
2956
                FMouseSelectionMode := smLine;
2579
 
              end;
2580
2957
            else
2581
2958
              FMouseSelectionMode := FBlockSelection.SelectionMode;
2582
2959
          end;
2621
2998
        end;
2622
2999
      emcPasteSelection:
2623
3000
        begin
2624
 
          ClipHelper := TSynClipboardStream.Create;
2625
 
          try
2626
 
            ClipHelper.ReadFromClipboard(PrimarySelection);
2627
 
            if ClipHelper.TextP <> nil then begin
2628
 
              MoveCaret;
2629
 
              if (not FBlockSelection.Persistent) then
2630
 
                FBlockSelection.Clear;
2631
 
              Result := PasteFromClipboardEx(ClipHelper);
2632
 
            end
2633
 
            else
2634
 
              Result := False;
2635
 
          finally
2636
 
            ClipHelper.Free;
 
3001
          if not ReadOnly then begin
 
3002
            ClipHelper := TSynClipboardStream.Create;
 
3003
            try
 
3004
              ClipHelper.ReadFromClipboard(PrimarySelection);
 
3005
              if ClipHelper.TextP <> nil then begin
 
3006
                MoveCaret;
 
3007
                if (not FBlockSelection.Persistent) then
 
3008
                  FBlockSelection.Clear;
 
3009
                Result := PasteFromClipboardEx(ClipHelper);
 
3010
              end
 
3011
              else
 
3012
                Result := False;
 
3013
            finally
 
3014
              ClipHelper.Free;
 
3015
            end;
2637
3016
          end;
2638
3017
        end;
2639
3018
      emcMouseLink:
2641
3020
          if assigned(fMarkupCtrlMouse) and fMarkupCtrlMouse.IsMouseOverLink and
2642
3021
             assigned(FOnClickLink)
2643
3022
          then
2644
 
            FOnClickLink(Self, AnInfo.Button, AnInfo.Shift, AnInfo.MouseX, AnInfo.MouseY)
 
3023
            FOnClickLink(Self, SynMouseButtonBackMap[AnInfo.Button], AnInfo.Shift, AnInfo.MouseX, AnInfo.MouseY)
2645
3024
          else
2646
3025
            Result := False;
2647
3026
        end;
2662
3041
            MoveCaret;
2663
3042
          CommandProcessor(AnAction.Option, #0, nil);
2664
3043
        end;
 
3044
      emcWheelHorizScrollDown, emcWheelHorizScrollUp:
 
3045
        begin
 
3046
          i := GetWheelScrollAmount(CharsInWindow);
 
3047
          if ACommand = emcWheelHorizScrollUp then i := -i;
 
3048
          if i <> 0 then LeftChar := LeftChar + i;
 
3049
        end;
 
3050
      emcWheelVertScrollDown, emcWheelVertScrollUp:
 
3051
        begin
 
3052
          i := GetWheelScrollAmount(LinesInWindow);
 
3053
          if ACommand = emcWheelVertScrollUp then i := -i;
 
3054
          if i <> 0 then TopView := TopView + i;
 
3055
        end;
 
3056
      emcWheelZoomOut, emcWheelZoomIn:
 
3057
        begin
 
3058
          if ( (ACommand = emcWheelZoomOut) and (abs(Font.Height) < 3) ) or
 
3059
             ( (ACommand = emcWheelZoomIn) and (abs(Font.Height) > 50) )
 
3060
          then begin
 
3061
            Result := False;
 
3062
          end
 
3063
          else begin
 
3064
            j := 1;
 
3065
            if ACommand = emcWheelZoomIn then j := -1;
 
3066
            i := FLastSetFontSize;
 
3067
            if Font.Height < 0
 
3068
            then Font.Height := Font.Height + j
 
3069
            else Font.Height := Font.Height - j;
 
3070
            FLastSetFontSize := i;
 
3071
          end;
 
3072
        end;
 
3073
      emcWheelZoomNorm:
 
3074
        begin
 
3075
          Font.Height := FLastSetFontSize;
 
3076
        end;
2665
3077
      else
2666
3078
        Result := False; // ACommand was not handled => Fallback to parent Context
2667
3079
    end;
2668
3080
 
2669
3081
    if Result and (not CaretDone) and AnAction.MoveCaret then
2670
3082
      MoveCaret;
 
3083
    if Result and (AnAction.IgnoreUpClick) then
 
3084
      AnInfo.IgnoreUpClick := True;
2671
3085
  end;
2672
3086
end;
2673
3087
 
2674
 
procedure TCustomSynEdit.FindAndHandleMouseAction(AButton: TMouseButton;
 
3088
procedure TCustomSynEdit.SetColor(Value: TColor);
 
3089
begin
 
3090
  inherited SetColor(Value);
 
3091
  FPaintArea.BackgroundColor := Color;
 
3092
end;
 
3093
 
 
3094
procedure TCustomSynEdit.FindAndHandleMouseAction(AButton: TSynMouseButton;
2675
3095
  AShift: TShiftState; X, Y: Integer; ACCount:TSynMAClickCount;
2676
 
  ADir: TSynMAClickDir);
 
3096
  ADir: TSynMAClickDir; AWheelDelta: Integer = 0);
2677
3097
var
2678
3098
  Info: TSynEditMouseActionInfo;
2679
3099
begin
2685
3105
    Shift := AShift;
2686
3106
    MouseX := X;
2687
3107
    MouseY := Y;
 
3108
    WheelDelta := AWheelDelta;
2688
3109
    CCount := ACCount;
2689
3110
    Dir := ADir;
2690
3111
    IgnoreUpClick := False;
2695
3116
                                         {$IFDEF FPC}@{$ENDIF}DoHandleMouseAction)
2696
3117
    then
2697
3118
      exit;
2698
 
    // mouse event occured in Gutter ?
 
3119
 
2699
3120
    if FLeftGutter.Visible and (X < FLeftGutter.Width) then begin
2700
 
      FLeftGutter.MaybeHandleMouseAction(Info, {$IFDEF FPC}@{$ENDIF}DoHandleMouseAction);
2701
 
      exit;
2702
 
      // No fallback to text actions
2703
 
    end;
 
3121
      // mouse event occured in Gutter ?
 
3122
      if FLeftGutter.MaybeHandleMouseAction(Info, {$IFDEF FPC}@{$ENDIF}DoHandleMouseAction) then
 
3123
        exit;
 
3124
    end
 
3125
    else
2704
3126
    if FRightGutter.Visible and (X > ClientWidth - FRightGutter.Width) then begin
2705
 
      FRightGutter.MaybeHandleMouseAction(Info, {$IFDEF FPC}@{$ENDIF}DoHandleMouseAction);
2706
 
      exit;
2707
 
      // No fallback to text actions
 
3127
      // mouse event occured in Gutter ?
 
3128
      if FRightGutter.MaybeHandleMouseAction(Info, {$IFDEF FPC}@{$ENDIF}DoHandleMouseAction) then
 
3129
        exit;
 
3130
    end
 
3131
    else
 
3132
    begin
 
3133
      // mouse event occured in selected block ?
 
3134
      if SelAvail and (X >= FTextArea.Bounds.Left) and (X < FTextArea.Bounds.Right) and
 
3135
         (Y >= FTextArea.Bounds.Top) and (Y < FTextArea.Bounds.Bottom) and
 
3136
         IsPointInSelection(FInternalCaret.LineBytePos)
 
3137
      then
 
3138
        if DoHandleMouseAction(FMouseSelActions.GetActionsForOptions(FMouseOptions), Info) then
 
3139
          exit;
 
3140
      // mouse event occured in text?
 
3141
      if DoHandleMouseAction(FMouseTextActions.GetActionsForOptions(FMouseOptions), Info) then
 
3142
        exit;
2708
3143
    end;
2709
 
    // mouse event occured in selected block ?
2710
 
    if SelAvail and (X >= TextLeftPixelOffset) and
2711
 
       //(x < ClientWidth - TextRightPixelOffset - ScrollBarWidth) and
2712
 
       IsPointInSelection(FInternalCaret.LineBytePos)
2713
 
    then
2714
 
      if DoHandleMouseAction(FMouseSelActions, Info) then
2715
 
        exit;
2716
 
    DoHandleMouseAction(FMouseActions, Info);
 
3144
 
 
3145
    DoHandleMouseAction(FMouseActions.GetActionsForOptions(FMouseOptions), Info);
2717
3146
  finally
2718
3147
    if Info.IgnoreUpClick then
2719
3148
      include(fStateFlags, sfIgnoreUpClick);
2728
3157
  //DebugLn(['TCustomSynEdit.MouseDown START Mouse=',X,',',Y,' Caret=',CaretX,',',CaretY,', BlockBegin=',BlockBegin.X,',',BlockBegin.Y,' BlockEnd=',BlockEnd.X,',',BlockEnd.Y]);
2729
3158
  Exclude(FStateFlags, sfHideCursor);
2730
3159
  FInMouseClickEvent := True;
 
3160
 
 
3161
  if FMouseDownEventList <> nil then
 
3162
    FMouseDownEventList.CallMouseDownHandlers(Self, Button, Shift, X, Y);
 
3163
 
2731
3164
  if (X>=ClientWidth-ScrollBarWidth) or (Y>=ClientHeight-ScrollBarWidth) then
2732
3165
  begin
2733
3166
    inherited MouseDown(Button, Shift, X, Y);
2770
3203
      Include(fStateFlags, sfRightGutterClick);
2771
3204
      FRightGutter.MouseDown(Button, Shift, X, Y);
2772
3205
    end;
2773
 
    FindAndHandleMouseAction(Button, Shift, X, Y, CType, cdDown);
 
3206
    FindAndHandleMouseAction(SynMouseButtonMap[Button], Shift, X, Y, CType, cdDown);
2774
3207
  finally
2775
3208
    DecPaintLock;
2776
3209
  end;
2782
3215
  inherited MouseDown(Button, Shift, X, Y);
2783
3216
  LCLIntf.SetFocus(Handle);
2784
3217
  UpdateCaret;
 
3218
  SelAvailChange(nil);
2785
3219
  //debugln('TCustomSynEdit.MouseDown END sfWaitForDragging=',dbgs(sfWaitForDragging in fStateFlags),' ');
2786
3220
end;
2787
3221
 
2788
3222
procedure TCustomSynEdit.MouseMove(Shift: TShiftState; X, Y: Integer);
2789
 
var
2790
 
  Z: integer;
2791
3223
begin
2792
3224
  Exclude(FStateFlags, sfHideCursor);
2793
3225
  inherited MouseMove(Shift, x, y);
2801
3233
  UpdateCursor;
2802
3234
 
2803
3235
  if (sfWaitForMouseSelecting in fStateFlags) and MouseCapture and
2804
 
     ( (abs(fMouseDownX-X) >= MinMax(fCharWidth div 2, 2, 4)) or
2805
 
       (abs(fMouseDownY-Y) >= MinMax(fTextHeight div 2, 2, 4)) )
 
3236
     ( (abs(fMouseDownX-X) >= MinMax(CharWidth div 2, 2, 4)) or
 
3237
       (abs(fMouseDownY-Y) >= MinMax(LineHeight div 2, 2, 4)) )
2806
3238
  then
2807
3239
    FStateFlags := FStateFlags - [sfWaitForMouseSelecting] + [sfMouseSelecting];
2808
3240
 
2827
3259
    FInternalCaret.AssignFrom(FCaret);
2828
3260
    FInternalCaret.LineCharPos := PixelsToRowColumn(Point(X,Y));
2829
3261
 
2830
 
    if ((X >= TextLeftPixelOffset(False)) or (fLeftChar <= 1)) and
2831
 
       ( (X < ClientWidth - TextRightPixelOffset)
2832
 
         or (LeftChar >= CurrentMaxLeftChar)) and
2833
 
       ((Y >= 0) or (fTopLine <= 1)) and
2834
 
       ((Y < ClientHeight-ScrollBarWidth) or (fTopLine >= CurrentMaxTopLine))
 
3262
    // compare to Bounds => Padding area does not scroll
 
3263
    if ( (X >= FTextArea.Bounds.Left)   or (LeftChar <= 1) ) and
 
3264
       ( (X <  FTextArea.Bounds.Right)  or (LeftChar >= CurrentMaxLeftChar) ) and
 
3265
       ( (Y >= FTextArea.Bounds.Top)    or (TopView <= 1) ) and
 
3266
       ( (Y <  FTextArea.Bounds.Bottom) or (TopView >= CurrentMaxTopView) )
2835
3267
    then begin
2836
3268
      if (sfMouseSelecting in fStateFlags) and not FInternalCaret.IsAtPos(FCaret) then
2837
3269
        Include(fStateFlags, sfMouseDoneSelecting);
2841
3273
    end
2842
3274
    else begin
2843
3275
      // begin scrolling?
2844
 
      Dec(X, TextLeftPixelOffset(False));
2845
 
      // calculate chars past right
2846
 
      Z := X - (fCharsInWindow * fCharWidth);
2847
 
      if Z > 0 then
2848
 
        Inc(Z, fCharWidth);
2849
 
      fScrollDeltaX := Max(Z div fCharWidth, 0);
2850
 
      if fScrollDeltaX = 0 then begin
2851
 
        // calculate chars past left
2852
 
        Z := X;
2853
 
        if Z < 0 then
2854
 
          Dec(Z, fCharWidth);
2855
 
        fScrollDeltaX := Min(Z div fCharWidth, 0);
2856
 
      end;
2857
 
      // calculate lines past bottom
2858
 
      Z := Y - (fLinesInWindow * fTextHeight);
2859
 
      if Z > 0 then
2860
 
        Inc(Z, fTextHeight);
2861
 
      fScrollDeltaY := Max(Z div fTextHeight, 0);
2862
 
      if fScrollDeltaY = 0 then begin
2863
 
        // calculate lines past top
2864
 
        Z := Y;
2865
 
        if Z < 0 then
2866
 
          Dec(Z, fTextHeight);
2867
 
        fScrollDeltaY := Min(Z div fTextHeight, 0);
2868
 
      end;
 
3276
      if X < FTextArea.Bounds.Left then
 
3277
        FScrollDeltaX := Min((X - FTextArea.Bounds.Left - CharWidth) div CharWidth, -1)
 
3278
      else if x >= FTextArea.Bounds.Right then
 
3279
        FScrollDeltaX := Max((X - FTextArea.Bounds.Right + 1 + CharWidth) div CharWidth, 1)
 
3280
      else
 
3281
        FScrollDeltaX := 0;
 
3282
 
 
3283
      if Y < FTextArea.Bounds.Top then
 
3284
        FScrollDeltaY := Min((Y - FTextArea.Bounds.Top - LineHeight) div LineHeight, -1)
 
3285
      else if Y >= FTextArea.Bounds.Bottom then
 
3286
        FScrollDeltaY := Max((Y - FTextArea.Bounds.Bottom + 1 + LineHeight) div LineHeight, 1)
 
3287
      else
 
3288
        FScrollDeltaY := 0;
 
3289
 
2869
3290
      fScrollTimer.Enabled := (fScrollDeltaX <> 0) or (fScrollDeltaY <> 0);
2870
3291
      if (sfMouseSelecting in fStateFlags) and ((fScrollDeltaX <> 0) or (fScrollDeltaY <> 0)) then
2871
3292
        Include(fStateFlags, sfMouseDoneSelecting);
2887
3308
var
2888
3309
  C: TPoint;
2889
3310
  CurMousePos: TPoint;
2890
 
  Z: integer;
2891
3311
  X, Y: Integer;
2892
3312
begin
2893
3313
  // changes to line / column in one go
2895
3315
    FBlockSelection.IncPersistentLock;
2896
3316
  DoIncPaintLock(Self); // No editing is taking place
2897
3317
  try
 
3318
    CurMousePos:=Point(0,0);
2898
3319
    GetCursorPos(CurMousePos);
2899
3320
    CurMousePos:=ScreenToClient(CurMousePos);
2900
3321
    C := PixelsToLogicalPos(CurMousePos);
 
3322
 
2901
3323
    // recalculate scroll deltas
2902
 
    Dec(CurMousePos.X, TextLeftPixelOffset(False));
2903
 
    // calculate chars past right
2904
 
    Z := CurMousePos.X - (fCharsInWindow * fCharWidth);
2905
 
    if Z > 0 then
2906
 
      Inc(Z, fCharWidth);
2907
 
    fScrollDeltaX := Max(Z div fCharWidth, 0);
2908
 
    if fScrollDeltaX = 0 then begin
2909
 
      // calculate chars past left
2910
 
      Z := CurMousePos.X;
2911
 
      if Z < 0 then
2912
 
        Dec(Z, fCharWidth);
2913
 
      fScrollDeltaX := Min(Z div fCharWidth, 0);
2914
 
    end;
2915
 
    // calculate lines past bottom
2916
 
    Z := CurMousePos.Y - (fLinesInWindow * fTextHeight);
2917
 
    if Z > 0 then
2918
 
      Inc(Z, fTextHeight);
2919
 
    fScrollDeltaY := Max(Z div fTextHeight, 0);
2920
 
    if fScrollDeltaY = 0 then begin
2921
 
      // calculate lines past top
2922
 
      Z := CurMousePos.Y;
2923
 
      if Z < 0 then
2924
 
        Dec(Z, fTextHeight);
2925
 
      fScrollDeltaY := Min(Z div fTextHeight, 0);
2926
 
    end;
 
3324
    if CurMousePos.X < FTextArea.Bounds.Left then
 
3325
      FScrollDeltaX := Min((CurMousePos.X - FTextArea.Bounds.Left - CharWidth) div CharWidth, -1)
 
3326
    else if CurMousePos.x >= FTextArea.Bounds.Right then
 
3327
      FScrollDeltaX := Max((CurMousePos.X - FTextArea.Bounds.Right + 1 + CharWidth) div CharWidth, 1)
 
3328
    else
 
3329
      FScrollDeltaX := 0;
 
3330
 
 
3331
    if CurMousePos.Y < FTextArea.Bounds.Top then
 
3332
      FScrollDeltaY := Min((CurMousePos.Y - FTextArea.Bounds.Top - LineHeight) div LineHeight, -1)
 
3333
    else if CurMousePos.Y >= FTextArea.Bounds.Bottom then
 
3334
      FScrollDeltaY := Max((CurMousePos.Y - FTextArea.Bounds.Bottom + 1 + LineHeight) div LineHeight, 1)
 
3335
    else
 
3336
      FScrollDeltaY := 0;
 
3337
 
2927
3338
    fScrollTimer.Enabled := (fScrollDeltaX <> 0) or (fScrollDeltaY <> 0);
2928
3339
    // now scroll
2929
3340
    if fScrollDeltaX <> 0 then begin
2956
3367
  end;
2957
3368
end;
2958
3369
 
2959
 
procedure TCustomSynEdit.DoContextPopup(const MousePos: TPoint; var Handled: Boolean);
 
3370
procedure TCustomSynEdit.DoContextPopup(MousePos: TPoint; var Handled: Boolean);
2960
3371
begin
2961
3372
  Handled := FInMouseClickEvent;
2962
3373
  if not Handled then
3008
3419
    Exclude(fStateFlags, sfWaitForDragging);
3009
3420
  end;
3010
3421
 
3011
 
  if SelAvail then
3012
 
    AquirePrimarySelection;
3013
3422
  if (X>=ClientWidth-ScrollBarWidth) or (Y>=ClientHeight-ScrollBarWidth) then
3014
3423
    exit;
3015
3424
  LastMouseCaret:=PixelsToRowColumn(Point(X,Y));
3027
3436
      FRightGutter.MouseUp(Button, Shift, X, Y);
3028
3437
      Exclude(fStateFlags, sfRightGutterClick);
3029
3438
    end;
3030
 
    FindAndHandleMouseAction(Button, Shift, X, Y, CType, cdUp);
 
3439
    FindAndHandleMouseAction(SynMouseButtonMap[Button], Shift, X, Y, CType, cdUp);
3031
3440
  finally
3032
3441
    DecPaintLock;
3033
3442
  end;
3035
3444
    PopupMenu.PopupComponent:=self;
3036
3445
    PopupMenu.PopUp;
3037
3446
  end;
 
3447
  SelAvailChange(nil);
3038
3448
  //DebugLn('TCustomSynEdit.MouseUp END Mouse=',X,',',Y,' Caret=',CaretX,',',CaretY,', BlockBegin=',BlockBegin.X,',',BlockBegin.Y,' BlockEnd=',BlockEnd.X,',',BlockEnd.Y);
3039
3449
end;
3040
3450
 
3041
3451
procedure TCustomSynEdit.Paint;
3042
3452
var
3043
 
  rcClip, rcDraw: TRect;
3044
 
  nL1, nL2, nC1, nC2: integer;
 
3453
  rcClip: TRect;
3045
3454
begin
3046
3455
  // Get the invalidated rect. Compute the invalid area in lines / columns.
3047
3456
  rcClip := Canvas.ClipRect;
3048
3457
 
3049
3458
  If FPaintLock > 0 then begin
3050
3459
    debugln(['Warning: SynEdit.Paint called during PaintLock']);
 
3460
    {$IFDEF SynCheckPaintLock}
 
3461
    DumpStack;
 
3462
    {$ENDIF}
3051
3463
    // Ensure this will be repainted after PaintLock
3052
3464
    if FInvalidateRect.Top < 0 then
3053
3465
      FInvalidateRect := rcClip
3074
3486
 
3075
3487
  Include(fStateFlags,sfPainting);
3076
3488
  Exclude(fStateFlags, sfHasScrolled);
3077
 
  // columns
3078
 
  nC1 := LeftChar;
3079
 
  if (rcClip.Left > TextLeftPixelOffset) then
3080
 
    Inc(nC1, (rcClip.Left - TextLeftPixelOffset) div CharWidth);
3081
 
  nC2 := LeftChar +
3082
 
    ( Min(rcClip.Right, ClientWidth - TextRightPixelOffset - ScrollBarWidth)
3083
 
     - TextLeftPixelOffset + CharWidth - 1) div CharWidth;
3084
 
  // lines
3085
 
  nL1 := Max(rcClip.Top div fTextHeight, 0);
3086
 
  nL2 := Min((rcClip.Bottom-1) div fTextHeight,
3087
 
             FFoldedLinesView.Count - FFoldedLinesView.TopLine);
3088
 
  {$IFDEF SYNSCROLLDEBUG}
3089
 
  debugln(['PAINT ',DbgSName(self),' rect=',dbgs(rcClip), ' L1=',nL1, '  Nl2=',nL2]);
3090
 
  {$ENDIF}
3091
 
  //DebugLn('TCustomSynEdit.Paint LinesInWindow=',dbgs(LinesInWindow),' nL1=',dbgs(nL1),' nL2=',dbgs(nL2));
3092
3489
  // Now paint everything while the caret is hidden.
3093
3490
  FScreenCaret.Hide;
3094
3491
  try
3095
 
    // First paint the gutter area if it was (partly) invalidated.
3096
 
    if FLeftGutter.Visible and (rcClip.Left < FLeftGutter.Width) then begin
3097
 
      rcDraw := rcClip;
3098
 
      rcDraw.Right := FLeftGutter.Width;
3099
 
      FLeftGutter.Paint(Canvas, rcDraw, nL1, nL2);
3100
 
    end;
3101
 
    // Then paint the text area if it was (partly) invalidated.
3102
 
    if (rcClip.Right > TextLeftPixelOffset(False)) then begin
3103
 
      rcDraw := rcClip;
3104
 
      rcDraw.Left  := Max(rcDraw.Left, TextLeftPixelOffset(False)); // Todo: This is also checked in paintLines (together with right side)
3105
 
      rcDraw.Right := Min(rcDraw.Right, ClientWidth - TextRightPixelOffset - ScrollBarWidth);
3106
 
      PaintTextLines(rcDraw, nL1, nL2, nC1, nC2);
3107
 
    end;
3108
 
    // right gutter
3109
 
    if FRightGutter.Visible and (rcClip.Right > ClientWidth - FRightGutter.Width - ScrollBarWidth) then begin
3110
 
      rcDraw := rcClip;
3111
 
      rcDraw.Left := ClientWidth - FRightGutter.Width - ScrollBarWidth;
3112
 
      FRightGutter.Paint(Canvas, rcDraw, nL1, nL2);
3113
 
    end;
3114
 
    // If there is a custom paint handler call it.
 
3492
    FPaintArea.Paint(Canvas, rcClip);
3115
3493
    DoOnPaint;
3116
3494
  finally
3117
3495
    {$IFDEF EnableDoubleBuf}
3118
3496
    EndPaintBuffer(rcClip);
3119
3497
    {$ENDIF}
3120
 
    UpdateCaret;
 
3498
    UpdateCaret; // Todo: only ShowCaret() / do not create caret here / Issue 0021924
3121
3499
    Exclude(fStateFlags,sfPainting);
3122
3500
  end;
3123
3501
end;
3170
3548
  Invalidate;
3171
3549
end;
3172
3550
 
3173
 
procedure TCustomSynEdit.PaintTextLines(AClip: TRect; FirstLine, LastLine,
3174
 
  FirstCol, LastCol: integer);
3175
 
// FirstLine, LastLine are based 1
3176
 
// FirstCol, LastCol are screen based 1 without scrolling (physical position).
3177
 
//  i.e. the real screen position is fTextOffset+Pred(FirstCol)*CharWidth
3178
 
var
3179
 
  bDoRightEdge: boolean; // right edge
3180
 
  nRightEdge: integer;
3181
 
  colEditorBG: TColor;
3182
 
    // painting the background and the text
3183
 
  rcLine, rcToken: TRect;
3184
 
  EraseLeft, DrawLeft: Integer;  // LeftSide for EraseBackground, Text
3185
 
  CurLine: integer;         // Screen-line index for the loop
3186
 
  CurTextIndex: Integer;    // Current Index in text
3187
 
  CurPhysPos, CurLogIndex : Integer; // Physical Start Position of next token in current Line
3188
 
  ForceEto: Boolean;
3189
 
  TokenAccu: record
3190
 
    Len, MaxLen: integer;
3191
 
    PhysicalStartPos, PhysicalEndPos: integer;
3192
 
    p: PChar;
3193
 
    FG, BG: TColor;
3194
 
    Style: TFontStyles;
3195
 
    FrameColor: array[TSynFrameSide] of TColor;
3196
 
    FrameStyle: array[TSynFrameSide] of TSynLineStyle;
3197
 
  end;
3198
 
  dc: HDC;
3199
 
 
3200
 
  ExpandedPaintToken: string; // used to create the string sent to TextDrawer
3201
 
  CharWidths: TPhysicalCharWidths;
3202
 
 
3203
 
{ local procedures }
3204
 
 
3205
 
  procedure SetTokenAccuLength;
3206
 
  begin
3207
 
    ReAllocMem(TokenAccu.p,TokenAccu.MaxLen+1);
3208
 
    TokenAccu.p[TokenAccu.MaxLen]:=#0;
3209
 
  end;
3210
 
 
3211
 
  function ExpandSpecialChars(var p: PChar; var Count: integer;
3212
 
    PhysicalStartPos: integer): Integer;
3213
 
  // if there are no tabs or special chars: keep p and Count untouched
3214
 
  // if there are special chars: copy p into ExpandedPaintToken buffer,
3215
 
  //                             convert tabs to spaces, and return the buffer
3216
 
  // Return DisplayCell-Count in Buffer
3217
 
  var
3218
 
    i: integer;
3219
 
    LengthNeeded: Integer;
3220
 
    DestPos: Integer;
3221
 
    SrcPos: Integer;
3222
 
    Dest: PChar;
3223
 
    c: Char;
3224
 
    CharLen: Integer;
3225
 
    Special, HasTabs: boolean;
3226
 
    Fill: Integer;
3227
 
  begin
3228
 
      LengthNeeded := 0;
3229
 
    Result := 0;
3230
 
    HasTabs := False;
3231
 
    SrcPos:=0;
3232
 
    for i := CurLogIndex to CurLogIndex + Count -1 do begin
3233
 
      Result := Result + CharWidths[i];
3234
 
      if CharWidths[i] > 1 then
3235
 
        LengthNeeded := LengthNeeded + CharWidths[i] - 1;
3236
 
      if p[SrcPos] = #9 then HasTabs := True;
3237
 
      inc(SrcPos);
3238
 
    end;
3239
 
    Special:=eoShowSpecialChars in Options;
3240
 
    if (not Special) and (LengthNeeded=0) and (not HasTabs)
3241
 
    and (FindInvalidUTF8Character(p,Count)<0) then
3242
 
      exit;
3243
 
    LengthNeeded := LengthNeeded + Count;
3244
 
    if Special then LengthNeeded:=LengthNeeded*2;
3245
 
    if length(ExpandedPaintToken)<LengthNeeded then
3246
 
      SetLength(ExpandedPaintToken,LengthNeeded+CharsInWindow);
3247
 
    //DebugLn(['ExpandSpecialChars Count=',Count,' TabCount=',TabCount,' Special=',Special,' LengthNeeded=',LengthNeeded]);
3248
 
    SrcPos:=0;
3249
 
    DestPos:=0;
3250
 
    Dest:=PChar(Pointer(ExpandedPaintToken));
3251
 
    if UseUTF8 then begin
3252
 
      while SrcPos<Count do begin
3253
 
        c:=p[SrcPos];
3254
 
        Fill := CharWidths[CurLogIndex + SrcPos] - 1;
3255
 
        if c = #9 then begin
3256
 
          // tab char, fill spaces at start
3257
 
          for i := 0 to Fill do begin
3258
 
            Dest[DestPos]:= ' ';
3259
 
            inc(DestPos);
3260
 
          end;
3261
 
          if Special then begin
3262
 
            // #194#187 looks like >>
3263
 
            Dest[DestPos-1] := #194;
3264
 
            Dest[DestPos]   := #187;
3265
 
            inc(DestPos);
3266
 
          end;
3267
 
          inc(SrcPos);
3268
 
        end
3269
 
        else begin
3270
 
          // could be UTF8 char
3271
 
          if c in [#128..#255]
3272
 
          then CharLen := UTF8CharacterStrictLength(@p[SrcPos])
3273
 
          else CharLen := 1;
3274
 
          if CharLen=0 then begin
3275
 
            // invalid character
3276
 
            Dest[DestPos]:='?';
3277
 
            inc(DestPos);
3278
 
            inc(SrcPos);
3279
 
          end else begin
3280
 
            // normal UTF-8 character
3281
 
            for i:=1 to CharLen do begin
3282
 
              Dest[DestPos]:=p[SrcPos];
3283
 
              inc(DestPos);
3284
 
              inc(SrcPos);
3285
 
            end;
3286
 
            if (c = #32) and Special then begin
3287
 
              // #194#183 looks like .
3288
 
              Dest[DestPos-1] := #194;
3289
 
              Dest[DestPos]   := #183;
3290
 
              inc(DestPos);
3291
 
            end;
3292
 
            for i := 1 to Fill do begin
3293
 
              Dest[DestPos]:= ' ';
3294
 
              inc(DestPos);
3295
 
            end;
3296
 
          end;
3297
 
          // ToDo: pass the eto with to fTextDrawer, instead of filling with spaces
3298
 
          if Fill > 0 then ForceEto := True;
3299
 
        end;
3300
 
      end;
3301
 
    end else begin
3302
 
      // non UTF-8
3303
 
      while SrcPos<Count do begin
3304
 
        c:=p[SrcPos];
3305
 
        Fill := CharWidths[CurLogIndex + SrcPos] - 1;
3306
 
        if c = #9 then // tab char
3307
 
          Dest[DestPos] := ' '
3308
 
        else begin
3309
 
          Dest[DestPos] := p[SrcPos];
3310
 
          if Fill > 0 then ForceEto := True;
3311
 
        end;
3312
 
        inc(DestPos);
3313
 
        inc(SrcPos);
3314
 
        for i := 1 to Fill do begin
3315
 
          Dest[DestPos]:= ' ';
3316
 
          inc(DestPos);
3317
 
        end;
3318
 
      end;
3319
 
    end;
3320
 
    p:=PChar(Pointer(ExpandedPaintToken));
3321
 
    Count:=DestPos;
3322
 
    //debugln('ExpandSpecialChars Token with Tabs: "',DbgStr(copy(ExpandedPaintToken,1,Count)),'"');
3323
 
  end;
3324
 
 
3325
 
  const
3326
 
    ETOOptions = ETO_OPAQUE; // Note: clipping is slow and not needed
3327
 
 
3328
 
  procedure PaintToken(Token: PChar; TokenLen, FirstPhysical: integer);
3329
 
  // FirstPhysical is the physical (screen without scrolling)
3330
 
  // column of the first character
3331
 
  var
3332
 
    nX: integer;
3333
 
    tok: TRect;
3334
 
  begin
3335
 
    {debugln('PaintToken A TokenLen=',dbgs(TokenLen),
3336
 
      ' FirstPhysical=',dbgs(FirstPhysical),
3337
 
      ' Tok="'+copy(Token, 1, TokenLen),'"',
3338
 
      ' rcToken='+dbgs(rcToken.Left)+'-'+dbgs(rcToken.Right));}
3339
 
    if (rcToken.Right <= rcToken.Left) then exit;
3340
 
    // Draw the right edge under the text if necessary
3341
 
    nX := ScreenColumnToXValue(FirstPhysical); // == rcToken.Left
3342
 
    if ForceEto then fTextDrawer.ForceNextTokenWithEto;
3343
 
    if bDoRightEdge and (not (eoHideRightMargin in Options))
3344
 
    and (nRightEdge<rcToken.Right) and (nRightEdge>=rcToken.Left)
3345
 
    then begin
3346
 
      // draw background (use rcToken, so we do not delete the divider-draw-line)
3347
 
      if rcToken.Left < nRightEdge then begin
3348
 
        tok := rcToken;
3349
 
        tok.Right := nRightEdge;
3350
 
        InternalFillRect(dc, tok);
3351
 
      end;
3352
 
      if rcToken.Right > nRightEdge then begin
3353
 
        tok := rcToken;
3354
 
        tok.Left := nRightEdge;
3355
 
        tok.Bottom := rcLine.Bottom;
3356
 
        InternalFillRect(dc, tok);
3357
 
      end;
3358
 
      // draw edge (use rcLine / rcToken may be reduced)
3359
 
      LCLIntf.MoveToEx(dc, nRightEdge, rcLine.Top, nil);
3360
 
      LCLIntf.LineTo(dc, nRightEdge, rcLine.Bottom + 1);
3361
 
      // draw text
3362
 
      fTextDrawer.ExtTextOut(nX, rcToken.Top, ETOOptions-ETO_OPAQUE, rcToken,
3363
 
                             Token, TokenLen, rcLine.Bottom);
3364
 
    end else begin
3365
 
      // draw text with background
3366
 
      //debugln('PaintToken nX=',dbgs(nX),' Token=',dbgstr(copy(Token,1, TokenLen)),' rcToken=',dbgs(rcToken));
3367
 
      tok := rcToken;
3368
 
      if rcToken.Right > nRightEdge + 1 then
3369
 
        tok.Bottom := rcLine.Bottom;
3370
 
      fTextDrawer.ExtTextOut(nX, rcToken.Top, ETOOptions, tok,
3371
 
                             Token, TokenLen, rcLine.Bottom);
3372
 
    end;
3373
 
    rcToken.Left := rcToken.Right;
3374
 
  end;
3375
 
 
3376
 
  procedure PaintHighlightToken(bFillToEOL: boolean);
3377
 
  var
3378
 
    nX1, eolx: integer;
3379
 
    NextPos : Integer;
3380
 
    MarkupInfo, FoldedCodeInfo: TSynSelectedColor;
3381
 
    FillFCol, FillBCol, FillFrame: TColor;
3382
 
    FrameStyle: TSynLineStyle;
3383
 
    FillStyle: TFontStyles;
3384
 
    tok: TRect;
3385
 
    Attr: TSynHighlighterAttributes;
3386
 
    s: TSynFrameSide;
3387
 
    side: TSynFrameSide;
3388
 
  begin
3389
 
    {debugln('PaintHighlightToken A TokenAccu: Len=',dbgs(TokenAccu.Len),
3390
 
      ' PhysicalStartPos=',dbgs(TokenAccu.PhysicalStartPos),
3391
 
      ' PhysicalEndPos=',dbgs(TokenAccu.PhysicalEndPos),
3392
 
      ' "',copy(TokenAccu.p,1,TokenAccu.Len),'"');}
3393
 
 
3394
 
    // Any token chars accumulated?
3395
 
    if (TokenAccu.Len > 0) then 
3396
 
    begin
3397
 
      // Initialize the colors and the font style.
3398
 
      with fTextDrawer do 
3399
 
      begin
3400
 
        SetBackColor(TokenAccu.BG);
3401
 
        SetForeColor(TokenAccu.FG);
3402
 
        SetStyle(TokenAccu.Style);
3403
 
        for s := low(TSynFrameSide) to high(TSynFrameSide) do begin
3404
 
          FrameColor[s] := TokenAccu.FrameColor[s];
3405
 
          FrameStyle[s] := TokenAccu.FrameStyle[s];
3406
 
        end;
3407
 
      end;
3408
 
      // Paint the chars
3409
 
      rcToken.Right := ScreenColumnToXValue(TokenAccu.PhysicalEndPos+1);
3410
 
      if rcToken.Right > AClip.Right then begin
3411
 
        rcToken.Right := AClip.Right;
3412
 
        fTextDrawer.FrameColor[sfdRight] := clNone; // right side of char is not painted
3413
 
      end;
3414
 
      with TokenAccu do PaintToken(p, Len, PhysicalStartPos);
3415
 
    end;
3416
 
 
3417
 
    // Fill the background to the end of this line if necessary.
3418
 
    if bFillToEOL and (rcToken.Left < rcLine.Right) then begin
3419
 
      eolx := rcToken.Left; // remeber end of actual line, so we can decide to draw the right edge
3420
 
      NextPos := Min(LastCol, TokenAccu.PhysicalEndPos+1);
3421
 
      if Assigned(fHighlighter) then
3422
 
        Attr := fHighlighter.GetEndOfLineAttribute
3423
 
      else
3424
 
        Attr := nil;
3425
 
      repeat
3426
 
        MarkupInfo := fMarkupManager.GetMarkupAttributeAtRowCol(FFoldedLinesView.TextIndex[CurLine]+1, NextPos);
3427
 
        NextPos := fMarkupManager.GetNextMarkupColAfterRowCol(FFoldedLinesView.TextIndex[CurLine]+1, NextPos);
3428
 
 
3429
 
        if Assigned(Attr) then
3430
 
        begin
3431
 
          FillFCol := Attr.Foreground;
3432
 
          FillBCol := Attr.Background;
3433
 
          FillFrame := Attr.FrameColor;
3434
 
          FillStyle := Attr.Style;
3435
 
          FrameStyle := Attr.FrameStyle;
3436
 
          if FillFCol = clNone then FillFCol := Font.Color;
3437
 
          if FillBCol = clNone then FillBCol := colEditorBG;
3438
 
        end else
3439
 
        begin
3440
 
          FillFCol := Font.Color;
3441
 
          FillBCol := colEditorBG;
3442
 
          FillFrame := clNone;
3443
 
          FillStyle := Font.Style;
3444
 
          FrameStyle := slsSolid;
3445
 
        end;
3446
 
 
3447
 
        if Assigned(MarkupInfo) then
3448
 
          MarkupInfo.ModifyColors(FillFCol, FillBCol, FillFrame, FillStyle, FrameStyle);
3449
 
 
3450
 
        fTextDrawer.BackColor := FillBCol;
3451
 
        //fTextDrawer.ForeColor := FillFCol; // for underline
3452
 
        //fTextDrawer.Style := FillStyle;
3453
 
 
3454
 
        if NextPos < 1
3455
 
        then nX1 := rcLine.Right
3456
 
        else begin
3457
 
          nX1 := ScreenColumnToXValue(NextPos);
3458
 
          if nX1 > rcLine.Right
3459
 
          then nX1 := rcLine.Right;
3460
 
        end;
3461
 
 
3462
 
        if nX1 > nRightEdge then begin
3463
 
          if rcToken.Left < nRightEdge then begin
3464
 
            tok := rcToken;
3465
 
            tok.Right := nRightEdge;
3466
 
            InternalFillRect(dc, tok);
3467
 
            rcToken.Left := nRightEdge;
3468
 
          end;
3469
 
          rcToken.Bottom := rcLine.Bottom;
3470
 
        end;
3471
 
        rcToken.Right := nX1;
3472
 
        InternalFillRect(dc, rcToken); {TODO: if style underline, then print spaces}
3473
 
        rcToken.Left := nX1;
3474
 
      until nX1 >= rcLine.Right;
3475
 
 
3476
 
      // Draw the right edge if necessary.
3477
 
      if bDoRightEdge and (not (eoHideRightMargin in Options))
3478
 
      and (nRightEdge >= eolx) then begin // xx rc Token
3479
 
        LCLIntf.MoveToEx(dc, nRightEdge, rcLine.Top, nil);
3480
 
        LCLIntf.LineTo(dc, nRightEdge, rcLine.Bottom + 1);
3481
 
      end;
3482
 
 
3483
 
      if FFoldedLinesView.FoldType[CurLine] * [cfCollapsedFold, cfCollapsedHide] <> [] then
3484
 
      begin
3485
 
        FillFCol := Font.Color;
3486
 
        FillBCol := colEditorBG;
3487
 
        FillFrame := Font.Color;
3488
 
        FrameStyle := slsSolid;
3489
 
        FillStyle  := [];
3490
 
        MarkupInfo := fMarkupManager.GetMarkupAttributeAtRowCol(FFoldedLinesView.TextIndex[CurLine]+1, CurPhysPos + 3);
3491
 
        if MarkupInfo <> nil then
3492
 
          MarkupInfo.ModifyColors(FillFCol, FillBCol, FillFrame, FillStyle, FrameStyle);
3493
 
        FoldedCodeInfo := FoldedCodeColor;
3494
 
        if Assigned(FoldedCodeInfo) then
3495
 
          FoldedCodeInfo.ModifyColors(FillFCol, FillBCol, FillFrame, FillStyle, FrameStyle);
3496
 
        if (FillBCol = FillFCol) then begin // or if diff(gb,fg) < x
3497
 
          if FillBCol = colEditorBG
3498
 
          then FillFCol := not(FillBCol) and $00ffffff // or maybe Font.color ?
3499
 
          else FillFCol := colEditorBG;
3500
 
        end;
3501
 
 
3502
 
        rcToken.Left := ScreenColumnToXValue(CurPhysPos+3);
3503
 
        rcToken.Right := ScreenColumnToXValue(CurPhysPos+6);
3504
 
 
3505
 
        FTextDrawer.ForeColor := FillFCol;
3506
 
        FTextDrawer.BackColor := FillBCol;
3507
 
        FTextDrawer.SetStyle(FillStyle);
3508
 
 
3509
 
        if Assigned(FoldedCodeInfo) and (FoldedCodeInfo.FrameColor <> clNone) then
3510
 
        begin
3511
 
          for side := low(TSynFrameSide) to high(TSynFrameSide) do begin
3512
 
            if ( (FoldedCodeInfo.FrameEdges = sfeAround) or
3513
 
                 ((FoldedCodeInfo.FrameEdges = sfeBottom) and (side = sfdBottom)) or
3514
 
                 ((FoldedCodeInfo.FrameEdges = sfeLeft) and (side = sfdLeft))
3515
 
               )
3516
 
            then
3517
 
              FTextDrawer.FrameColor[side] := FoldedCodeInfo.FrameColor
3518
 
            else
3519
 
              FTextDrawer.FrameColor[side] := clNone;
3520
 
            FTextDrawer.FrameStyle[side] := FoldedCodeInfo.FrameStyle;
3521
 
          end;
3522
 
        end;
3523
 
        if rcToken.Right > rcLine.Right then begin
3524
 
          rcToken.Right := rcLine.Right;
3525
 
          fTextDrawer.FrameColor[sfdRight] := clNone; // right side of char is not painted
3526
 
        end;
3527
 
        if rcToken.Right > rcToken.Left then begin
3528
 
          if ForceEto then fTextDrawer.ForceNextTokenWithEto;
3529
 
          fTextDrawer.ExtTextOut(rcToken.Left, rcToken.Top, ETOOptions-ETO_OPAQUE,
3530
 
                                 rcToken, '...', 3, rcLine.Bottom);
3531
 
        end;
3532
 
      end;
3533
 
    end;
3534
 
  end;
3535
 
 
3536
 
  procedure AddHighlightToken(Token: PChar;
3537
 
    TokenLen, PhysicalStartPos, PhysicalEndPos: integer;
3538
 
    MarkupInfo : TSynSelectedColor);
3539
 
  var
3540
 
    CanAppend: boolean;
3541
 
    SpacesTest, IsSpaces: boolean;
3542
 
    i: integer;
3543
 
    s: TSynFrameSide;
3544
 
 
3545
 
    function TokenIsSpaces: boolean;
3546
 
    var
3547
 
      pTok: PChar;
3548
 
      Cnt: Integer;
3549
 
    begin
3550
 
      if not SpacesTest then begin
3551
 
        SpacesTest := TRUE;
3552
 
        IsSpaces := not (eoShowSpecialChars in fOptions) ;
3553
 
        pTok := PChar(Pointer(Token));
3554
 
        Cnt := TokenLen;
3555
 
        while IsSpaces and (Cnt > 0) do begin
3556
 
          if not (pTok^ in [' ',#9])
3557
 
          then IsSpaces := False;
3558
 
          Inc(pTok);
3559
 
          dec(Cnt);
3560
 
        end;
3561
 
      end;
3562
 
      Result := IsSpaces;
3563
 
    end;
3564
 
 
3565
 
  begin
3566
 
    {DebugLn('AddHighlightToken A TokenLen=',dbgs(TokenLen),
3567
 
      ' PhysicalStartPos=',dbgs(PhysicalStartPos),' PhysicalEndPos=',dbgs(PhysicalEndPos),
3568
 
      ' Tok="',copy(Token,1,TokenLen),'"');}
3569
 
 
3570
 
    // Do we have to paint the old chars first, or can we just append?
3571
 
    CanAppend := FALSE;
3572
 
    SpacesTest := FALSE;
3573
 
 
3574
 
    if (TokenAccu.Len > 0) then
3575
 
    begin
3576
 
      CanAppend :=
3577
 
        // Frame can be continued
3578
 
        (TokenAccu.FrameColor[sfdTop] = MarkupInfo.FrameSideColors[sfdTop]) and
3579
 
        (TokenAccu.FrameStyle[sfdTop] = MarkupInfo.FrameSideStyles[sfdTop]) and
3580
 
        (TokenAccu.FrameColor[sfdBottom] = MarkupInfo.FrameSideColors[sfdBottom]) and
3581
 
        (TokenAccu.FrameStyle[sfdBottom] = MarkupInfo.FrameSideStyles[sfdBottom]) and
3582
 
        (TokenAccu.FrameColor[sfdRight] = clNone) and
3583
 
        (MarkupInfo.FrameSideColors[sfdLeft] = clNone) and
3584
 
        // colors
3585
 
        (TokenAccu.BG = MarkupInfo.Background) and
3586
 
        // space-dependent
3587
 
        ( ( (TokenAccu.FG = MarkupInfo.Foreground) and
3588
 
            (TokenAccu.Style = MarkupInfo.Style)
3589
 
          ) or
3590
 
          // whitechar only token, can ignore Foreground color and certain styles (yet must match underline)
3591
 
          ( (TokenAccu.Style - [fsBold, fsItalic] = MarkupInfo.Style - [fsBold, fsItalic]) and
3592
 
            ( (TokenAccu.Style * [fsUnderline, fsStrikeOut] = []) or
3593
 
              (TokenAccu.FG = MarkupInfo.Foreground)
3594
 
            ) and
3595
 
            TokenIsSpaces
3596
 
          )
3597
 
        );
3598
 
      // If we can't append it, then we have to paint the old token chars first.
3599
 
      if not CanAppend then
3600
 
        PaintHighlightToken(FALSE);
3601
 
    end;
3602
 
 
3603
 
    // Don't use AppendStr because it's more expensive.
3604
 
    //if (CurLine=TopLine) then debugln('      -t-Accu len ',dbgs(TokenAccu.Len),' pstart ',dbgs(TokenAccu.PhysicalStartPos),' p-end ',dbgs(TokenAccu.PhysicalEndPos));
3605
 
    if CanAppend then begin
3606
 
      if (TokenAccu.Len + TokenLen > TokenAccu.MaxLen) then begin
3607
 
        TokenAccu.MaxLen := TokenAccu.Len + TokenLen + 32;
3608
 
        SetTokenAccuLength;
3609
 
      end;
3610
 
      // use move() ???
3611
 
      for i := 0 to TokenLen-1 do begin
3612
 
        TokenAccu.p[TokenAccu.Len + i] := Token[i];
3613
 
      end;
3614
 
      Inc(TokenAccu.Len, TokenLen);
3615
 
      TokenAccu.PhysicalEndPos := PhysicalEndPos;
3616
 
      TokenAccu.FrameColor[sfdRight] := MarkupInfo.FrameSideColors[sfdRight];
3617
 
      TokenAccu.FrameStyle[sfdRight] := MarkupInfo.FrameSideStyles[sfdRight];
3618
 
    end else begin
3619
 
      TokenAccu.Len := TokenLen;
3620
 
      if (TokenAccu.Len > TokenAccu.MaxLen) then begin
3621
 
        TokenAccu.MaxLen := TokenAccu.Len + 32;
3622
 
        SetTokenAccuLength;
3623
 
      end;
3624
 
      for i := 0 to TokenLen-1 do begin
3625
 
        TokenAccu.p[i] := Token[i];
3626
 
      end;
3627
 
      TokenAccu.PhysicalStartPos := PhysicalStartPos;
3628
 
      TokenAccu.PhysicalEndPos := PhysicalEndPos;
3629
 
      TokenAccu.FG := MarkupInfo.Foreground;
3630
 
      TokenAccu.BG := MarkupInfo.Background;
3631
 
      TokenAccu.Style := MarkupInfo.Style;
3632
 
      for s := low(TSynFrameSide) to high(TSynFrameSide) do begin
3633
 
        TokenAccu.FrameColor[s] := MarkupInfo.FrameSideColors[s];
3634
 
        TokenAccu.FrameStyle[s] := MarkupInfo.FrameSideStyles[s];
3635
 
      end;
3636
 
    end;
3637
 
    {debugln('AddHighlightToken END CanAppend=',dbgs(CanAppend),
3638
 
      ' Len=',dbgs(TokenAccu.Len),
3639
 
      ' PhysicalStartPos=',dbgs(TokenAccu.PhysicalStartPos),
3640
 
      ' PhysicalEndPos=',dbgs(TokenAccu.PhysicalEndPos),
3641
 
      ' "',copy(TokenAccu.s,1,TokenAccu.Len),'"');}
3642
 
  end;
3643
 
 
3644
 
  procedure DrawHiLightMarkupToken(attr: TSynHighlighterAttributes;
3645
 
    sToken: PChar; nTokenByteLen: integer);
3646
 
  var
3647
 
    DefaultFGCol, DefaultBGCol: TColor;
3648
 
    PhysicalStartPos: integer;
3649
 
    PhysicalEndPos: integer;
3650
 
    len: Integer;
3651
 
    SubTokenByteLen, SubCharLen, TokenCharLen : Integer;
3652
 
    NextPhysPos : Integer;
3653
 
 
3654
 
    function CharToByteLen(aCharLen: Integer) : Integer;
3655
 
    begin
3656
 
      if not UseUTF8 then exit(aCharLen);
3657
 
      Result := UTF8CharToByteIndex(sToken, nTokenByteLen, aCharLen);
3658
 
      if Result < 0 then begin
3659
 
        debugln('ERROR: Could not convert CharLen (',dbgs(aCharLen),') to byteLen (maybe invalid UTF8?)',' len ',dbgs(nTokenByteLen),' Line ',dbgs(CurLine),' PhysPos ',dbgs(CurPhysPos));
3660
 
        Result := aCharLen;
3661
 
      end;
3662
 
    end;
3663
 
 
3664
 
    procedure InitTokenColors;
3665
 
    begin
3666
 
      FPaintLineColor.Clear;
3667
 
      if Assigned(attr) then
3668
 
      begin
3669
 
        DefaultFGCol := attr.Foreground;
3670
 
        DefaultBGCol := attr.Background;
3671
 
        if DefaultBGCol = clNone then DefaultBGCol := colEditorBG;
3672
 
        if DefaultFGCol = clNone then DefaultFGCol := Font.Color;
3673
 
 
3674
 
        FPaintLineColor.FrameColor := attr.FrameColor;
3675
 
        FPaintLineColor.FrameStyle := attr.FrameStyle;
3676
 
        FPaintLineColor.FrameEdges := attr.FrameEdges;
3677
 
        FPaintLineColor.Style      := attr.Style;
3678
 
        // TSynSelectedColor.Style and StyleMask describe how to modify a style,
3679
 
        // but FPaintLineColor contains an actual style
3680
 
        FPaintLineColor.MergeFinalStyle := True;
3681
 
        FPaintLineColor.StyleMask  := [];
3682
 
        if FPaintLineColor.Background = clNone then
3683
 
          FPaintLineColor.Background := colEditorBG;
3684
 
        if FPaintLineColor.Foreground = clNone then
3685
 
          FPaintLineColor.Foreground := Font.Color;
3686
 
        if attr.FrameColor <> clNone then begin
3687
 
          FPaintLineColor.StartX := PhysicalStartPos;
3688
 
          FPaintLineColor.EndX   := PhysicalStartPos + TokenCharLen - 1;
3689
 
          FPaintLineColor.MergeFrames(nil, PhysicalStartPos, PhysicalStartPos + TokenCharLen - 1);
3690
 
        end;
3691
 
      end else
3692
 
      begin
3693
 
        DefaultFGCol := Font.Color;
3694
 
        DefaultBGCol := colEditorBG;
3695
 
        FPaintLineColor.Style := Font.Style;
3696
 
      end;
3697
 
 
3698
 
      FPaintLineColor.Foreground := DefaultFGCol;
3699
 
      FPaintLineColor.Background := DefaultBGCol;
3700
 
    end;
3701
 
 
3702
 
  begin
3703
 
    if CurPhysPos > LastCol then exit;
3704
 
 
3705
 
    PhysicalStartPos := CurPhysPos;
3706
 
    len := nTokenByteLen;
3707
 
    TokenCharLen := ExpandSpecialChars(sToken, nTokenByteLen, PhysicalStartPos);
3708
 
    CurLogIndex := CurLogIndex + len;
3709
 
    // Prepare position for next token
3710
 
    inc(CurPhysPos, TokenCharLen);
3711
 
    if CurPhysPos <= FirstCol then exit;
3712
 
 
3713
 
    // Remove any Part of the Token that is before FirstCol
3714
 
    if PhysicalStartPos < FirstCol then begin
3715
 
      SubCharLen := FirstCol - PhysicalStartPos;
3716
 
      len := CharToByteLen(SubCharLen);
3717
 
      dec(TokenCharLen, SubCharLen);
3718
 
      inc(PhysicalStartPos, SubCharLen);
3719
 
      dec(nTokenByteLen, len);
3720
 
      inc(sToken, len);
3721
 
    end;
3722
 
 
3723
 
    // Remove any Part of the Token that is after LastCol
3724
 
    SubCharLen := PhysicalStartPos + TokenCharLen - (LastCol + 1);
3725
 
    if SubCharLen > 0 then begin
3726
 
      dec(TokenCharLen, SubCharLen);
3727
 
      nTokenByteLen := CharToByteLen(TokenCharLen);
3728
 
    end;
3729
 
 
3730
 
    InitTokenColors;
3731
 
 
3732
 
    // Draw the token
3733
 
    {TODO: cache NextPhysPos, and MarkupInfo between 2 calls }
3734
 
    while (nTokenByteLen > 0) do begin
3735
 
      FPaintLineColor2.Assign(FPaintLineColor);
3736
 
 
3737
 
      // Calculate Token Sublen for current Markup
3738
 
      NextPhysPos := fMarkupManager.GetNextMarkupColAfterRowCol
3739
 
                       (FFoldedLinesView.TextIndex[CurLine]+1, PhysicalStartPos);
3740
 
      if NextPhysPos < 1
3741
 
      then SubCharLen := TokenCharLen
3742
 
      else SubCharLen := NextPhysPos - PhysicalStartPos;
3743
 
 
3744
 
      if SubCharLen > TokenCharLen then SubCharLen := TokenCharLen;
3745
 
      if SubCharLen < 1 then begin // safety for broken input...
3746
 
        debugln('ERROR: Got invalid SubCharLen ',dbgs(SubCharLen),' len ',dbgs(nTokenByteLen),' Line ',dbgs(CurLine),' PhysPos ',dbgs(CurPhysPos));
3747
 
        SubCharLen:=1;
3748
 
      end;
3749
 
 
3750
 
      SubTokenByteLen := CharToByteLen(SubCharLen);
3751
 
      PhysicalEndPos:= PhysicalStartPos + SubCharLen - 1;
3752
 
 
3753
 
      // Calculate Markup
3754
 
      fMarkupManager.MergeMarkupAttributeAtRowCol(FFoldedLinesView.TextIndex[CurLine]+1,
3755
 
        PhysicalStartPos, PhysicalEndPos, FPaintLineColor2);
3756
 
 
3757
 
      // Deal with equal colors
3758
 
      if (FPaintLineColor2.Background = FPaintLineColor2.Foreground) then begin // or if diff(gb,fg) < x
3759
 
        if FPaintLineColor2.Background = DefaultBGCol then
3760
 
          FPaintLineColor2.Foreground := not(FPaintLineColor2.Background) and $00ffffff // or maybe Font.color ?
3761
 
        else
3762
 
          FPaintLineColor2.Foreground := DefaultBGCol;
3763
 
      end;
3764
 
 
3765
 
      // Add to TokenAccu
3766
 
      AddHighlightToken(sToken, SubTokenByteLen,
3767
 
        PhysicalStartPos, PhysicalEndPos, FPaintLineColor2);
3768
 
 
3769
 
      PhysicalStartPos:=PhysicalEndPos + 1;
3770
 
      dec(nTokenByteLen,SubTokenByteLen);
3771
 
      dec(TokenCharLen, SubCharLen);
3772
 
      inc(sToken, SubTokenByteLen);
3773
 
    end;
3774
 
  end;
3775
 
 
3776
 
  {$IFDEF SYNDEBUGPRINT}
3777
 
  procedure DebugPrint(Txt: String; MinCol: Integer = 0);
3778
 
  begin
3779
 
    if CurPhysPos < MinCol then Txt := StringOfChar(' ', MinCol - CurPhysPos) + txt;
3780
 
    Setlength(CharWidths, length(CharWidths) + length(Txt));
3781
 
    FillChar(CharWidths[length(CharWidths)-length(Txt)], length(Txt), #1);
3782
 
    DrawHiLightMarkupToken(nil, PChar(Pointer(Txt)), Length(Txt));
3783
 
  end;
3784
 
  {$ENDIF}
3785
 
 
3786
 
  procedure PaintLines;
3787
 
  var
3788
 
    sLine: string; // the current line
3789
 
    sToken: PChar; // highlighter token info
3790
 
    nTokenLen: integer; // Pos in Char // Len in Byte ??
3791
 
    attr: TSynHighlighterAttributes;
3792
 
    ypos: Integer;
3793
 
    DividerInfo: TSynDividerDrawConfigSetting;
3794
 
    cl: Integer;
3795
 
  begin
3796
 
    // Initialize rcLine for drawing. Note that Top and Bottom are updated
3797
 
    // inside the loop. Get only the starting point for this.
3798
 
    rcLine := AClip;
3799
 
    rcLine.Bottom := FirstLine * fTextHeight;
3800
 
    // Make sure the token accumulator string doesn't get reassigned to often.
3801
 
    if Assigned(fHighlighter) then begin
3802
 
      TokenAccu.MaxLen := Max(128, fCharsInWindow * 4);
3803
 
      SetTokenAccuLength;
3804
 
    end;
3805
 
 
3806
 
    // Now loop through all the lines. The indices are valid for Lines.
3807
 
    CurLine := FirstLine-1;
3808
 
    while CurLine<LastLine do begin
3809
 
      inc(CurLine);
3810
 
      CurTextIndex := FFoldedLinesView.TextIndex[CurLine];
3811
 
      //CharWidths := FFoldedLinesView.GetPhysicalCharWidths(CurLine);
3812
 
      CharWidths := FTheLinesView.GetPhysicalCharWidths(CurTextIndex);
3813
 
 
3814
 
      fMarkupManager.PrepareMarkupForRow(CurTextIndex+1);
3815
 
      // Get the line.
3816
 
      // Update the rcLine rect to this line.
3817
 
      rcLine.Top := rcLine.Bottom;
3818
 
      Inc(rcLine.Bottom, fTextHeight);
3819
 
      // Paint the lines depending on the assigned highlighter.
3820
 
      rcToken := rcLine;
3821
 
      TokenAccu.Len := 0;
3822
 
      TokenAccu.PhysicalEndPos := FirstCol - 1; // in case of an empty line
3823
 
      CurPhysPos := 1;
3824
 
      CurLogIndex := 0;
3825
 
      // Delete the whole Line
3826
 
      fTextDrawer.BackColor := colEditorBG;
3827
 
      SetBkColor(dc, ColorToRGB(colEditorBG));
3828
 
      rcLine.Left := EraseLeft;
3829
 
      InternalFillRect(dc, rcLine);
3830
 
      rcLine.Left := DrawLeft;
3831
 
      ForceEto := False;
3832
 
 
3833
 
      if not Assigned(fHighlighter) then begin
3834
 
        sLine := FFoldedLinesView[CurLine];
3835
 
        DrawHiLightMarkupToken(nil, PChar(Pointer(sLine)), Length(sLine));
3836
 
      end else begin
3837
 
        // draw splitter line
3838
 
        DividerInfo := fHighlighter.DrawDivider[CurTextIndex];
3839
 
        if (DividerInfo.Color <> clNone) and (nRightEdge > TextLeftPixelOffset(False) - 1) then
3840
 
        begin
3841
 
          ypos := rcToken.Bottom - 1;
3842
 
          cl := DividerInfo.Color;
3843
 
          if cl = clDefault then
3844
 
            cl := fRightEdgeColor;
3845
 
          fTextDrawer.DrawLine(nRightEdge, ypos, TextLeftPixelOffset(False) - 1, ypos, cl);
3846
 
          dec(rcToken.Bottom);
3847
 
        end;
3848
 
        // Initialize highlighter with line text and range info. It is
3849
 
        // necessary because we probably did not scan to the end of the last
3850
 
        // line - the internal highlighter range might be wrong.
3851
 
        fHighlighter.StartAtLineIndex(CurTextIndex);
3852
 
        // Try to concatenate as many tokens as possible to minimize the count
3853
 
        // of ExtTextOut calls necessary. This depends on the selection state
3854
 
        // or the line having special colors. For spaces the foreground color
3855
 
        // is ignored as well.
3856
 
        //debugln('>>>> PaintLines Line=',dbgs(CurLine),' rect=',dbgs(rcToken));
3857
 
        while not fHighlighter.GetEol do begin
3858
 
          fHighlighter.GetTokenEx(sToken,nTokenLen);
3859
 
          attr := fHighlighter.GetTokenAttribute;
3860
 
          // Add Markup to the token and append it to the TokenAccu
3861
 
          // record. This will paint any chars already stored if there is
3862
 
          // a (visible) change in the attributes.
3863
 
          DrawHiLightMarkupToken(attr,sToken,nTokenLen);
3864
 
          // Let the highlighter scan the next token.
3865
 
          fHighlighter.Next;
3866
 
        end;
3867
 
      end;
3868
 
      // Draw anything that's left in the TokenAccu record. Fill to the end
3869
 
      // of the invalid area with the correct colors.
3870
 
      PaintHighlightToken(TRUE);
3871
 
 
3872
 
      fMarkupManager.FinishMarkupForRow(CurTextIndex+1);
3873
 
    end;
3874
 
    CurLine:=-1;
3875
 
  end;
3876
 
 
3877
 
{ end local procedures }
3878
 
 
3879
 
begin
3880
 
  if (AClip.Right < TextLeftPixelOffset(False)) then exit;
3881
 
  if (AClip.Left > ClientWidth - TextRightPixelOffset) then exit;
3882
 
 
3883
 
  //DebugLn(['TCustomSynEdit.PaintTextLines ',dbgs(AClip)]);
3884
 
  CurLine:=-1;
3885
 
  FillChar(TokenAccu,SizeOf(TokenAccu),0);
3886
 
  //DebugLn('TCustomSynEdit.PaintTextLines ',DbgSName(Self),' TopLine=',dbgs(TopLine),' AClip=',dbgs(AClip));
3887
 
  colEditorBG := Color;
3888
 
  if Assigned(fHighlighter) then
3889
 
    fHighlighter.CurrentLines := FTheLinesView;
3890
 
  // If the right edge is visible and in the invalid area, prepare to paint it.
3891
 
  // Do this first to realize the pen when getting the dc variable.
3892
 
  bDoRightEdge := FALSE;
3893
 
  if (fRightEdge > 0) then begin // column value
3894
 
    nRightEdge := fTextOffset + fRightEdge * fCharWidth; // pixel value
3895
 
    if (nRightEdge >= AClip.Left) and (nRightEdge <= AClip.Right) then
3896
 
      bDoRightEdge := TRUE;
3897
 
    if nRightEdge > AClip.Right then
3898
 
      nRightEdge := AClip.Right; // for divider draw lines (don't draw into right gutter)
3899
 
  end
3900
 
  else
3901
 
    nRightEdge := AClip.Right;
3902
 
 
3903
 
  Canvas.Pen.Color := fRightEdgeColor; // used for code folding too
3904
 
  Canvas.Pen.Width := 1;
3905
 
  // Do everything else with API calls. This (maybe) realizes the new pen color.
3906
 
  dc := Canvas.Handle;
3907
 
  SetBkMode(dc, TRANSPARENT);
3908
 
 
3909
 
  // Adjust the invalid area to not include the gutter (nor the 2 ixel offset to the guttter).
3910
 
  EraseLeft := AClip.Left;
3911
 
  if (AClip.Left < TextLeftPixelOffset) then
3912
 
    AClip.Left := TextLeftPixelOffset;
3913
 
  DrawLeft := AClip.Left;
3914
 
 
3915
 
  if (LastLine >= FirstLine) then begin
3916
 
    // Paint the visible text lines. To make this easier, compute first the
3917
 
    // necessary information about the selected area: is there any visible
3918
 
    // selected area, and what are its lines / columns?
3919
 
    // Moved to two local procedures to make it easier to read.
3920
 
    fTextDrawer.Style := Font.Style;
3921
 
    fTextDrawer.BeginDrawing(dc);
3922
 
    try
3923
 
      PaintLines;
3924
 
    finally
3925
 
      fTextDrawer.EndDrawing;
3926
 
    end;
3927
 
  end;
3928
 
 
3929
 
  AClip.Top := (LastLine+1) * fTextHeight;
3930
 
  if (AClip.Top < AClip.Bottom) then begin
3931
 
    // Delete the remaining area
3932
 
    SetBkColor(dc, ColorToRGB(colEditorBG));
3933
 
    AClip.Left := EraseLeft;
3934
 
    InternalFillRect(dc, AClip);
3935
 
    AClip.Left := DrawLeft;
3936
 
 
3937
 
    // Draw the right edge if necessary.
3938
 
    if bDoRightEdge and (not (eoHideRightMargin in Options)) then begin
3939
 
      LCLIntf.MoveToEx(dc, nRightEdge, AClip.Top, nil);
3940
 
      LCLIntf.LineTo(dc, nRightEdge, AClip.Bottom + 1);
3941
 
    end;
3942
 
  end;
3943
 
 
3944
 
  fMarkupManager.EndMarkup;
3945
 
  ReAllocMem(TokenAccu.p,0);
3946
 
end;
3947
 
 
3948
3551
procedure TCustomSynEdit.StartPaintBuffer(const ClipRect: TRect);
3949
3552
{$IFDEF EnableDoubleBuf}
3950
3553
var
3952
3555
  NewBufferHeight: Integer;
3953
3556
{$ENDIF}
3954
3557
begin
 
3558
  {$IFDEF EnableDoubleBuf}
3955
3559
  if (SavedCanvas<>nil) then RaiseGDBException('');
3956
 
  {$IFDEF EnableDoubleBuf}
3957
3560
  if BufferBitmap=nil then
3958
3561
    BufferBitmap:=TBitmap.Create;
3959
3562
  NewBufferWidth:=BufferBitmap.Width;
3980
3583
  {$ENDIF}
3981
3584
end;
3982
3585
 
3983
 
function TCustomSynEdit.NextWordLogicalPos(WordEndForDelete: Boolean): TPoint;
 
3586
function TCustomSynEdit.NextWordLogicalPos(ABoundary: TLazSynWordBoundary;
 
3587
  WordEndForDelete: Boolean): TPoint;
3984
3588
var
3985
 
  CX, CY, LineLen: integer;
3986
 
  Line: string;
3987
 
  LogCaret: TPoint;
3988
 
  DelSpaces : Boolean;
 
3589
  i, j, CX, CY, NX, OX, LineLen: integer;
 
3590
  Line, ULine: string;
 
3591
  CWidth: TPhysicalCharWidths;
 
3592
  r, InclCurrent: Boolean;
3989
3593
begin
3990
 
  LogCaret:=LogicalCaretXY;
3991
 
  CX := LogCaret.X;
3992
 
  CY := LogCaret.Y;
3993
 
  // valid line?
3994
 
  if (CY >= 1) and (CY <= FTheLinesView.Count) then begin
3995
 
    Line := FTheLinesView[CY - 1];
 
3594
  Result := LogicalCaretXY;
 
3595
  CX := Result.X;
 
3596
  CY := Result.Y;
 
3597
 
 
3598
  if (CY < 1) then begin
 
3599
    Result.X := 1;
 
3600
    Result.Y := 1;
 
3601
    exit;
 
3602
  end;
 
3603
  i := FTheLinesView.Count;
 
3604
  if (CY > i) or ((CY = i) and (CX > length(FTheLinesView[i-1]))) then begin
 
3605
    Result.Y := i;
 
3606
    Result.X := length(FTheLinesView[Result.Y-1]) + 1;
 
3607
    exit;
 
3608
  end;
 
3609
 
 
3610
  Line := FTheLinesView[CY - 1];
 
3611
  InclCurrent := False;
 
3612
  LineLen := Length(Line);
 
3613
  if CX > LineLen then begin
 
3614
    Line := FTheLinesView[CY];
3996
3615
    LineLen := Length(Line);
3997
 
 
3998
 
    if CX >= LineLen then begin
3999
 
      // find first IdentChar in the next line
4000
 
      if CY < FTheLinesView.Count then begin
4001
 
        Line := FTheLinesView[CY];
4002
 
        Inc(CY);
4003
 
        if WordEndForDelete then
4004
 
          CX := Max(1, StrScanForCharInSet(Line, 1, [#1..#255] - TSynWhiteChars))
4005
 
        else
4006
 
          CX := Max(1, WordBreaker.NextWordStart(Line, 1, True));
4007
 
      end;
4008
 
    end else begin
4009
 
      if WordEndForDelete then begin
4010
 
        DelSpaces := WordBreaker.IsAtWordStart(Line, CX) or not WordBreaker.IsInWord(Line, CX);
4011
 
        CX := WordBreaker.NextBoundary(Line, CX);
4012
 
        if DelSpaces and(cx > 0) then
4013
 
          CX := StrScanForCharInSet(Line, CX, [#1..#255] - TSynWhiteChars);
4014
 
      end
4015
 
      else
4016
 
        CX := WordBreaker.NextWordStart(Line, CX);
4017
 
      // if one of those failed just position at the end of the line
4018
 
      if CX <= 0 then
4019
 
        CX := LineLen + 1;
4020
 
    end;
4021
 
  end;
 
3616
    Inc(CY);
 
3617
    CX := 1;
 
3618
    InclCurrent := True;
 
3619
  end;
 
3620
 
 
3621
  case ABoundary of
 
3622
    swbWordBegin: begin
 
3623
        CX := WordBreaker.NextWordStart(Line,  CX, InclCurrent);
 
3624
        if (CX <= 0) and not InclCurrent then CX := LineLen + 1;
 
3625
        if (CX <= 0) and InclCurrent then CX := 1;
 
3626
      end;
 
3627
    swbWordEnd: begin
 
3628
        CX := WordBreaker.NextWordEnd(Line,  CX);
 
3629
        if (CX <= 0) then CX := LineLen + 1;
 
3630
      end;
 
3631
    swbTokenBegin: begin
 
3632
        if not (   InclCurrent and
 
3633
                   ((CX <= 1) or (Line[CX-1] in FWordBreaker.WhiteChars)) and
 
3634
                   ((CX > LineLen) or not(Line[CX] in FWordBreaker.WhiteChars))   )
 
3635
        then
 
3636
          CX := WordBreaker.NextBoundary(Line,  CX);
 
3637
        if (CX > 0) and (CX <= LineLen) and (Line[CX] in FWordBreaker.WhiteChars) then
 
3638
          CX := WordBreaker.NextBoundary(Line,  CX);
 
3639
        if (CX <= 0) then CX := LineLen + 1;
 
3640
      end;
 
3641
    swbTokenEnd: begin
 
3642
        CX := WordBreaker.NextBoundary(Line,  CX);
 
3643
        if (CX > 1) and (Line[CX-1] in FWordBreaker.WhiteChars) then
 
3644
          CX := WordBreaker.NextBoundary(Line,  CX);
 
3645
        if (CX <= 0) then CX := LineLen + 1;
 
3646
      end;
 
3647
    swbCaseChange: begin
 
3648
        NX := WordBreaker.NextWordStart(Line,  CX, InclCurrent);
 
3649
        if (NX <= 0) and not InclCurrent then NX := LineLen + 1;
 
3650
        if (NX <= 0) and InclCurrent then NX := 1;
 
3651
 
 
3652
        ULine := LazUTF8.UTF8UpperCase(Line);
 
3653
        CWidth := FTheLinesView.GetPhysicalCharWidths(CY - 1); // for utf 8
 
3654
        OX := CX;
 
3655
        i := Length(ULine);
 
3656
        // skip upper
 
3657
        While (CX < NX) and (CX <= i) do begin          // check entire next utf-8 char to be equal
 
3658
          r := (CX = OX) or (CX <= 1) or (Line[CX-1] <> '_') or ((CX <= i) and (Line[CX] = '_'));
 
3659
          j := CX;
 
3660
          repeat
 
3661
            r := r and (Line[j] = ULine[j]);
 
3662
            inc(j);
 
3663
          until (j > i) or (CWidth[j-1] <> 0);
 
3664
          if not r then break;
 
3665
          CX := j;
 
3666
        end;
 
3667
        // skip lowercase
 
3668
        ULine := LazUTF8.UTF8LowerCase(Line);
 
3669
        While (CX < NX) and (CX <= i) do begin          // check entire next utf-8 char to be equal
 
3670
          r := (CX = OX) or (CX <= 1) or (Line[CX-1] <> '_') or ((CX <= i) and (Line[CX] = '_'));
 
3671
          j := CX;
 
3672
          repeat
 
3673
            r := r and (Line[j] = ULine[j]);
 
3674
            inc(j);
 
3675
          until (j > i) or (CWidth[j-1] <> 0);
 
3676
          if not r then break;
 
3677
          CX := j;
 
3678
        end;
 
3679
      end;
 
3680
  end;
 
3681
 
4022
3682
  Result := Point(CX, CY);
4023
3683
end;
4024
3684
 
4025
 
function TCustomSynEdit.PrevWordLogicalPos: TPoint;
4026
 
var
4027
 
  CX, CY: integer;
4028
 
  Line: string;
4029
 
  LogCaret: TPoint;
4030
 
begin
4031
 
  LogCaret:=LogicalCaretXY;
4032
 
  CX := LogCaret.X;
4033
 
  CY := LogCaret.Y;
4034
 
  // valid line?
4035
 
  if (CY >= 1) and (CY <= FTheLinesView.Count) then begin
4036
 
    Line := FTheLinesView[CY - 1];
4037
 
    CX := WordBreaker.PrevWordStart(Line,  Min(CX, Length(Line) + 1));
 
3685
function TCustomSynEdit.PrevWordLogicalPos(ABoundary: TLazSynWordBoundary): TPoint;
 
3686
 
 
3687
  procedure CheckLineStart(var CX, CY: integer);
 
3688
  var
 
3689
    Line: String;
 
3690
  begin
4038
3691
    if CX <= 0 then
4039
3692
      if CY > 1 then begin
4040
3693
        // just position at the end of the previous line
 
3694
        // Todo skip spaces
4041
3695
        Dec(CY);
4042
3696
        Line := FTheLinesView[CY - 1];
4043
3697
        CX := Length(Line) + 1;
4045
3699
      else
4046
3700
        CX := 1;
4047
3701
  end;
 
3702
 
 
3703
var
 
3704
  i, j, CX, CY, NX, OX: integer;
 
3705
  Line, ULine: string;
 
3706
  CWidth: TPhysicalCharWidths;
 
3707
  r: Boolean;
 
3708
begin
 
3709
  Result := LogicalCaretXY;
 
3710
  CX := Result.X;
 
3711
  CY := Result.Y;
 
3712
 
 
3713
  if (CY < 1) then begin
 
3714
    Result.X := 1;
 
3715
    Result.Y := 1;
 
3716
    exit;
 
3717
  end;
 
3718
  if (CY > FTheLinesView.Count) then begin
 
3719
    Result.Y := FTheLinesView.Count;
 
3720
    Result.X := length(FTheLinesView[Result.Y-1]) + 1;
 
3721
    exit;
 
3722
  end;
 
3723
 
 
3724
  Line := FTheLinesView[CY - 1];
 
3725
 
 
3726
  case ABoundary of
 
3727
    swbWordBegin: begin
 
3728
        CX := WordBreaker.PrevWordStart(Line,  Min(CX, Length(Line) + 1));
 
3729
        CheckLineStart(CX, CY);
 
3730
      end;
 
3731
    swbWordEnd: begin
 
3732
        CX := WordBreaker.PrevWordEnd(Line,  Min(CX, Length(Line) + 1));
 
3733
        CheckLineStart(CX, CY);
 
3734
      end;
 
3735
    swbTokenBegin: begin
 
3736
        CX := WordBreaker.PrevBoundary(Line,  Min(CX, Length(Line) + 1));
 
3737
        if (CX > 0) and (Line[CX] in FWordBreaker.WhiteChars) then
 
3738
          CX := WordBreaker.PrevBoundary(Line,  Min(CX, Length(Line) + 1));
 
3739
        if CX = 1 then CX := -1;
 
3740
        CheckLineStart(CX, CY);
 
3741
      end;
 
3742
    swbTokenEnd: begin
 
3743
        CX := WordBreaker.PrevBoundary(Line,  Min(CX, Length(Line) + 1));
 
3744
        if (CX > 1) and (Line[CX-1] in FWordBreaker.WhiteChars) then
 
3745
          CX := WordBreaker.PrevBoundary(Line,  Min(CX, Length(Line) + 1));
 
3746
        if CX = 1 then CX := -1;
 
3747
        CheckLineStart(CX, CY);
 
3748
      end;
 
3749
    swbCaseChange: begin
 
3750
        NX := WordBreaker.PrevWordStart(Line,  Min(CX, Length(Line) + 1));
 
3751
 
 
3752
        ULine := LazUTF8.UTF8LowerCase(Line);
 
3753
        CWidth := FTheLinesView.GetPhysicalCharWidths(CY - 1); // for utf 8
 
3754
        OX := CX;
 
3755
        i := Length(ULine);
 
3756
        if CX > i + 1 then CX := i + 1;
 
3757
        // skip lowercase
 
3758
        While (CX > NX) and (CX - 1 > 0) do begin          // check entire previous utf-8 char to be equal
 
3759
          r := (CX = OX) or (Line[CX - 1] <> '_') or ((CX <= i) and (Line[CX] = '_'));
 
3760
          j := CX;
 
3761
          repeat
 
3762
            dec(j);
 
3763
            r := r and (Line[j] = ULine[j]);
 
3764
          until (j < 1) or (CWidth[j-1] <> 0);
 
3765
          if not r then break;
 
3766
          CX := j;
 
3767
        end;
 
3768
        // skip upper
 
3769
        While (CX > NX) and (CX - 1 > 0) do begin          // check entire previous utf-8 char to be not equal
 
3770
          j := CX;
 
3771
          r := true;
 
3772
          repeat
 
3773
            dec(j);
 
3774
            r := r and (Line[j] = ULine[j]);
 
3775
          until (j < 1) or (CWidth[j-1] <> 0);
 
3776
          r := r or not( (CX = OX) or (Line[CX - 1] <> '_') or ((CX <= i) and (Line[CX] = '_')) );
 
3777
          if r then break;
 
3778
          CX := j;
 
3779
        end;
 
3780
        if (CX - 1 < 1) then
 
3781
          CX := NX;
 
3782
        CheckLineStart(CX, CY);
 
3783
      end;
 
3784
  end;
 
3785
 
4048
3786
  Result := Point(CX, CY);
4049
3787
end;
4050
3788
 
4053
3791
  // we are painting everything ourselves, so not need to erase background
4054
3792
end;
4055
3793
 
4056
 
procedure TCustomSynEdit.Update;
4057
 
begin
4058
 
  {$IFDEF SYN_LAZARUS}
4059
 
  Invalidate;
4060
 
  {$ELSE}
4061
 
  Paint;
4062
 
  inherited Update;
4063
 
  {$ENDIF}
4064
 
end;
4065
 
 
4066
3794
procedure TCustomSynEdit.Invalidate;
4067
3795
begin
4068
3796
  {$IFDEF VerboseSynEditInvalidate}
4174
3902
  FindMatchingBracket(CaretXY,true,true,true,false);
4175
3903
end;
4176
3904
 
4177
 
procedure TCustomSynEdit.SetSelWord;
4178
 
begin
4179
 
  SelectWord;
4180
 
end;
4181
 
 
4182
3905
procedure TCustomSynEdit.SelectWord;
4183
3906
begin
4184
3907
  SetWordBlock(LogicalCaretXY);
4197
3920
procedure TCustomSynEdit.DoBlockSelectionChanged(Sender : TObject);
4198
3921
begin
4199
3922
  StatusChanged([scSelection]);
 
3923
  if HandleAllocated and Focused then
 
3924
    SelAvailChange(nil);
4200
3925
end;
4201
3926
 
4202
3927
procedure TCustomSynEdit.SetBlockBegin(Value: TPoint); // logical position (byte)
4242
3967
 
4243
3968
procedure TCustomSynEdit.SetCaretX(const Value: Integer);
4244
3969
begin
 
3970
  FCaret.ChangeOnTouch; // setting the caret always clears selection (even setting to current pos / no change)
4245
3971
  FCaret.CharPos := Value;
4246
3972
end;
4247
3973
 
4248
3974
procedure TCustomSynEdit.SetCaretY(const Value: Integer);
4249
3975
begin
 
3976
  FCaret.ChangeOnTouch; // setting the caret always clears selection (even setting to current pos / no change)
4250
3977
  FCaret.LinePos := Value;
4251
3978
end;
4252
3979
 
4268
3995
procedure TCustomSynEdit.SetCaretXY(Value: TPoint);
4269
3996
// physical position (screen)
4270
3997
begin
4271
 
  FCaret.ChangeOnTouch;
 
3998
  FCaret.ChangeOnTouch; // setting the caret always clears selection (even setting to current pos / no change)
4272
3999
  FCaret.LineCharPos:= Value;
4273
4000
end;
4274
4001
 
4294
4021
  Result := FTheLinesView.LengthOfLongestLine;
4295
4022
  if (eoScrollPastEol in Options) and (Result < fMaxLeftChar) then
4296
4023
    Result := fMaxLeftChar;
4297
 
  Result := Result - fCharsInWindow + 1 + FScreenCaret.ExtraLineChars;
 
4024
  Result := Result - CharsInWindow + 1 + FScreenCaret.ExtraLineChars;
4298
4025
end;
4299
4026
 
4300
4027
function TCustomSynEdit.CurrentMaxLineLen: Integer;
4310
4037
begin
4311
4038
  Value := Min(Value, CurrentMaxLeftChar);
4312
4039
  Value := Max(Value, 1);
4313
 
  if Value <> fLeftChar then begin
4314
 
    fLeftChar := Value;
4315
 
    fTextOffset := TextLeftPixelOffset - (LeftChar - 1) * fCharWidth;
 
4040
  if Value <> FTextArea.LeftChar then begin
 
4041
    FTextArea.LeftChar := Value;
4316
4042
    UpdateScrollBars;
4317
4043
    InvalidateLines(-1, -1);
4318
4044
    StatusChanged([scLeftChar]);
4414
4140
  FLines.Text := Value; // Do not trim
4415
4141
end;
4416
4142
 
4417
 
function TCustomSynEdit.CurrentMaxTopLine: Integer;
 
4143
function TCustomSynEdit.CurrentMaxTopView: Integer;
4418
4144
begin
4419
 
  if (eoScrollPastEof in Options) then
4420
 
    Result := FTheLinesView.Count
4421
 
  else
4422
 
    Result := FFoldedLinesView.TextPosAddLines(FTheLinesView.Count+1, -fLinesInWindow);
 
4145
  Result := FFoldedLinesView.Count;
 
4146
  if not(eoScrollPastEof in Options) then
 
4147
    Result := Result + 1 - Max(0, LinesInWindow);
4423
4148
  Result := Max(Result, 1);
4424
4149
end;
4425
4150
 
4426
4151
procedure TCustomSynEdit.SetTopLine(Value: Integer);
 
4152
var
 
4153
  NewTopView: Integer;
4427
4154
begin
4428
 
  // don't use MinMax here, it will fail in design mode (Lines.Count is zero,
4429
 
  // but the painting code relies on TopLine >= 1)
4430
 
  {$IFDEF SYNSCROLLDEBUG}
4431
 
  if fPaintLock = 0 then debugln(['SetTopline outside Paintlock']);
4432
 
  if (sfHasScrolled in fStateFlags) then debugln(['SetTopline with sfHasScrolled Value=',Value, '  FOldTopLine=',FOldTopLine,'  FOldTopView=',FOldTopView ]);
4433
 
  {$ENDIF}
4434
 
  Value := Min(Value, CurrentMaxTopLine);
4435
 
  Value := Max(Value, 1);
 
4155
  // TODO : Above hidden line only if folded, if hidden then use below
4436
4156
  if FFoldedLinesView.FoldedAtTextIndex[Value-1] then
4437
4157
    Value := FindNextUnfoldedLine(Value, False);
4438
4158
  if FFoldedLinesView.FoldedAtTextIndex[Value-1] then
4439
4159
    Value := FindNextUnfoldedLine(Value, True);
4440
 
  Value := Min(Value, CurrentMaxTopLine);
4441
 
  FFoldedLinesView.TopTextIndex := fTopLine - 1;
4442
 
  if Value <> fTopLine then begin
4443
 
    fTopLine := Value;
4444
 
    FFoldedLinesView.TopTextIndex := Value-1;
4445
 
    UpdateScrollBars;
4446
 
    // call MarkupMgr before ScrollAfterTopLineChanged, in case we aren't in a PaintLock
4447
 
    fMarkupManager.TopLine:= fTopLine;
4448
 
    if (sfPainting in fStateFlags) then debugln('SetTopline inside paint');
4449
 
    ScrollAfterTopLineChanged;
4450
 
    StatusChanged([scTopLine]);
4451
 
  end
4452
 
  else
4453
 
    fMarkupManager.TopLine:= fTopLine;
4454
 
  {$IFDEF SYNSCROLLDEBUG}
4455
 
  if fPaintLock = 0 then debugln('SetTopline outside Paintlock EXIT');
4456
 
  {$ENDIF}
 
4160
 
 
4161
  NewTopView := FFoldedLinesView.TextIndexToViewPos(Value-1);
 
4162
  if NewTopView <> TopView then begin
 
4163
    TopView := NewTopView;
 
4164
  end;
4457
4165
end;
4458
4166
 
4459
4167
procedure TCustomSynEdit.ScrollAfterTopLineChanged;
4460
4168
var
4461
4169
  Delta: Integer;
 
4170
  srect: TRect;
4462
4171
begin
4463
4172
  if (sfPainting in fStateFlags) or (fPaintLock <> 0) or (not HandleAllocated) then
4464
4173
    exit;
4465
4174
  Delta := FOldTopView - TopView;
4466
4175
  {$IFDEF SYNSCROLLDEBUG}
4467
 
  if (sfHasScrolled in fStateFlags) then debugln(['ScrollAfterTopLineChanged with sfHasScrolled Delta=',Delta,' Ftopline=',FTopLine, '  FOldTopLine=',FOldTopLine,'  FOldTopView=',FOldTopView ]);
 
4176
  if (sfHasScrolled in fStateFlags) then debugln(['ScrollAfterTopLineChanged with sfHasScrolled Delta=',Delta,' topline=',TopLine, '  FOldTopView=',FOldTopView ]);
4468
4177
  {$ENDIF}
4469
4178
  if Delta <> 0 then begin
4470
4179
    // TODO: SW_SMOOTHSCROLL --> can't get it work
4471
 
    if (Abs(Delta) >= fLinesInWindow) or (sfHasScrolled in FStateFlags) then begin
 
4180
    if (Abs(Delta) >= LinesInWindow) or (sfHasScrolled in FStateFlags) then begin
4472
4181
      {$IFDEF SYNSCROLLDEBUG}
4473
4182
      debugln(['ScrollAfterTopLineChanged does invalidet Delta=',Delta]);
4474
4183
      {$ENDIF}
4475
4184
      Invalidate;
4476
4185
    end else
4477
 
    if ScrollWindowEx(Handle, 0, fTextHeight * Delta, nil, nil, 0, nil, SW_INVALIDATE)
4478
 
    then begin
4479
 
      {$IFDEF SYNSCROLLDEBUG}
4480
 
      debugln(['ScrollAfterTopLineChanged did scroll Delta=',Delta]);
4481
 
      {$ENDIF}
4482
 
      include(fStateFlags, sfHasScrolled);
4483
 
    end else begin
4484
 
      Invalidate;    // scrollwindow failed, invalidate all
4485
 
      {$IFDEF SYNSCROLLDEBUG}
4486
 
      debugln(['ScrollAfterTopLineChanged does invalidet (scroll failed) Delta=',Delta]);
4487
 
      {$ENDIF}
 
4186
    begin
 
4187
      srect := FPaintArea.Bounds;
 
4188
      srect.Top := FTextArea.TextBounds.Top;
 
4189
      srect.Bottom := FTextArea.TextBounds.Bottom;
 
4190
      if ScrollWindowEx(Handle, 0, LineHeight * Delta, @srect, @srect, 0, nil, SW_INVALIDATE)
 
4191
      then begin
 
4192
        {$IFDEF SYNSCROLLDEBUG}
 
4193
        debugln(['ScrollAfterTopLineChanged did scroll Delta=',Delta]);
 
4194
        {$ENDIF}
 
4195
        include(fStateFlags, sfHasScrolled);
 
4196
        FScreenCaret.InvalidatePos; // Wine (Win emulator) may have changed the pos with the scroll
 
4197
      end else begin
 
4198
        Invalidate;    // scrollwindow failed, invalidate all
 
4199
        {$IFDEF SYNSCROLLDEBUG}
 
4200
        debugln(['ScrollAfterTopLineChanged does invalidet (scroll failed) Delta=',Delta]);
 
4201
        {$ENDIF}
 
4202
      end;
4488
4203
    end;
4489
4204
  end;
4490
 
  FOldTopLine := FTopLine;
4491
4205
  FOldTopView := TopView;
4492
4206
  if (Delta <> 0) and (eoAlwaysVisibleCaret in fOptions2) then
4493
4207
    MoveCaretToVisibleArea;
4494
4208
end;
4495
4209
 
4496
 
{$IFDEF SYN_LAZARUS}
4497
4210
procedure TCustomSynEdit.MoveCaretToVisibleArea;
4498
4211
// scroll to make the caret visible
4499
4212
var
4508
4221
    exit;
4509
4222
 
4510
4223
  NewCaretXY:=CaretXY;
4511
 
  if NewCaretXY.X < fLeftChar then
4512
 
    NewCaretXY.X := fLeftChar
4513
 
  else if NewCaretXY.X > fLeftChar + fCharsInWindow - FScreenCaret.ExtraLineChars then
4514
 
    NewCaretXY.X := fLeftChar + fCharsInWindow - FScreenCaret.ExtraLineChars;
4515
 
  if NewCaretXY.Y < fTopLine then
4516
 
    NewCaretXY.Y := fTopLine
 
4224
  if NewCaretXY.X < LeftChar then
 
4225
    NewCaretXY.X := LeftChar
 
4226
  else if NewCaretXY.X > LeftChar + CharsInWindow - FScreenCaret.ExtraLineChars then
 
4227
    NewCaretXY.X := LeftChar + CharsInWindow - FScreenCaret.ExtraLineChars;
 
4228
  if NewCaretXY.Y < TopLine then
 
4229
    NewCaretXY.Y := TopLine
4517
4230
  else begin
4518
 
    MaxY:= ScreenRowToRow(Max(0,fLinesInWindow-1));
 
4231
    MaxY:= ScreenRowToRow(Max(0,LinesInWindow-1));
4519
4232
    if NewCaretXY.Y > MaxY then
4520
4233
      NewCaretXY.Y := MaxY;
4521
4234
  end;
4537
4250
begin
4538
4251
  MoveCaretIgnoreEOL(LogicalToPhysicalPos(NewLogCaret));
4539
4252
end;
4540
 
{$ENDIF}
4541
4253
 
4542
4254
procedure TCustomSynEdit.UpdateCaret(IgnorePaintLock: Boolean = False);
4543
 
{$IFDEF SYN_MBCSSUPPORT}
4544
4255
var
4545
 
  cf: TCompositionForm;
4546
 
{$ENDIF}
 
4256
  x, y: Integer;
4547
4257
begin
4548
4258
  if ( (PaintLock <> 0) and not IgnorePaintLock ) or (not HandleAllocated)
4549
4259
  then begin
4553
4263
    if eoAlwaysVisibleCaret in fOptions2 then
4554
4264
      MoveCaretToVisibleArea;
4555
4265
 
4556
 
    FScreenCaret.DisplayPos := Point(CaretXPix, CaretYPix);
4557
 
 
4558
 
{$IFDEF SYN_MBCSSUPPORT}
4559
 
    if HandleAllocated then begin
4560
 
      cf.dwStyle := CFS_POINT;
4561
 
      cf.ptCurrentPos := Point(CX, CY);
4562
 
      ImmSetCompositionWindow(ImmGetContext(Handle), @cf);
4563
 
    end;
4564
 
{$ENDIF}
 
4266
    x := CaretXPix;
 
4267
    y := CaretYPix;
 
4268
    FScreenCaret.DisplayPos := Point(x, y);
4565
4269
  end;
4566
4270
end;
4567
4271
 
4596
4300
      ShowScrollBar(Handle, SB_Horz, sfHorizScrollbarVisible in fStateFlags);
4597
4301
      RecalcCharsAndLinesInWin(True);
4598
4302
    end;
 
4303
    {$IFnDEF SynNewScrollBarUpdate}
 
4304
    if (sfHorizScrollbarVisible in fStateFlags) then begin
 
4305
    {$ENDIF}
4599
4306
    ScrollInfo.nPage := CharsInWindow;
4600
4307
    ScrollInfo.nPos := LeftChar;
4601
4308
    SetScrollInfo(Handle, SB_HORZ, ScrollInfo, True);
4603
4310
    if not (sfHorizScrollbarVisible in fStateFlags) then
4604
4311
      ShowScrollBar(Handle, SB_Horz, False);
4605
4312
    {$ENDIF} {$ENDIF}
 
4313
    {$IFnDEF SynNewScrollBarUpdate}
 
4314
    end;
 
4315
    {$ENDIF}
4606
4316
    //DebugLn('[TCustomSynEdit.UpdateScrollbars] nMin=',ScrollInfo.nMin,' nMax=',ScrollInfo.nMax,
4607
4317
    //' nPage=',ScrollInfo.nPage,' nPos=',ScrollInfo.nPos,' ClientW=',ClientWidth);
4608
4318
 
4622
4332
      ShowScrollBar(Handle, SB_Vert, sfVertScrollbarVisible in fStateFlags);
4623
4333
      RecalcCharsAndLinesInWin(True);
4624
4334
    end;
 
4335
    {$IFnDEF SynNewScrollBarUpdate}
 
4336
    if (sfVertScrollbarVisible in fStateFlags) then begin
 
4337
    {$ENDIF}
4625
4338
    ScrollInfo.nPage := LinesInWindow;
4626
 
    ScrollInfo.nPos := FFoldedLinesView.TextIndexToViewPos(TopLine-1);
 
4339
    ScrollInfo.nPos := TopView;
4627
4340
    SetScrollInfo(Handle, SB_VERT, ScrollInfo, True);
4628
4341
    {$IFNDEF LCLWin32} {$IFnDEF SynScrollBarWorkaround}
4629
4342
    if not (sfVertScrollbarVisible in fStateFlags) then
4630
4343
      ShowScrollBar(Handle, SB_Vert, False);
4631
4344
    {$ENDIF} {$ENDIF}
4632
 
  end;
 
4345
    {$IFnDEF SynNewScrollBarUpdate}
 
4346
    end;
 
4347
    {$ENDIF}
 
4348
  end;
 
4349
end;
 
4350
 
 
4351
procedure TCustomSynEdit.SelAvailChange(Sender: TObject);
 
4352
begin
 
4353
  if PaintLock > 0 then begin
 
4354
    Include(FStateFlags, sfSelChanged);
 
4355
    exit;
 
4356
  end;
 
4357
  Exclude(FStateFlags, sfSelChanged);
 
4358
  if SelAvail
 
4359
  then AquirePrimarySelection
 
4360
  else SurrenderPrimarySelection;
4633
4361
end;
4634
4362
 
4635
4363
procedure TCustomSynEdit.WMDropFiles(var Msg: TMessage);
4699
4427
    SB_LINEUP: LeftChar := LeftChar - 1;
4700
4428
      // Scrolls one page of chars left / right
4701
4429
    SB_PAGEDOWN: LeftChar := LeftChar
4702
 
      + (fCharsInWindow - Ord(eoScrollByOneLess in fOptions));
 
4430
      + Max(1, (CharsInWindow - Ord(eoScrollByOneLess in fOptions)));
4703
4431
    SB_PAGEUP: LeftChar := LeftChar
4704
 
      - (fCharsInWindow - Ord(eoScrollByOneLess in fOptions));
 
4432
      - Max(1, (CharsInWindow - Ord(eoScrollByOneLess in fOptions)));
4705
4433
      // Scrolls to the current scroll bar position
4706
4434
    SB_THUMBPOSITION,
4707
4435
    SB_THUMBTRACK: LeftChar := Msg.Pos;
4714
4442
  Exclude(FStateFlags, sfHideCursor);
4715
4443
  inherited;
4716
4444
  {$IFDEF VerboseFocus}
4717
 
  DebugLn(['[TCustomSynEdit.WMKillFocus] A ',Name, ' time=', dbgs(Now*86640)]);
 
4445
  DebugLn(['[TCustomSynEdit.WMKillFocus] A ',DbgSName(Self), ' time=', dbgs(Now*86640)]);
4718
4446
  {$ENDIF}
4719
4447
  LastMouseCaret:=Point(-1,-1);
4720
4448
  // Todo: Under Windows, keeping the Caret only works, if no other component creates a caret
4724
4452
  end;
4725
4453
  if FHideSelection and SelAvail then
4726
4454
    Invalidate;
 
4455
  {$IFDEF WinIME}
 
4456
  FImeHandler.FocusKilled;
 
4457
  {$ENDIF}
4727
4458
  inherited;
4728
4459
end;
4729
4460
 
4730
 
procedure TCustomSynEdit.WMSetFocus(var Msg: TWMSetFocus);
 
4461
procedure TCustomSynEdit.WMSetFocus(var Msg: TLMSetFocus);
4731
4462
begin
4732
4463
  if fCaret = nil then exit; // This SynEdit is in Destroy
4733
4464
  Exclude(FStateFlags, sfHideCursor);
4734
4465
  LastMouseCaret:=Point(-1,-1);
4735
4466
  {$IFDEF VerboseFocus}
4736
 
  DebugLn(['[TCustomSynEdit.WMSetFocus] A ',Name,':',ClassName, ' time=', dbgs(Now*86640)]);
 
4467
  DebugLn(['[TCustomSynEdit.WMSetFocus] A ',DbgSName(Self), ' time=', dbgs(Now*86640)]);
4737
4468
  {$ENDIF}
4738
4469
  FScreenCaret.DestroyCaret; // Ensure recreation. On Windows only one caret exists, and it must be moved to the focused editor
4739
 
  FScreenCaret.Visible := True;
 
4470
  FScreenCaret.Visible := not(eoNoCaret in FOptions);
4740
4471
  //if FHideSelection and SelAvail then
4741
4472
  //  Invalidate;
4742
4473
  inherited;
4743
4474
  //DebugLn('[TCustomSynEdit.WMSetFocus] END');
4744
4475
end;
4745
4476
 
4746
 
procedure TCustomSynEdit.Resize;
 
4477
procedure TCustomSynEdit.DoOnResize;
4747
4478
begin
4748
4479
  inherited;
4749
4480
  if (not HandleAllocated) or ((ClientWidth = FOldWidth) and (ClientHeight = FOldHeight)) then exit;
4774
4505
begin
4775
4506
  if ScrollHintWnd = nil then begin
4776
4507
    ScrollHintWnd := HintWindowClass.Create(Application);
 
4508
    ScrollHintWnd.Name:='SynEditScrollHintWnd';
4777
4509
    ScrollHintWnd.Visible := FALSE;
4778
4510
  end;
4779
4511
  Result := ScrollHintWnd;
4788
4520
  pt: TPoint;
4789
4521
  ScrollHint: THintWindow;
4790
4522
begin
4791
 
  //debugln('TCustomSynEdit.WMVScroll A ',DbgSName(Self),' Msg.ScrollCode=',dbgs(Msg.ScrollCode),' SB_PAGEDOWN=',dbgs(SB_PAGEDOWN),' SB_PAGEUP=',dbgs(SB_PAGEUP));
 
4523
  {$IFDEF SYNSCROLLDEBUG}
 
4524
  debugln('TCustomSynEdit.WMVScroll A ',DbgSName(Self),' Msg.ScrollCode=',dbgs(Msg.ScrollCode),' SB_PAGEDOWN=',dbgs(SB_PAGEDOWN),' SB_PAGEUP=',dbgs(SB_PAGEUP));
 
4525
  {$ENDIF}
4792
4526
  case Msg.ScrollCode of
4793
4527
      // Scrolls to start / end of the text
4794
 
    SB_TOP: TopLine := 1;
4795
 
    SB_BOTTOM: TopLine := FTheLinesView.Count;
 
4528
    SB_TOP: TopView := 1;
 
4529
    SB_BOTTOM: TopView := FFoldedLinesView.Count;
4796
4530
      // Scrolls one line up / down
4797
 
{$IFDEF SYN_LAZARUS}
4798
4531
    SB_LINEDOWN: TopView := TopView + 1;
4799
4532
    SB_LINEUP: TopView := TopView - 1;
4800
4533
      // Scrolls one page of lines up / down
4801
4534
    SB_PAGEDOWN: TopView := TopView
4802
 
      + (fLinesInWindow - Ord(eoScrollByOneLess in fOptions));
 
4535
      + Max(1, (LinesInWindow - Ord(eoScrollByOneLess in fOptions))); // TODO: scroll half page ?
4803
4536
    SB_PAGEUP: TopView := TopView
4804
 
      - (fLinesInWindow - Ord(eoScrollByOneLess in fOptions));
4805
 
{$ELSE}
4806
 
    SB_LINEDOWN: TopLine := TopLine + 1;
4807
 
    SB_LINEUP: TopLine := TopLine - 1;
4808
 
      // Scrolls one page of lines up / down
4809
 
    SB_PAGEDOWN: TopLine := TopLine
4810
 
      + (fLinesInWindow - Ord(eoScrollByOneLess in fOptions));
4811
 
    SB_PAGEUP: TopLine := TopLine
4812
 
      - (fLinesInWindow - Ord(eoScrollByOneLess in fOptions));
4813
 
{$ENDIF}
 
4537
      - Max(1, (LinesInWindow - Ord(eoScrollByOneLess in fOptions)));
4814
4538
      // Scrolls to the current scroll bar position
4815
4539
    SB_THUMBPOSITION,
4816
4540
    SB_THUMBTRACK:
4817
4541
      begin
4818
 
{$IFNDEF SYN_LAZARUS}
4819
 
        if Lines.Count > MAX_SCROLL then
4820
 
          TopLine := MulDiv(LinesInWindow + Lines.Count - 1, Msg.Pos,
4821
 
            MAX_SCROLL)
4822
 
        else
4823
 
{$ENDIF}
4824
 
          {$IFDEF SYN_LAZARUS}
4825
 
          TopView := Msg.Pos;
4826
 
          {$ELSE}
4827
 
          TopLine := Msg.Pos;
4828
 
          {$ENDIF}
 
4542
        TopView := Msg.Pos;
4829
4543
 
4830
4544
        if eoShowScrollHint in fOptions then begin
4831
4545
          ScrollHint := GetScrollHint;
4834
4548
            ScrollHint.Visible := TRUE;
4835
4549
          end;
4836
4550
          s := Format('line %d', [TopLine]);
4837
 
{$IFDEF SYN_COMPILER_3_UP}
4838
4551
          rc := ScrollHint.CalcHintRect(200, s, nil);
4839
 
{$ELSE}
4840
 
          rc := Rect(0, 0, ScrollHint.Canvas.TextWidth(s) + 6,
4841
 
            ScrollHint.Canvas.TextHeight(s) + 4);
4842
 
{$ENDIF}
4843
4552
          pt := ClientToScreen(Point(
4844
4553
                ClientWidth-ScrollBarWidth
4845
4554
                        - rc.Right - 4, 10));
 
4555
          if eoScrollHintFollows in fOptions then
 
4556
            pt.y := Mouse.CursorPos.y - (rc.Bottom div 2);
4846
4557
          OffsetRect(rc, pt.x, pt.y);
4847
4558
          ScrollHint.ActivateHint(rc, s);
4848
 
{$IFNDEF SYN_COMPILER_3_UP}
4849
4559
          ScrollHint.Invalidate;
4850
 
{$ENDIF}
4851
4560
          ScrollHint.Update;
4852
4561
        end;
4853
4562
      end;
4861
4570
  end;
4862
4571
end;
4863
4572
 
 
4573
procedure TCustomSynEdit.CMWantSpecialKey(var Message: TLMessage);
 
4574
begin
 
4575
  if (Message.wParam = VK_TAB) then begin
 
4576
    if WantTabs then
 
4577
      Message.Result := 1
 
4578
    else
 
4579
      Message.Result := 0;
 
4580
  end
 
4581
  else
 
4582
    inherited;
 
4583
end;
 
4584
 
4864
4585
procedure TCustomSynEdit.ScanRanges(ATextChanged: Boolean = True);
4865
4586
begin
4866
4587
  if not HandleAllocated then begin
4875
4596
      // TODO: see TSynEditFoldedView.LineCountChanged, this is only needed, because NeedFixFrom does not always work
4876
4597
      FFoldedLinesView.FixFoldingAtTextIndex(FChangedLinesStart, FChangedLinesEnd);
4877
4598
    end;
4878
 
    Topline := TopLine;
 
4599
    TopView := TopView;
4879
4600
    exit;
4880
4601
  end;
4881
4602
  FHighlighter.CurrentLines := FLines; // Trailing spaces are not needed
4884
4605
  // Todo: text may not have changed
4885
4606
  if ATextChanged then
4886
4607
    fMarkupManager.TextChanged(FChangedLinesStart, FChangedLinesEnd);
4887
 
  Topline := TopLine;
 
4608
  TopView := TopView;
4888
4609
end;
4889
4610
 
4890
4611
procedure TCustomSynEdit.IdleScanRanges(Sender: TObject; var Done: Boolean);
4977
4698
  SetBlockBegin(Point(1, 1));
4978
4699
  SetCaretXY(Point(1, 1));
4979
4700
  // scroll to start of text
4980
 
  TopLine := 1;
 
4701
  TopView := 1;
4981
4702
  LeftChar := 1;
4982
4703
  StatusChanged(scTextCleared);
4983
4704
end;
4986
4707
var
4987
4708
  i: Integer;
4988
4709
begin
4989
 
  {$IFDEF SynFoldDebug}debugln(['FOLD-- FoldChanged; Index=', Index, ' topline=', TopLine, '  ScreenRowToRow(LinesInWindow + 1)=', ScreenRowToRow(LinesInWindow + 1)]);{$ENDIF}
4990
 
  TopLine := TopLine;
 
4710
  {$IFDEF SynFoldDebug}debugln(['FOLD-- FoldChanged; Index=', Index, ' TopView=', TopView, '  ScreenRowToRow(LinesInWindow + 1)=', ScreenRowToRow(LinesInWindow + 1)]);{$ENDIF}
 
4711
  TopView := TopView;
4991
4712
  i := FFoldedLinesView.CollapsedLineForFoldAtLine(CaretY);
4992
4713
  if i > 0 then begin
4993
4714
    SetCaretXY(Point(1, i));
5003
4724
  InvalidateGutterLines(Index + 1, -1);
5004
4725
end;
5005
4726
 
5006
 
procedure TCustomSynEdit.SetTopView(const AValue : Integer);
 
4727
procedure TCustomSynEdit.SetTopView(AValue : Integer);
5007
4728
begin
5008
 
  TopLine := FFoldedLinesView.ViewPosToTextIndex(AValue)+1;
 
4729
  //  don't use MinMax here, it will fail in design mode (Lines.Count is zero,
 
4730
  // but the painting code relies on TopLine >= 1)
 
4731
  {$IFDEF SYNSCROLLDEBUG}
 
4732
  if (fPaintLock = 0) and (not FIsInDecPaintLock) then debugln(['SetTopView outside Paintlock New=',AValue, ' Old=', FFoldedLinesView.TopLine]);
 
4733
  if (sfHasScrolled in fStateFlags) then debugln(['SetTopView with sfHasScrolled Value=',AValue, '  FOldTopView=',FOldTopView ]);
 
4734
  {$ENDIF}
 
4735
  TSynEditStringList(FLines).SendCachedNotify; // TODO: review
 
4736
 
 
4737
  AValue := Min(AValue, CurrentMaxTopView);
 
4738
  AValue := Max(AValue, 1);
 
4739
 
 
4740
  (* ToDo: FFoldedLinesView.TopLine := AValue;
 
4741
    Required, if "TopView := TopView" or "TopLine := TopLine" is called,
 
4742
    after ScanRanges (used to be: LineCountChanged / LineTextChanged)
 
4743
  *)
 
4744
  FFoldedLinesView.TopLine := AValue;
 
4745
 
 
4746
  if FTextArea.TopLine <> AValue then begin
 
4747
    FTextArea.TopLine := AValue;
 
4748
    UpdateScrollBars;
 
4749
    // call MarkupMgr before ScrollAfterTopLineChanged, in case we aren't in a PaintLock
 
4750
    fMarkupManager.TopLine := TopLine;
 
4751
    if (sfPainting in fStateFlags) then debugln('SetTopline inside paint');
 
4752
    ScrollAfterTopLineChanged;
 
4753
    StatusChanged([scTopLine]);
 
4754
  end
 
4755
  else
 
4756
    fMarkupManager.TopLine := TopLine;
 
4757
 
 
4758
  {$IFDEF SYNSCROLLDEBUG}
 
4759
  if (fPaintLock = 0) and (not FIsInDecPaintLock) then debugln('SetTopline outside Paintlock EXIT');
 
4760
  {$ENDIF}
5009
4761
end;
5010
4762
 
5011
4763
function TCustomSynEdit.GetTopView : Integer;
5012
4764
begin
5013
 
  Result := FFoldedLinesView.TextIndexToViewPos(TopLine-1);
 
4765
  Result := FTextArea.TopLine;
5014
4766
end;
5015
4767
 
5016
4768
procedure TCustomSynEdit.SetWordBlock(Value: TPoint);
5108
4860
 
5109
4861
function TCustomSynEdit.GetCanPaste:Boolean;
5110
4862
begin
5111
 
  Result := Clipboard.HasFormat(CF_TEXT)
5112
 
    or Clipboard.HasFormat(TSynClipboardStream.ClipboardFormatId)
 
4863
  Result := (Clipboard.HasFormat(CF_TEXT) or
 
4864
             Clipboard.HasFormat(TSynClipboardStream.ClipboardFormatId)
 
4865
            )
5113
4866
end;
5114
4867
 
5115
4868
procedure TCustomSynEdit.Redo;
5119
4872
begin
5120
4873
  Group := fRedoList.PopItem;
5121
4874
  if Group <> nil then begin;
 
4875
    {$IFDEF SynUndoDebugCalls}
 
4876
    DebugLnEnter(['>> TCustomSynEdit.Redo ',DbgSName(self), ' ', dbgs(Self), ' Group', dbgs(Group), ' cnt=', Group.Count]);
 
4877
    {$ENDIF}
5122
4878
    IncPaintLock;
5123
4879
    FTheLinesView.IsRedoing := True;
5124
4880
    Item := Group.Pop;
5140
4896
    if fRedoList.IsTopMarkedAsUnmodified then
5141
4897
      fUndoList.MarkTopAsUnmodified;
5142
4898
    DecPaintLock;
 
4899
    {$IFDEF SynUndoDebugCalls}
 
4900
    DebugLnExit(['<< TCustomSynEdit.Redo ',DbgSName(self), ' ', dbgs(Self)]);
 
4901
  end else begin
 
4902
    DebugLn(['<< TCustomSynEdit.Redo - NO GROUP ',DbgSName(self), ' ', dbgs(Self)]);
 
4903
    {$ENDIF}
5143
4904
  end;
5144
4905
end;
5145
4906
 
5167
4928
      SetCaretAndSelection(LogicalToPhysicalPos(Point(1,TSynEditUndoIndent(Item).FPosY1)),
5168
4929
        Point(1, TSynEditUndoIndent(Item).FPosY1), Point(2, TSynEditUndoIndent(Item).FPosY2),
5169
4930
        smNormal);
5170
 
      x := fBlockIndent;
5171
 
      fBlockIndent := TSynEditUndoIndent(Item).FCnt;
 
4931
      x := FBlockIndent;
 
4932
      y := FBlockTabIndent;
 
4933
      FBlockIndent := TSynEditUndoIndent(Item).FCnt;
 
4934
      FBlockTabIndent := TSynEditUndoIndent(Item).FTabCnt;
5172
4935
      DoBlockIndent;
5173
 
      fBlockIndent := x;
 
4936
      FBlockIndent := x;
 
4937
      FBlockTabIndent := y;
5174
4938
    end
5175
4939
    else
5176
4940
    if Item.ClassType = TSynEditUndoUnIndent then
5208
4972
    exit;
5209
4973
  end;
5210
4974
 
5211
 
  if (FLastMousePoint.X >= TextLeftPixelOffset(False)) and
5212
 
     (FLastMousePoint.X < ClientWidth - TextRightPixelOffset - ScrollBarWidth) and
5213
 
     (FLastMousePoint.Y >= 0) and (FLastMousePoint.Y < ClientHeight - ScrollBarWidth) then
5214
 
  begin
 
4975
  if (FLastMousePoint.X >= FTextArea.Bounds.Left) and (FLastMousePoint.X <  FTextArea.Bounds.Right) and
 
4976
     (FLastMousePoint.Y >= FTextArea.Bounds.Top) and (FLastMousePoint.Y < FTextArea.Bounds.Bottom)
 
4977
  then begin
5215
4978
    if Assigned(FMarkupCtrlMouse) and (FMarkupCtrlMouse.Cursor <> crDefault) then
5216
4979
      Cursor := FMarkupCtrlMouse.Cursor
5217
4980
    else
5228
4991
begin
5229
4992
  Group := fUndoList.PopItem;
5230
4993
  if Group <> nil then begin;
 
4994
    {$IFDEF SynUndoDebugCalls}
 
4995
    DebugLnEnter(['>> TCustomSynEdit.Undo ',DbgSName(self), ' ', dbgs(Self), ' Group', dbgs(Group), ' cnt=', Group.Count]);
 
4996
    {$ENDIF}
5231
4997
    IncPaintLock;
5232
4998
    FTheLinesView.IsUndoing := True;
5233
4999
    Item := Group.Pop;
5252
5018
    if fUndoList.IsTopMarkedAsUnmodified then
5253
5019
      fRedoList.MarkTopAsUnmodified;
5254
5020
    DecPaintLock;
 
5021
    {$IFDEF SynUndoDebugCalls}
 
5022
    DebugLnExit(['<< TCustomSynEdit.Undo ',DbgSName(self), ' ', dbgs(Self)]);
 
5023
  end else begin
 
5024
    DebugLn(['<< TCustomSynEdit.Undo - NO GROUP ',DbgSName(self), ' ', dbgs(Self)]);
 
5025
    {$ENDIF}
5255
5026
  end;
5256
5027
end;
5257
5028
 
5258
5029
procedure TCustomSynEdit.UndoItem(Item: TSynEditUndoItem);
5259
5030
var
5260
5031
  Line, OldText: PChar;
5261
 
  y, Len, Len2: integer;
 
5032
  y, Len, Len2, LenT: integer;
5262
5033
 
5263
5034
  function GetLeadWSLen : integer;
5264
5035
  var
5278
5049
    begin
5279
5050
      // add to redo list
5280
5051
      fRedoList.AddChange(TSynEditUndoIndent.Create(TSynEditUndoIndent(Item).FPosY1,
5281
 
         TSynEditUndoIndent(Item).FPosY2, TSynEditUndoIndent(Item).FCnt));
 
5052
         TSynEditUndoIndent(Item).FPosY2, TSynEditUndoIndent(Item).FCnt, TSynEditUndoIndent(Item).FTabCnt));
5282
5053
      // quick unintend (must all be spaces, as inserted...)
5283
5054
      fRedoList.Lock;
5284
5055
      Len2 := TSynEditUndoIndent(Item).FCnt;
5285
 
      for y := TSynEditUndoUnIndent(Item).FPosY1 to TSynEditUndoUnIndent(Item).FPosY2 do begin
 
5056
      LenT := TSynEditUndoIndent(Item).FTabCnt;
 
5057
      for y := TSynEditUndoIndent(Item).FPosY1 to TSynEditUndoIndent(Item).FPosY2 do begin
5286
5058
        Line := PChar(FTheLinesView[y - 1]);
5287
5059
        Len := GetLeadWSLen;
5288
5060
        FTheLinesView.EditDelete(Len+1-Len2, y, Len2);
 
5061
        FTheLinesView.EditDelete(1, y, LenT);
5289
5062
      end;
5290
5063
      fRedoList.Unlock;
5291
5064
    end
5319
5092
  end;
5320
5093
end;
5321
5094
 
5322
 
procedure TCustomSynEdit.SetDividerDrawLevel(const AValue: Integer);
5323
 
begin
5324
 
  if assigned(fHighlighter) then
5325
 
    fHighlighter.DrawDividerLevel := AValue;
5326
 
  Invalidate;
5327
 
end;
5328
 
 
5329
5095
procedure TCustomSynEdit.SetFoldState(const AValue: String);
5330
5096
begin
5331
5097
  if assigned(fHighlighter) then begin
5341
5107
  end;
5342
5108
  FFoldedLinesView.Lock;
5343
5109
  FFoldedLinesView.ApplyFoldDescription(0, 0, -1, -1, PChar(AValue), length(AValue), True);
5344
 
  TopLine := TopLine; // Todo: reset topline on foldedview
 
5110
  TopView := TopView; // Todo: reset TopView on foldedview
5345
5111
  FFoldedLinesView.UnLock;
5346
5112
  FPendingFoldState := '';
5347
5113
end;
5348
5114
 
 
5115
procedure TCustomSynEdit.SetHighlightAllColor(AValue: TSynSelectedColor);
 
5116
begin
 
5117
  fMarkupHighAll.MarkupInfo.Assign(AValue);
 
5118
end;
 
5119
 
 
5120
procedure TCustomSynEdit.SetIncrementColor(AValue: TSynSelectedColor);
 
5121
begin
 
5122
  fMarkupSelection.MarkupInfoIncr.Assign(AValue);
 
5123
end;
 
5124
 
 
5125
procedure TCustomSynEdit.SetLineHighlightColor(AValue: TSynSelectedColor);
 
5126
begin
 
5127
  fMarkupSpecialLine.MarkupLineHighlightInfo.Assign(AValue);
 
5128
end;
 
5129
 
5349
5130
procedure TCustomSynEdit.SetMouseActions(const AValue: TSynEditMouseActions);
5350
5131
begin
5351
 
  if AValue = nil then
5352
 
    FMouseActions.Clear
5353
 
  else
5354
 
    FMouseActions.Assign(AValue);
 
5132
  FMouseActions.UserActions := AValue;
 
5133
end;
 
5134
 
 
5135
procedure TCustomSynEdit.SetMouseLinkColor(AValue: TSynSelectedColor);
 
5136
begin
 
5137
  fMarkupCtrlMouse.MarkupInfo.Assign(AValue);
5355
5138
end;
5356
5139
 
5357
5140
procedure TCustomSynEdit.SetMouseSelActions(const AValue: TSynEditMouseActions);
5358
5141
begin
5359
 
  if AValue = nil then
5360
 
    FMouseSelActions.Clear
5361
 
  else
5362
 
    FMouseSelActions.Assign(AValue);
 
5142
  FMouseSelActions.UserActions := AValue;
 
5143
end;
 
5144
 
 
5145
procedure TCustomSynEdit.SetMouseTextActions(AValue: TSynEditMouseActions);
 
5146
begin
 
5147
  FMouseTextActions.UserActions := AValue;
5363
5148
end;
5364
5149
 
5365
5150
procedure TCustomSynEdit.SetPaintLockOwner(const AValue: TSynEditBase);
5406
5191
  OldBuffer: TSynEditStringList;
5407
5192
  LView: TSynEditStrings;
5408
5193
  i: Integer;
5409
 
  TempPlugins: TList;
5410
5194
begin
5411
5195
  FLines.SendNotification(senrTextBufferChanging, FLines); // Send the old buffer
5412
5196
  DestroyMarkList;
5413
5197
 
5414
 
  // Remember all Plugins; Detach from Lines
5415
 
  TempPlugins := TList.Create;
5416
 
  for i := FPlugins.Count - 1 downto 0 do begin
5417
 
    TempPlugins.Add(FPlugins[i]);
5418
 
    TSynEditPlugin(FPlugins[i]).Editor := nil;
5419
 
  end;
5420
5198
  // Detach Highlighter
5421
5199
  if FHighlighter <> nil then
5422
5200
    FHighlighter.DetachFromLines(FLines);
5444
5222
  NewBuffer.CopyHanlders(OldBuffer, fMarkupManager);
5445
5223
  for i := 0 to fMarkupManager.Count - 1 do
5446
5224
    NewBuffer.CopyHanlders(OldBuffer, fMarkupManager.Markup[i]);
 
5225
  for i := 0 to FPlugins.Count - 1 do
 
5226
    NewBuffer.CopyHanlders(OldBuffer, Plugin[i]);
5447
5227
 
5448
5228
  FUndoList := NewBuffer.UndoList;
5449
5229
  FRedoList := NewBuffer.RedoList;
5460
5240
  if FHighlighter <> nil then
5461
5241
    FHighlighter.AttachToLines(FLines);
5462
5242
 
5463
 
  // Restore Plugins; Attach to Lines
5464
 
  for i := 0 to TempPlugins.Count - 1 do
5465
 
    TSynEditPlugin(TempPlugins[i]).Editor := Self;
5466
 
  TempPlugins.Free;
5467
 
 
5468
5243
  RemoveHandlers(OldBuffer);
5469
5244
  OldBuffer.DetachSynEdit(Self);
5470
5245
  FLines.SendNotification(senrTextBufferChanged, OldBuffer); // Send the old buffer
5480
5255
  j := 0;
5481
5256
  i := TSynEditStringList(FLines).AttachedSynEditCount - 1;
5482
5257
  while (i >= 0) and (j <= 1) do begin
5483
 
    if TSynEdit(TSynEditStringList(FLines).AttachedSynEdits[i]).FMarkList = FMarkList then
 
5258
    if TCustomSynEdit(TSynEditStringList(FLines).AttachedSynEdits[i]).FMarkList = FMarkList then
5484
5259
      inc(j);
5485
5260
    dec(i);
5486
5261
  end;
5500
5275
    s := TSynEditStringList(FLines).AttachedSynEdits[0];
5501
5276
    if s = Self then
5502
5277
      s := TSynEditStringList(FLines).AttachedSynEdits[1];
5503
 
    FMarkList := TSynEdit(s).FMarkList;
 
5278
    FMarkList := TCustomSynEdit(s).FMarkList;
5504
5279
    TSynEditMarkListInternal(fMarkList).AddOwnerEdit(Self);
5505
5280
    for i := 0 to 9 do
5506
 
      FBookMarks[i] := TSynEdit(s).fBookMarks[i];
 
5281
      FBookMarks[i] := TCustomSynEdit(s).fBookMarks[i];
5507
5282
  end
5508
5283
  else begin
5509
5284
    FMarkList := TSynEditMarkListInternal.Create(self, FTheLinesView);
5532
5307
      s := TSynEditStringList(FLines).AttachedSynEdits[1]; // TODO: find one that shares the MarkList (if someday partial sharing of Marks is avail)
5533
5308
 
5534
5309
    if TSynEditMarkListInternal(FMarkList).LinesView = FTheLinesView then
5535
 
      TSynEditMarkListInternal(FMarkList).LinesView := TSynEdit(s).FTheLinesView;
 
5310
      TSynEditMarkListInternal(FMarkList).LinesView := TCustomSynEdit(s).FTheLinesView;
5536
5311
 
5537
5312
    it := TSynEditMarkIterator.Create(FMarkList);
5538
5313
    it.GotoBOL;
5594
5369
  UpdateScrollBars;
5595
5370
end;
5596
5371
 
5597
 
procedure TCustomSynEdit.SetTextBetweenPoints(aStartPoint, aEndPoint: TPoint;
 
5372
procedure TCustomSynEdit.SetTextBetweenPointsSimple(aStartPoint, aEndPoint: TPoint;
5598
5373
  const AValue: String);
5599
5374
begin
5600
5375
  InternalBeginUndoBlock;
5611
5386
procedure TCustomSynEdit.SetTextBetweenPointsEx(aStartPoint, aEndPoint: TPoint;
5612
5387
  aCaretMode: TSynCaretAdjustMode; const AValue: String);
5613
5388
begin
 
5389
  SetTextBetweenPoints(aStartPoint, aEndPoint, AValue, [], aCaretMode);
 
5390
end;
 
5391
 
 
5392
procedure TCustomSynEdit.SetTextBetweenPoints(aStartPoint, aEndPoint: TPoint;
 
5393
  const AValue: String; aFlags: TSynEditTextFlags; aCaretMode: TSynCaretAdjustMode;
 
5394
  aMarksMode: TSynMarksAdjustMode; aSelectionMode: TSynSelectionMode);
 
5395
begin
5614
5396
  InternalBeginUndoBlock;
5615
5397
  try
5616
5398
    if aCaretMode = scamAdjust then
5617
5399
      FCaret.IncAutoMoveOnEdit;
5618
 
    FInternalBlockSelection.SelectionMode := smNormal;
 
5400
 
 
5401
    if aSelectionMode = smCurrent then
 
5402
      FInternalBlockSelection.SelectionMode    := FBlockSelection.ActiveSelectionMode
 
5403
    else
 
5404
      FInternalBlockSelection.SelectionMode    := aSelectionMode;
5619
5405
    FInternalBlockSelection.StartLineBytePos := aStartPoint;
5620
 
    FInternalBlockSelection.EndLineBytePos := aEndPoint;
 
5406
    FInternalBlockSelection.EndLineBytePos   := aEndPoint;
 
5407
    aStartPoint := FInternalBlockSelection.FirstLineBytePos;
 
5408
 
5621
5409
    if aCaretMode = scamBegin then
5622
 
      FCaret.LineBytePos := FInternalBlockSelection.StartLineBytePos;
5623
 
    FInternalBlockSelection.SelText := AValue;
 
5410
      FCaret.LineBytePos := aStartPoint;
 
5411
 
 
5412
    FInternalBlockSelection.SetSelTextPrimitive(FInternalBlockSelection.ActiveSelectionMode,
 
5413
                                                PChar(AValue),
 
5414
                                                aMarksMode = smaKeep
 
5415
                                               );
5624
5416
    if aCaretMode = scamEnd then
5625
5417
      FCaret.LineBytePos := FInternalBlockSelection.StartLineBytePos;
 
5418
    if setSelect in aFlags then begin
 
5419
      FBlockSelection.StartLineBytePos    := aStartPoint;
 
5420
      FBlockSelection.ActiveSelectionMode := FInternalBlockSelection.SelectionMode;
 
5421
      FBlockSelection.EndLineBytePos      := FInternalBlockSelection.StartLineBytePos;
 
5422
      if FBlockSelection.ActiveSelectionMode = smLine then
 
5423
        FBlockSelection.EndLineBytePos := Point(FBlockSelection.StartBytePos + 1, FBlockSelection.EndLinePos - 1);
 
5424
    end;
5626
5425
  finally
5627
5426
    if aCaretMode = scamAdjust then
5628
5427
      FCaret.DecAutoMoveOnEdit;
5630
5429
  end;
5631
5430
end;
5632
5431
 
 
5432
procedure TCustomSynEdit.SetVisibleSpecialChars(AValue: TSynVisibleSpecialChars);
 
5433
begin
 
5434
  if FVisibleSpecialChars = AValue then Exit;
 
5435
  FVisibleSpecialChars := AValue;
 
5436
  fMarkupSpecialChar.VisibleSpecialChars := AValue;
 
5437
  if eoShowSpecialChars in Options
 
5438
  then FPaintArea.VisibleSpecialChars := AValue
 
5439
  else FPaintArea.VisibleSpecialChars := [];
 
5440
  if eoShowSpecialChars in Options then Invalidate;
 
5441
end;
 
5442
 
5633
5443
function TCustomSynEdit.GetLineState(ALine: Integer): TSynLineState;
5634
5444
begin
5635
5445
  with TSynEditStringList(fLines) do
5657
5467
  then begin
5658
5468
    LogCaret:=Point(fBookMarks[BookMark].Column, fBookMarks[BookMark].Line);
5659
5469
    DoIncPaintLock(Self); // No editing is taking place
 
5470
    FCaret.ChangeOnTouch;
5660
5471
    FCaret.LineBytePos := LogCaret;
5661
 
    SetBlockEnd(LogCaret);
5662
 
    SetBlockBegin(LogCaret);
5663
5472
    DoDecPaintLock(Self);
5664
5473
  end;
5665
5474
end;
5719
5528
  State: TDragState; var Accept: Boolean);
5720
5529
begin
5721
5530
  inherited;
5722
 
  {$IFDEF SYN_LAZARUS}
5723
5531
  LastMouseCaret:=Point(-1,-1);
5724
 
  {$ENDIF}
5725
5532
  if (Source is TCustomSynEdit) and not TCustomSynEdit(Source).ReadOnly then
5726
5533
  begin
5727
5534
    Accept := True;
5831
5638
 
5832
5639
procedure TCustomSynEdit.SetRightEdge(Value: Integer);
5833
5640
begin
5834
 
  if fRightEdge <> Value then begin
5835
 
    fRightEdge := Value;
5836
 
    Invalidate;
 
5641
  // Todo: check and invalidate in text area
 
5642
  if FTextArea.RightEdgeColumn <> Value then begin
 
5643
    FPaintArea.RightEdgeColumn := Value;
 
5644
    if FTextArea.RightEdgeVisible then
 
5645
      Invalidate;
5837
5646
  end;
5838
5647
end;
5839
5648
 
5842
5651
  nX: integer;
5843
5652
  rcInval: TRect;
5844
5653
begin
5845
 
  if fRightEdgeColor <> Value then begin
5846
 
    fRightEdgeColor := Value;
 
5654
  // Todo: check and invalidate in text area
 
5655
  if RightEdgeColor <> Value then begin
 
5656
    FPaintArea.RightEdgeColor := Value;
5847
5657
    if HandleAllocated then begin
5848
 
      nX := fTextOffset + fRightEdge * fCharWidth;
5849
 
      rcInval := Rect(nX - 1, 0, nX + 1
5850
 
         , ClientHeight{$IFDEF SYN_LAZARUS}-ScrollBarWidth{$ENDIF});
 
5658
      nX := FTextArea.ScreenColumnToXValue(FTextArea.RightEdgeColumn + 1);
 
5659
      rcInval := Rect(nX - 1, 0, nX + 1, ClientHeight-ScrollBarWidth);
5851
5660
      {$IFDEF VerboseSynEditInvalidate}
5852
5661
      DebugLn(['TCustomSynEdit.SetRightEdgeColor ',dbgs(rcInval)]);
5853
5662
      {$ENDIF}
5880
5689
      fMarkupHighCaret.Highlighter := nil;
5881
5690
      fMarkupWordGroup.Highlighter := nil;
5882
5691
      FFoldedLinesView.Highlighter := nil;
5883
 
{begin}                                                                         //mh 2000-10-01
 
5692
      FPaintArea.Highlighter := nil;
5884
5693
      if not (csDestroying in ComponentState) then begin
5885
5694
        RecalcCharExtent;
5886
 
        SizeOrFontChanged(TRUE);                                                //jr 2000-10-01
5887
5695
        Invalidate;
5888
5696
      end;
5889
 
{end}                                                                           //mh 2000-10-01
5890
5697
    end;
5891
5698
    if (fBookmarkOpt <> nil) then
5892
5699
      if (AComponent = fBookmarkOpt.BookmarkImages) then begin
5923
5730
      fMarkupHighCaret.Highlighter := Value;
5924
5731
      fMarkupWordGroup.Highlighter := Value;
5925
5732
      FFoldedLinesView.Highlighter := Value;
 
5733
      FPaintArea.Highlighter := Value;
5926
5734
      FWordBreaker.Reset;
5927
5735
      if fHighlighter<>nil then begin
5928
5736
        fTSearch.IdentChars := fHighlighter.IdentChars;
5933
5741
      end;
5934
5742
      RecalcCharExtent;
5935
5743
      ScanRanges; // Todo: Skip if paintlocked
 
5744
      // There may not have been a scan
 
5745
      if fHighlighter <> nil then
 
5746
        FHighlighter.CurrentLines := FLines;
 
5747
      FLines.SendNotification(senrHighlightChanged, FLines, -1, -1);
5936
5748
    finally
5937
5749
      DecPaintLock;
5938
5750
    end;
5939
 
    SizeOrFontChanged(TRUE);
5940
5751
  end;
5941
5752
end;
5942
5753
 
6016
5827
    // try to make the current selection visible as well
6017
5828
    MinX:=PhysCaretXY.X;
6018
5829
    MaxX:=PhysCaretXY.X;
6019
 
    if SelAvail then begin
 
5830
    // sfMouseSelecting: ignore block while selecting by mouse
 
5831
    if SelAvail and not(sfMouseSelecting in fStateFlags) then begin
6020
5832
      PhysBlockBeginXY:=LogicalToPhysicalPos(BlockBegin);
6021
5833
      PhysBlockEndXY:=LogicalToPhysicalPos(BlockEnd);
6022
5834
      if (PhysBlockBeginXY.X<>PhysBlockEndXY.X)
6040
5852
      ' LeftChar='+dbgs(LeftChar), '');}
6041
5853
    if MinX < LeftChar then
6042
5854
      LeftChar := MinX
6043
 
    else if LeftChar < MaxX - (CharsInWindow - 1 - FScreenCaret.ExtraLineChars) then
6044
 
      LeftChar := MaxX - (CharsInWindow - 1 - FScreenCaret.ExtraLineChars)
 
5855
    else if LeftChar < MaxX - (Max(1, CharsInWindow) - 1 - FScreenCaret.ExtraLineChars) then
 
5856
      LeftChar := MaxX - (Max(1, CharsInWindow) - 1 - FScreenCaret.ExtraLineChars)
6045
5857
    else
6046
5858
      LeftChar := LeftChar;                                                     //mh 2000-10-19
6047
5859
    //DebugLn(['TCustomSynEdit.EnsureCursorPosVisible B LeftChar=',LeftChar,' MinX=',MinX,' MaxX=',MaxX,' CharsInWindow=',CharsInWindow]);
6051
5863
    else if CaretY > ScreenRowToRow(Max(1, LinesInWindow) - 1) then             //mh 2000-10-19
6052
5864
      TopLine := FFoldedLinesView.TextPosAddLines(CaretY, -Max(0, LinesInWindow-1))
6053
5865
    else
6054
 
      TopLine := TopLine;                                                       //mh 2000-10-19
 
5866
      TopView := TopView;                                                       //mh 2000-10-19
6055
5867
  finally
6056
5868
    DoDecPaintLock(Self);
6057
5869
  end;
6069
5881
begin
6070
5882
  if fExtraCharSpacing=Value then exit;
6071
5883
  fExtraCharSpacing := Value;
 
5884
  FPaintArea.ExtraCharSpacing := Value;
6072
5885
  FontChanged(self);
6073
5886
end;
6074
5887
 
6086
5899
  FKeystrokes.ResetDefaults;
6087
5900
end;
6088
5901
 
 
5902
procedure TCustomSynEdit.ResetMouseActions;
 
5903
begin
 
5904
  FMouseActions.Options := FMouseOptions;
 
5905
  FMouseActions.ResetUserActions;
 
5906
  FMouseSelActions.Options := FMouseOptions;
 
5907
  FMouseSelActions.ResetUserActions;
 
5908
  FMouseTextActions.Options := FMouseOptions;
 
5909
  FMouseTextActions.ResetUserActions;
 
5910
 
 
5911
  FLeftGutter.ResetMouseActions;
 
5912
  FRightGutter.ResetMouseActions;
 
5913
end;
 
5914
 
6089
5915
procedure TCustomSynEdit.CommandProcessor(Command: TSynEditorCommand;
6090
5916
  AChar: TUTF8Char;
6091
5917
  Data: pointer);
6092
5918
var
6093
5919
  InitialCmd: TSynEditorCommand;
6094
5920
begin
6095
 
  {$IFDEF VerboseKeys}
6096
 
  DebugLn(['[TCustomSynEdit.CommandProcessor] ',Command
6097
 
    ,' AChar=',AChar,' Data=',DbgS(Data)]);
6098
 
  {$ENDIF}
6099
 
  // first the program event handler gets a chance to process the command
6100
 
  InitialCmd := Command;
6101
 
  DoOnProcessCommand(Command, AChar, Data);
6102
 
  if Command <> ecNone then begin
6103
 
    try
6104
 
      InternalBeginUndoBlock;
6105
 
      FBeautifyStartLineIdx := -1;
6106
 
      FBeautifyEndLineIdx := -1;
6107
 
      if assigned(FBeautifier) then begin
6108
 
        FBeautifier.AutoIndent := (eoAutoIndent in FOptions);
6109
 
        FBeautifier.BeforeCommand(self, FTheLinesView, FCaret, Command, InitialCmd);
6110
 
      end;
6111
 
      // notify hooked command handlers before the command is executed inside of
6112
 
      // the class
6113
 
      if Command <> ecNone then
6114
 
        NotifyHookedCommandHandlers(FALSE, Command, AChar, Data);
6115
 
      // internal command handler
6116
 
      if (Command <> ecNone) and (Command < ecUserFirst) then
6117
 
        ExecuteCommand(Command, AChar, Data);
6118
 
      // notify hooked command handlers after the command was executed inside of
6119
 
      // the class
6120
 
      if Command <> ecNone then
6121
 
        NotifyHookedCommandHandlers(TRUE, Command, AChar, Data);
6122
 
      if Command <> ecNone then
6123
 
        DoOnCommandProcessed(Command, AChar, Data);
 
5921
  IncLCLRefCount;
 
5922
  try
 
5923
    {$IFDEF VerboseKeys}
 
5924
    DebugLn(['[TCustomSynEdit.CommandProcessor] ',Command
 
5925
      ,' AChar=',AChar,' Data=',DbgS(Data)]);
 
5926
    {$ENDIF}
 
5927
    // first the program event handler gets a chance to process the command
 
5928
    InitialCmd := Command;
 
5929
    NotifyHookedCommandHandlers(Command, AChar, Data, hcfInit);
 
5930
    DoOnProcessCommand(Command, AChar, Data);
 
5931
    if Command <> ecNone then begin
 
5932
      try
 
5933
        InternalBeginUndoBlock;
 
5934
        FBeautifyStartLineIdx := -1;
 
5935
        FBeautifyEndLineIdx := -1;
 
5936
        if assigned(FBeautifier) then begin
 
5937
          FBeautifier.AutoIndent := (eoAutoIndent in FOptions);
 
5938
          FBeautifier.BeforeCommand(self, FTheLinesView, FCaret, Command, InitialCmd);
 
5939
        end;
 
5940
        // notify hooked command handlers before the command is executed inside of
 
5941
        // the class
 
5942
        if Command <> ecNone then
 
5943
          NotifyHookedCommandHandlers(Command, AChar, Data, hcfPreExec);
 
5944
        // internal command handler
 
5945
        if (Command <> ecNone) and (Command < ecUserFirst) then
 
5946
          ExecuteCommand(Command, AChar, Data);
 
5947
        // notify hooked command handlers after the command was executed inside of
 
5948
        // the class
 
5949
        if Command <> ecNone then
 
5950
          NotifyHookedCommandHandlers(Command, AChar, Data, hcfPostExec);
 
5951
        if Command <> ecNone then
 
5952
          DoOnCommandProcessed(Command, AChar, Data);
6124
5953
 
6125
 
      if assigned(FBeautifier) then begin
6126
 
        tsyneditstringlist(FLines).FlushNotificationCache;
6127
 
        FBeautifier.AutoIndent := (eoAutoIndent in FOptions);
6128
 
        FBeautifier.AfterCommand(self, FTheLinesView, FCaret, Command, InitialCmd,
6129
 
                                 FBeautifyStartLineIdx+1, FBeautifyEndLineIdx+1);
 
5954
        if assigned(FBeautifier) then begin
 
5955
          tsyneditstringlist(FLines).FlushNotificationCache;
 
5956
          FBeautifier.AutoIndent := (eoAutoIndent in FOptions);
 
5957
          FBeautifier.AfterCommand(self, FTheLinesView, FCaret, Command, InitialCmd,
 
5958
                                   FBeautifyStartLineIdx+1, FBeautifyEndLineIdx+1);
 
5959
        end;
 
5960
      finally
 
5961
        InternalEndUndoBlock;
 
5962
        {$IFDEF SynCheckPaintLock}
 
5963
        if (FPaintLock > 0) and (FInvalidateRect.Bottom > FInvalidateRect.Top) then begin
 
5964
          debugln(['TCustomSynEdit.CommandProcessor: Paint called while locked  InitialCmd=', InitialCmd, ' Command=', Command]);
 
5965
          DumpStack;
 
5966
        end;
 
5967
        {$ENDIF}
6130
5968
      end;
6131
 
    finally
6132
 
      InternalEndUndoBlock;
6133
5969
    end;
 
5970
    NotifyHookedCommandHandlers(Command, AChar, Data, hcfFinish);
 
5971
  finally
 
5972
    DecLCLRefCount;
6134
5973
  end;
6135
5974
end;
6136
5975
 
6137
5976
procedure TCustomSynEdit.ExecuteCommand(Command: TSynEditorCommand;
6138
5977
  const AChar: TUTF8Char; Data: pointer);
6139
5978
const
6140
 
  ALPHANUMERIC = DIGIT + ALPHA_UC + ALPHA_LC;
6141
5979
  SEL_MODE: array[ecNormalSelect..ecLineSelect] of TSynSelectionMode = (
6142
5980
    smNormal, smColumn, smLine);
6143
5981
var
6149
5987
  WP: TPoint;
6150
5988
  Caret: TPoint;
6151
5989
  CaretNew: TPoint;
6152
 
{$IFDEF SYN_MBCSSUPPORT}
6153
 
  StartOfBlock: TPoint;
6154
 
  i: integer;
6155
 
  s: string;
6156
 
{$ENDIF}
6157
5990
  counter: Integer;
6158
5991
  LogCounter: integer;
6159
5992
  LogCaretXY: TPoint;
6161
5994
 
6162
5995
begin
6163
5996
  IncPaintLock;
 
5997
  IncLCLRefCount;
6164
5998
  try
6165
5999
    fUndoList.CurrentReason := Command;
6166
6000
 
6170
6004
      FBlockSelection.ActiveSelectionMode := FBlockSelection.SelectionMode;
6171
6005
 
6172
6006
    FBlockSelection.AutoExtend := Command in [ecSelectionStart..ecSelectionEnd];
6173
 
    if Command in [ecSelectionStart..ecSelectionEnd] then
6174
 
      AquirePrimarySelection;
6175
 
 
6176
6007
    FCaret.ChangeOnTouch;
6177
6008
 
6178
6009
    case Command of
6199
6030
        end;
6200
6031
      ecPageLeft, ecSelPageLeft, ecColSelPageLeft:
6201
6032
        begin
6202
 
          MoveCaretHorz(-CharsInWindow);
 
6033
          MoveCaretHorz(-Max(1, CharsInWindow));
6203
6034
        end;
6204
6035
      ecPageRight, ecSelPageRight, ecColSelPageRight:
6205
6036
        begin
6206
 
          MoveCaretHorz(CharsInWindow);
 
6037
          MoveCaretHorz(Max(1, CharsInWindow));
6207
6038
        end;
6208
6039
      ecLineStart, ecSelLineStart, ecColSelLineStart:
6209
6040
        begin
6228
6059
        end;
6229
6060
      ecPageUp, ecSelPageUp, ecPageDown, ecSelPageDown, ecColSelPageUp, ecColSelPageDown:
6230
6061
        begin
6231
 
          counter := fLinesInWindow;
6232
 
          if (eoHalfPageScroll in fOptions) then counter:=counter shr 1;
 
6062
          counter := LinesInWindow;
 
6063
          if (eoHalfPageScroll in fOptions) then counter:=counter div 2;
6233
6064
          if eoScrollByOneLess in fOptions then
6234
6065
            Dec(counter);
 
6066
          counter := Max(1, counter);
6235
6067
          if (Command in [ecPageUp, ecSelPageUp, ecColSelPageUp]) then
6236
6068
            counter := -counter;
6237
6069
          TopView := TopView + counter;
6271
6103
          FCaret.LineCharPos := PPoint(Data)^;
6272
6104
        end;
6273
6105
// word selection
6274
 
      ecWordLeft, ecSelWordLeft, ecColSelWordLeft:
 
6106
      ecWordLeft, ecSelWordLeft, ecColSelWordLeft,
 
6107
      ecWordEndLeft, ecSelWordEndLeft, ecHalfWordLeft, ecSelHalfWordLeft:
6275
6108
        begin
6276
 
          CaretNew := PrevWordLogicalPos;
 
6109
          case Command of
 
6110
            ecWordEndLeft, ecSelWordEndLeft:   CaretNew := PrevWordLogicalPos(swbWordEnd);
 
6111
            ecHalfWordLeft, ecSelHalfWordLeft: CaretNew := PrevWordLogicalPos(swbCaseChange);
 
6112
            else                               CaretNew := PrevWordLogicalPos;
 
6113
          end;
6277
6114
          if FFoldedLinesView.FoldedAtTextIndex[CaretNew.Y - 1] then begin
6278
6115
            CY := FindNextUnfoldedLine(CaretNew.Y, False);
6279
6116
            CaretNew := Point(1 + Length(FTheLinesView[CY-1]), CY);
6280
6117
          end;
6281
6118
          FCaret.LineBytePos := CaretNew;
6282
6119
        end;
6283
 
      ecWordRight, ecSelWordRight, ecColSelWordRight:
 
6120
      ecWordRight, ecSelWordRight, ecColSelWordRight,
 
6121
      ecWordEndRight, ecSelWordEndRight, ecHalfWordRight, ecSelHalfWordRight:
6284
6122
        begin
6285
 
          CaretNew := NextWordLogicalPos;
 
6123
          case Command of
 
6124
            ecWordEndRight, ecSelWordEndRight:   CaretNew := NextWordLogicalPos(swbWordEnd);
 
6125
            ecHalfWordRight, ecSelHalfWordRight: CaretNew := NextWordLogicalPos(swbCaseChange);
 
6126
            else                                 CaretNew := NextWordLogicalPos;
 
6127
          end;
6286
6128
          if FFoldedLinesView.FoldedAtTextIndex[CaretNew.Y - 1] then
6287
6129
            CaretNew := Point(1, FindNextUnfoldedLine(CaretNew.Y, True));
6288
6130
          FCaret.LineBytePos := CaretNew;
6345
6187
              // delete char
6346
6188
              Counter:=GetCharLen(Temp,LogCaretXY.X);
6347
6189
              FTheLinesView.EditDelete(LogCaretXY.X, CaretY, Counter);
 
6190
              SetLogicalCaretXY(LogCaretXY);
6348
6191
            end else begin
6349
6192
              // join line with the line after
6350
6193
              if CaretY < FTheLinesView.Count then begin
6364
6207
              Helper := StringOfChar(' ', CaretX - 1 - Len);
6365
6208
              CaretX := 1 + Len;
6366
6209
            end;
6367
 
            WP := NextWordLogicalPos(True);
 
6210
            // if we are not in a word, delete word + spaces (up to next token)
 
6211
            if WordBreaker.IsAtWordStart(LineText, LogicalCaretXY.X) or
 
6212
               WordBreaker.IsAtWordEnd(LineText, LogicalCaretXY.X) or
 
6213
               (not WordBreaker.IsInWord(LineText, LogicalCaretXY.X)) or
 
6214
               (LogicalCaretXY.X > Length(LineText))
 
6215
            then
 
6216
              WP := NextWordLogicalPos(swbTokenBegin, True)
 
6217
            else
 
6218
              // if we are inside a word, delete to word-end
 
6219
              WP := NextWordLogicalPos(swbWordEnd, True);
6368
6220
          end else
6369
6221
            WP := Point(Len + 1, CaretY);
6370
6222
          if (WP.X <> FCaret.BytePos) or (WP.Y <> FCaret.LinePos) then begin
6371
6223
            FInternalBlockSelection.StartLineBytePos := WP;
6372
6224
            FInternalBlockSelection.EndLineBytePos := LogicalCaretXY;
6373
6225
            FInternalBlockSelection.ActiveSelectionMode := smNormal;
6374
 
            FInternalBlockSelection.SetSelTextPrimitive(smNormal, nil);
6375
 
            if Helper <> '' then
6376
 
              FTabbedLinesView.EditInsert(CaretX, CaretY, Helper);
6377
 
            CaretXY := Caret;
 
6226
            FInternalBlockSelection.SetSelTextPrimitive(smNormal, PChar(Helper));
 
6227
            FCaret.BytePos := FInternalBlockSelection.StartBytePos;
6378
6228
          end;
6379
6229
        end;
6380
6230
      ecDeleteLastWord, ecDeleteBOL:
6432
6282
        end;
6433
6283
      ecShiftTab:
6434
6284
        if not ReadOnly then
6435
 
          {$IFDEF SYN_LAZARUS}
6436
6285
          if SelAvail and (eoTabIndent in Options) then
6437
 
            DoBlockUnindent
6438
 
          {$ENDIF};
 
6286
            DoBlockUnindent;
6439
6287
      ecMatchBracket:
6440
6288
        FindMatchingBracket;
6441
6289
      ecChar:
6475
6323
              {$ENDIF}
6476
6324
 
6477
6325
              CaretX := CaretX + 1;
6478
 
              if CaretX >= LeftChar + fCharsInWindow then
6479
 
                LeftChar := LeftChar + Min(25, fCharsInWindow - 1);
 
6326
              if CaretX >= LeftChar + CharsInWindow then
 
6327
                LeftChar := LeftChar + Min(25, CharsInWindow - 1);
6480
6328
            finally
6481
6329
              FCaret.DecForceAdjustToNextChar;
6482
6330
              FCaret.DecForcePastEOL;
6553
6401
          LeftChar := LeftChar - 1;
6554
6402
          if CaretX > LeftChar + CharsInWindow then
6555
6403
            CaretX := LeftChar + CharsInWindow;
6556
 
          Update;
6557
6404
        end;
6558
6405
      ecScrollRight:
6559
6406
        begin
6560
6407
          LeftChar := LeftChar + 1;
6561
6408
          if CaretX < LeftChar then
6562
6409
            CaretX := LeftChar;
6563
 
          Update;
6564
6410
        end;
6565
6411
      ecInsertMode:
6566
6412
        begin
6644
6490
        begin
6645
6491
          DefaultSelectionMode := SEL_MODE[Command];
6646
6492
        end;
6647
 
{$IFDEF SYN_MBCSSUPPORT}
6648
 
      ecImeStr:
6649
 
        if not ReadOnly then begin
6650
 
          SetString(s, PChar(Data), StrLen(Data));
6651
 
          if SelAvail then begin
6652
 
            SetSelTextExternal(s);
6653
 
          end else begin
6654
 
            Temp := LineText;
6655
 
            Len := Length(Temp);
6656
 
            if Len < CaretX then
6657
 
              Temp := Temp + StringOfChar(' ', CaretX - Len);
6658
 
            try
6659
 
              FCaret.IncForcePastEOL;
6660
 
              StartOfBlock := CaretXY;
6661
 
// Processing of case character covers on LeadByte.
6662
 
              Len := Length(s);
6663
 
              if not fInserting then begin
6664
 
                i := (CaretX + Len);
6665
 
                if (ByteType(Temp, i) = mbTrailByte) then begin
6666
 
                  s := s + Temp[i - 1];
6667
 
                  Helper := Copy(Temp, CaretX, Len - 1);
6668
 
                end else
6669
 
                  Helper := Copy(Temp, CaretX, Len);
6670
 
                Delete(Temp, CaretX, Len);
6671
 
              end;
6672
 
              Insert(s, Temp, CaretX);
6673
 
              CaretX := (CaretX + Len);
6674
 
              FTheLinesView[CaretY - 1] := Temp;
6675
 
              if fInserting then
6676
 
                Helper := '';
6677
 
              fUndoList.AddChange(crInsert, StartOfBlock,
6678
 
                LogicalCaretXY,
6679
 
                Helper, smNormal);
6680
 
              if CaretX >= LeftChar + fCharsInWindow then
6681
 
                LeftChar := LeftChar + min(25, fCharsInWindow - 1);
6682
 
            finally
6683
 
              FCaret.DecForcePastEOL;
6684
 
            end;
6685
 
          end;
6686
 
        end;
6687
 
{$ENDIF}
6688
 
      {$IFDEF SYN_LAZARUS}
6689
6493
      EcFoldLevel1..EcFoldLevel9:
6690
6494
        FoldAll(Command - EcFoldLevel1);
6691
6495
      EcFoldLevel0:
6700
6504
        end;
6701
6505
      EcUnFoldCurrent:
6702
6506
          FFoldedLinesView.UnFoldAtTextIndex(CaretY-1);
6703
 
      {$ENDIF}
6704
6507
      EcToggleMarkupWord:
6705
6508
          FMarkupHighCaret.ToggleCurrentWord;
6706
6509
    end;
6707
6510
  finally
6708
6511
    DecPaintLock;
 
6512
    DecLCLRefCount;
6709
6513
  end;
6710
6514
end;
6711
6515
 
6732
6536
 
6733
6537
procedure TCustomSynEdit.ClearAll;
6734
6538
begin
6735
 
  {$IFDEF SYN_LAZARUS}
6736
6539
  InternalBeginUndoBlock;
6737
 
  SelectAll;
6738
 
  SelText:='';
6739
 
  InternalEndUndoBlock;
6740
 
  {$ELSE}
6741
 
  Lines.Clear;
6742
 
  {$ENDIF}
 
6540
  try
 
6541
    SelectAll;
 
6542
    SelText:='';
 
6543
  finally
 
6544
    InternalEndUndoBlock;
 
6545
  end;
6743
6546
end;
6744
6547
 
6745
6548
procedure TCustomSynEdit.ClearSelection;
6761
6564
procedure TCustomSynEdit.InternalBeginUndoBlock(aList: TSynEditUndoList);
6762
6565
begin
6763
6566
  if aList = nil then aList := fUndoList;
 
6567
  {$IFDEF SynUndoDebugBeginEnd}
 
6568
  DebugLnEnter(['>> TCustomSynEdit.InternalBeginUndoBlock', DbgSName(self), ' ', dbgs(Self), ' aList=', aList, ' FPaintLock=', FPaintLock, ' InGroupCount=',aList.InGroupCount]);
 
6569
  {$ENDIF}
6764
6570
  aList.OnNeedCaretUndo := {$IFDEF FPC}@{$ENDIF}GetCaretUndo;
6765
6571
  aList.BeginBlock;
6766
6572
  IncPaintLock;
6777
6583
   // after unfold
6778
6584
  DecPaintLock;
6779
6585
  aList.EndBlock; // Todo: Doing this after DecPaintLock, can cause duplicate calls to StatusChanged(scModified)
 
6586
  {$IFDEF SynUndoDebugBeginEnd}
 
6587
  DebugLnEnter(['<< TCustomSynEdit.InternalEndUndoBlock', DbgSName(self), ' ', dbgs(Self), ' aList=', aList, ' FPaintLock=', FPaintLock, ' InGroupCount=',aList.InGroupCount]);
 
6588
  {$ENDIF}
6780
6589
end;
6781
6590
 
6782
 
procedure TCustomSynEdit.BeginUndoBlock;
 
6591
procedure TCustomSynEdit.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}(ACaller: String = ''){$ENDIF};
6783
6592
begin
 
6593
  {$IFDEF SynUndoDebugBeginEnd}
 
6594
  DebugLnEnter(['>> TCustomSynEdit.BeginUndoBlock ', DbgSName(self), ' ', dbgs(Self), ' Caller=', ACaller, ' FPaintLock=', FPaintLock, ' InGroupCount=',fUndoList.InGroupCount, '  FIsInDecPaintLock=',dbgs(FIsInDecPaintLock)]);
 
6595
  if ACaller = '' then DumpStack;
 
6596
  {$ENDIF}
6784
6597
  fUndoList.OnNeedCaretUndo := {$IFDEF FPC}@{$ENDIF}GetCaretUndo;
6785
6598
  fUndoList.BeginBlock;
6786
6599
  ////FFoldedLinesView.Lock;
6787
6600
  //FTrimmedLinesView.Lock;
6788
6601
end;
6789
6602
 
6790
 
procedure TCustomSynEdit.BeginUpdate;
 
6603
procedure TCustomSynEdit.BeginUpdate(WithUndoBlock: Boolean = True);
6791
6604
begin
6792
6605
  IncPaintLock;
 
6606
  {$IFDEF SynUndoDebugBeginEnd}
 
6607
  if WithUndoBlock and (FPaintLock = 0) and (FUndoBlockAtPaintLock = 0) then
 
6608
    DebugLn(['************** TCustomSynEdit.BeginUpdate  PAINTLOCK NOT INCREASED  ', DbgSName(self), ' ', dbgs(Self),  ' FPaintLock=', FPaintLock, ' InGroupCount=',fUndoList.InGroupCount, '  FIsInDecPaintLock=',dbgs(FIsInDecPaintLock)]);
 
6609
  {$ENDIF}
 
6610
  if WithUndoBlock and (FPaintLock > 0) and (FUndoBlockAtPaintLock = 0) then begin
 
6611
    FUndoBlockAtPaintLock := FPaintLock;
 
6612
    BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('SynEdit.BeginUpdate'){$ENDIF};
 
6613
  end;
6793
6614
end;
6794
6615
 
6795
 
procedure TCustomSynEdit.EndUndoBlock;
 
6616
procedure TCustomSynEdit.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}(ACaller: String = ''){$ENDIF};
6796
6617
begin
6797
6618
  // Write all trimming info to the end of the undo block,
6798
6619
  // so it will be undone first, and other UndoItems do see the expected spaces
6799
6620
  //FTrimmedLinesView.UnLock;
6800
6621
  ////FFoldedLinesView.UnLock;
6801
6622
  fUndoList.EndBlock;
 
6623
  {$IFDEF SynUndoDebugBeginEnd}
 
6624
  DebugLnEnter(['<< TCustomSynEdit.EndUndoBlock', DbgSName(self), ' ', dbgs(Self), ' Caller=', ACaller, ' FPaintLock=', FPaintLock, ' InGroupCount=',fUndoList.InGroupCount, '  FIsInDecPaintLock=',dbgs(FIsInDecPaintLock)]);
 
6625
  //if ACaller = '' then DumpStack;
 
6626
  {$ENDIF}
6802
6627
end;
6803
6628
 
6804
6629
procedure TCustomSynEdit.EndUpdate;
6834
6659
    FFoldedLinesView.CollapseDefaultFolds;
6835
6660
    if FPendingFoldState <> '' then
6836
6661
      SetFoldState(FPendingFoldState);
6837
 
    TopLine := TopLine;
 
6662
    TopView := TopView;
6838
6663
  end;
6839
6664
end;
6840
6665
 
6862
6687
  InvalidateGutterLines(Sender.Line, Sender.Line);
6863
6688
end;
6864
6689
 
6865
 
{$IFDEF SYN_LAZARUS}
6866
6690
function TCustomSynEdit.GetSelStart: integer;                                   //L505 begin
6867
6691
 
6868
6692
  function llen(const data: string): integer;
6972
6796
  p.x := value - count; p.y := loop + 1;
6973
6797
  BlockEnd := p;
6974
6798
end;
6975
 
{$ENDIF}
6976
6799
 
6977
6800
procedure TCustomSynEdit.SetExtraLineSpacing(const Value: integer);
6978
6801
begin
6979
6802
  if fExtraLineSpacing=Value then exit;
6980
6803
  fExtraLineSpacing := Value;
 
6804
  FPaintArea.ExtraLineSpacing := Value;
6981
6805
  FontChanged(self);
6982
6806
end;
6983
6807
 
7002
6826
var
7003
6827
  x, y: integer;
7004
6828
begin
7005
 
  Result := GetBookMark(BookMark, x, y);
 
6829
  Result := GetBookMark(BookMark, x{%H-}, y{%H-});
7006
6830
end;
7007
6831
 
7008
6832
procedure TCustomSynEdit.MarkTextAsSaved;
7039
6863
  if (csLoading in ComponentState) then exit;
7040
6864
 
7041
6865
  GutterChanged(Sender);
7042
 
  fTextOffset := TextLeftPixelOffset - (LeftChar - 1) * fCharWidth;
7043
6866
 
7044
6867
  if HandleAllocated then begin
7045
6868
    RecalcCharsAndLinesInWin(False);
7082
6905
  fRedoList.Unlock;
7083
6906
end;
7084
6907
 
7085
 
{$IFNDEF SYN_LAZARUS}
7086
 
 
7087
 
procedure TCustomSynEdit.WMMouseWheel(var Msg: TMessage);
 
6908
procedure TCustomSynEdit.WMMouseWheel(var Message: TLMMouseEvent);
7088
6909
var
7089
 
  nDelta: integer;
7090
 
  nWheelClicks: integer;
7091
 
{$IFNDEF SYN_COMPILER_4_UP}
7092
 
const
7093
 
  LinesToScroll = 3;
7094
 
  WHEEL_DELTA = 120;
7095
 
  WHEEL_PAGESCROLL = MAXDWORD;
7096
 
{$ENDIF}
 
6910
  lState: TShiftState;
7097
6911
begin
7098
 
  if csDesigning in ComponentState then
7099
 
    exit;
7100
 
 
7101
 
  if GetKeyState(VK_CONTROL) >= 0 then
7102
 
{$IFDEF SYN_COMPILER_4_UP}
7103
 
    nDelta := Mouse.WheelScrollLines
7104
 
{$ELSE}
7105
 
    nDelta := LinesToScroll
7106
 
{$ENDIF}
7107
 
  else begin
7108
 
    {$IFDEF SYN_LAZARUS}
7109
 
    nDelta := fLinesInWindow;
7110
 
    if (eoHalfPageScroll in fOptions) then counter:=counter shr 1;
7111
 
    {$ELSE}
7112
 
    nDelta := fLinesInWindow shr Ord(eoHalfPageScroll in fOptions);
7113
 
    {$ENDIF}
7114
 
  end;
7115
 
 
7116
 
  Inc(fMouseWheelAccumulator, SmallInt(Msg.wParamHi));
7117
 
  nWheelClicks := fMouseWheelAccumulator div WHEEL_DELTA;
7118
 
  fMouseWheelAccumulator := fMouseWheelAccumulator mod WHEEL_DELTA;
7119
 
  if (nDelta = integer(WHEEL_PAGESCROLL)) or (nDelta > LinesInWindow) then
7120
 
    nDelta := LinesInWindow;
7121
 
  {$IFDEF SYN_LAZARUS}
7122
 
  TopView := TopView - (nDelta * nWheelClicks);
7123
 
  {$ELSE}
7124
 
  TopLine := TopLine - (nDelta * nWheelClicks);
7125
 
  {$ENDIF}
7126
 
  Update;
 
6912
  if ((sfHorizScrollbarVisible in fStateFlags) and (Message.Y > ClientHeight)) or
 
6913
     ((sfVertScrollbarVisible in fStateFlags) and (Message.X > ClientWidth))
 
6914
   then begin
 
6915
     inherited;
 
6916
     exit;
 
6917
   end;
 
6918
 
 
6919
  lState := Message.State - [ssCaps, ssNum, ssScroll]; // Remove unreliable states, see http://bugs.freepascal.org/view.php?id=20065
 
6920
 
 
6921
  FMouseClickDoPopUp := False;
 
6922
  IncPaintLock;
 
6923
  try
 
6924
    if Message.WheelDelta > 0 then begin
 
6925
      FindAndHandleMouseAction(mbXWheelUp, lState, Message.X, Message.Y, ccSingle, cdDown, Message.WheelDelta);
 
6926
    end
 
6927
    else begin
 
6928
      // send megative delta
 
6929
      FindAndHandleMouseAction(mbXWheelDown, lState, Message.X, Message.Y, ccSingle, cdDown, Message.WheelDelta);
 
6930
    end;
 
6931
  finally
 
6932
    DecPaintLock;
 
6933
  end;
 
6934
 
 
6935
  if FMouseClickDoPopUp and (PopupMenu <> nil) then begin
 
6936
    PopupMenu.PopupComponent:=self;
 
6937
    PopupMenu.PopUp;
 
6938
  end;
 
6939
 
 
6940
  Message.Result := 1 // handled, skip further handling by interface
7127
6941
end;
7128
6942
 
7129
 
{$ENDIF}
7130
 
 
7131
6943
procedure TCustomSynEdit.SetWantTabs(const Value: boolean);
7132
6944
begin
7133
6945
  fWantTabs := Value;
7236
7048
  IncPaintLock;
7237
7049
  try
7238
7050
    //DebugLn(['TCustomSynEdit.SearchReplace ptStart=',dbgs(ptStart),' ptEnd=',dbgs(ptEnd),' ASearch="',dbgstr(ASearch),'" AReplace="',dbgstr(AReplace),'"']);
7239
 
    while fTSearch.FindNextOne(FTheLinesView,ptStart,ptEnd,ptFoundStart,ptFoundEnd) do
 
7051
    while fTSearch.FindNextOne(FTheLinesView,ptStart,ptEnd,ptFoundStart,ptFoundEnd, True) do
7240
7052
    begin
7241
7053
      //DebugLn(['TCustomSynEdit.SearchReplace FOUND ptStart=',dbgs(ptStart),' ptEnd=',dbgs(ptEnd),' ptFoundStart=',dbgs(ptFoundStart),' ptFoundEnd=',dbgs(ptFoundEnd)]);
7242
7054
      // check if found place is entirely in range
7275
7087
          // user has been prompted and has requested to silently replace all
7276
7088
          // so turn off prompting
7277
7089
          if nAction = raReplaceAll then begin
7278
 
            if not bReplaceAll then begin
7279
 
              bReplaceAll := TRUE;
7280
 
            end;
 
7090
            bReplaceAll := True;
7281
7091
            bPrompt := False;
7282
7092
          end;
7283
7093
          // replace text
7314
7124
  end;
7315
7125
end;
7316
7126
 
7317
 
{$IFDEF SYN_MBCSSUPPORT}
7318
 
 
7319
 
procedure TCustomSynEdit.MBCSGetSelRangeInLineWhenColumnSelectionMode(
7320
 
  const s: string; var ColFrom, ColTo: Integer);
7321
 
  // --ColFrom and ColTo are in/out parameter. their range
7322
 
  //    will be from 1 to MaxInt.
7323
 
  // --a range of selection means:  Copy(s, ColFrom, ColTo - ColFrom);
7324
 
  //    be careful what ColTo means.
7325
 
var
7326
 
  Len: Integer;
7327
 
begin
7328
 
  Len := Length(s);
7329
 
  if (0 < ColFrom) and (ColFrom <= Len) then
7330
 
    if mbTrailByte = ByteType(s, ColFrom) then
7331
 
      Inc(ColFrom);
7332
 
  if (0 < ColTo) and (ColTo <= Len) then
7333
 
    if mbTrailByte = ByteType(s, ColTo) then
7334
 
      Inc(ColTo);
7335
 
end;
7336
 
 
7337
 
{$ENDIF}
7338
 
 
7339
7127
function TCustomSynEdit.IsPointInSelection(Value: TPoint): boolean;
7340
7128
var
7341
7129
  ptBegin, ptEnd: TPoint;
7369
7157
procedure TCustomSynEdit.SetOptions(Value: TSynEditorOptions);
7370
7158
var
7371
7159
  ChangedOptions: TSynEditorOptions;
7372
 
  i: Integer;
 
7160
  m: TSynEditorOption;
 
7161
  MOpt: TSynEditorMouseOptions;
 
7162
  f: Boolean;
7373
7163
begin
7374
7164
  Value := Value - SYNEDIT_UNIMPLEMENTED_OPTIONS;
7375
 
  if (Value <> fOptions) then begin
7376
 
    ChangedOptions:=(fOptions-Value)+(Value-fOptions);
7377
 
    fOptions := Value;
7378
 
    UpdateOptions;
7379
 
    if not (eoScrollPastEol in Options) then
7380
 
      LeftChar := LeftChar;
7381
 
    if (eoScrollPastEol in Options) or (eoScrollPastEof in Options) then begin
7382
 
      UpdateScrollBars;
7383
 
      TopLine := TopLine;
7384
 
    end;
7385
 
    // (un)register HWND as drop target
7386
 
    if (eoDropFiles in ChangedOptions) and not (csDesigning in ComponentState) and HandleAllocated then
7387
 
      ; // ToDo DragAcceptFiles
7388
 
    if (eoPersistentCaret in ChangedOptions) and HandleAllocated then
7389
 
      UpdateCaret;
7390
 
    if (eoShowSpecialChars in ChangedOptions) and HandleAllocated then
 
7165
  if (Value = FOptions) then exit;
 
7166
 
 
7167
  ChangedOptions:=(FOptions-Value)+(Value-FOptions);
 
7168
  FOptions := Value;
 
7169
  UpdateOptions;
 
7170
 
 
7171
  if not (eoScrollPastEol in Options) then
 
7172
    LeftChar := LeftChar;
 
7173
  if (eoScrollPastEol in Options) or (eoScrollPastEof in Options) then begin
 
7174
    UpdateScrollBars;
 
7175
    TopView := TopView;
 
7176
  end;
 
7177
  // (un)register HWND as drop target
 
7178
  if (eoDropFiles in ChangedOptions) and not (csDesigning in ComponentState) and HandleAllocated then
 
7179
    ; // ToDo DragAcceptFiles
 
7180
  if (ChangedOptions * [eoPersistentCaret, eoNoCaret] <> []) and HandleAllocated then begin
 
7181
    UpdateCaret;
 
7182
    if Focused then
 
7183
      FScreenCaret.Visible := not(eoNoCaret in FOptions)
 
7184
    else
 
7185
      FScreenCaret.Visible := (eoPersistentCaret in FOptions) and not(eoNoCaret in FOptions);
 
7186
  end;
 
7187
  if (eoShowSpecialChars in ChangedOptions) then begin
 
7188
    if eoShowSpecialChars in FOptions
 
7189
    then FPaintArea.VisibleSpecialChars := VisibleSpecialChars
 
7190
    else FPaintArea.VisibleSpecialChars := [];
 
7191
    if HandleAllocated then
7391
7192
      Invalidate;
7392
 
 
7393
 
    (* Deal with deprecated values
7394
 
       Those are all controlled by mouse-actions.
7395
 
       As long as the default mouse actions are set, the below will act as normal
7396
 
    *)
7397
 
    // eoShowCtrlMouseLinks
7398
 
    if (eoShowCtrlMouseLinks in ChangedOptions) then begin
7399
 
      if (eoShowCtrlMouseLinks in fOptions) then begin
7400
 
        try
7401
 
          FMouseActions.AddCommand(emcMouseLink, False, mbLeft, ccSingle, cdUp, [SYNEDIT_LINK_MODIFIER], [ssShift, ssAlt, ssCtrl]);
7402
 
        except
7403
 
        end;
7404
 
      end else begin
7405
 
        for i := FMouseActions.Count-1 downto 0 do
7406
 
          if FMouseActions[i].Command = emcMouseLink then
7407
 
            FMouseActions.Delete(i);
7408
 
      end;
7409
 
      if assigned(fMarkupCtrlMouse) then
7410
 
        fMarkupCtrlMouse.UpdateCtrlMouse;
7411
 
      UpdateCursor;
7412
 
    end;
7413
 
    // eoDragDropEditing
7414
 
    if (eoDragDropEditing in ChangedOptions) then begin
7415
 
      if (eoDragDropEditing in fOptions) then begin
7416
 
        try
7417
 
          FMouseSelActions.AddCommand(emcStartDragMove, False, mbLeft, ccSingle, cdDown, [], []);
7418
 
        except
7419
 
        end;
7420
 
      end else begin
7421
 
        for i := FMouseActions.Count-1 downto 0 do
7422
 
          if FMouseActions[i].Command = emcStartDragMove then
7423
 
            FMouseActions.Delete(i);
7424
 
      end;
7425
 
    end;
7426
 
    // eoRightMouseMovesCursor
7427
 
    if (eoRightMouseMovesCursor in ChangedOptions) then begin
7428
 
      for i := FMouseActions.Count-1 downto 0 do
7429
 
        if FMouseActions[i].Button = mbRight then
7430
 
          FMouseActions[i].MoveCaret := (eoRightMouseMovesCursor in fOptions);
7431
 
    end;
7432
 
    // eoDoubleClickSelectsLine
7433
 
    if (eoDoubleClickSelectsLine in ChangedOptions) then begin
7434
 
      for i := FMouseActions.Count-1 downto 0 do
7435
 
        if (FMouseActions[i].Button = mbLeft) and
7436
 
           (FMouseActions[i].ClickCount = ccDouble) and
7437
 
           (FMouseActions[i].IsMatchingShiftState([])) and
7438
 
           ( (FMouseActions[i].Command = emcSelectWord) or
7439
 
             (FMouseActions[i].Command = emcSelectLine) )
7440
 
        then begin
7441
 
          if (eoDoubleClickSelectsLine in fOptions)
7442
 
          then FMouseActions[i].Command := emcSelectLine
7443
 
          else FMouseActions[i].Command := emcSelectWord;
7444
 
        end
7445
 
    end;
7446
 
    // eoAltSetsColumnMode
7447
 
    if (eoAltSetsColumnMode in ChangedOptions) then begin
7448
 
      if (eoAltSetsColumnMode in fOptions) then begin
7449
 
        try
7450
 
          FMouseActions.AddCommand(emcStartColumnSelections, True, mbLeft, ccSingle, cdDown, [ssAlt],          [ssShift, ssAlt], emcoSelectionStart);
7451
 
          FMouseActions.AddCommand(emcStartColumnSelections, True, mbLeft, ccSingle, cdDown, [ssShift, ssAlt], [ssShift, ssAlt], emcoSelectionContinue);
7452
 
        except
7453
 
        end;
7454
 
      end else begin
7455
 
        for i := FMouseActions.Count-1 downto 0 do
7456
 
          if FMouseActions[i].Command = emcStartColumnSelections then
7457
 
            FMouseActions.Delete(i);
7458
 
      end;
7459
 
    end;
7460
 
 
7461
 
  end;
 
7193
  end;
 
7194
  fMarkupSpecialChar.Enabled := (eoShowSpecialChars in fOptions);
 
7195
 
 
7196
  if (eoHideRightMargin in ChangedOptions) then begin
 
7197
    FPaintArea.RightEdgeVisible := not(eoHideRightMargin in FOptions);
 
7198
    Invalidate;
 
7199
  end;
 
7200
 
 
7201
  (* Deal with deprecated Mouse values
 
7202
     Those are all controlled by mouse-actions.
 
7203
     As long as the default mouse actions are set, the below will act as normal
 
7204
  *)
 
7205
 
 
7206
  MOpt := FMouseOptions;
 
7207
  f := False;
 
7208
  for m := low(SYNEDIT_OLD_MOUSE_OPTIONS_MAP) to high(SYNEDIT_OLD_MOUSE_OPTIONS_MAP) do
 
7209
    if (m in SYNEDIT_OLD_MOUSE_OPTIONS) and (m in ChangedOptions) then begin
 
7210
      f := True;
 
7211
      if (m in FOptions)
 
7212
      then MOpt := MOpt + [SYNEDIT_OLD_MOUSE_OPTIONS_MAP[m]]
 
7213
      else MOpt := MOpt - [SYNEDIT_OLD_MOUSE_OPTIONS_MAP[m]];
 
7214
    end;
 
7215
  if f then
 
7216
    MouseOptions := MOpt;
 
7217
 
 
7218
  FOptions := Value; // undo changes applied by MouseOptions
 
7219
 
7462
7220
end;
7463
7221
 
7464
7222
procedure TCustomSynEdit.UpdateOptions;
7491
7249
  FCaret.SkipTabs := (eoCaretSkipTab in fOptions2);
7492
7250
end;
7493
7251
 
 
7252
procedure TCustomSynEdit.SetMouseOptions(AValue: TSynEditorMouseOptions);
 
7253
var
 
7254
  ChangedOptions: TSynEditorMouseOptions;
 
7255
  m: TSynEditorOption;
 
7256
begin
 
7257
  if FMouseOptions = AValue then Exit;
 
7258
 
 
7259
  ChangedOptions := (FMouseOptions-AValue)+(AValue-FMouseOptions);
 
7260
  FMouseOptions := AValue;
 
7261
  // changes take effect when MouseActions are accessed
 
7262
 
 
7263
  for m := low(SYNEDIT_OLD_MOUSE_OPTIONS_MAP) to high(SYNEDIT_OLD_MOUSE_OPTIONS_MAP) do
 
7264
    if (m in SYNEDIT_OLD_MOUSE_OPTIONS) and
 
7265
       (SYNEDIT_OLD_MOUSE_OPTIONS_MAP[m] in ChangedOptions) and
 
7266
       not(SYNEDIT_OLD_MOUSE_OPTIONS_MAP[m] in FMouseOptions)
 
7267
    then
 
7268
      FOptions := FOptions - [m];
 
7269
 
 
7270
  if (emShowCtrlMouseLinks in ChangedOptions) then begin
 
7271
    if assigned(fMarkupCtrlMouse) then
 
7272
      fMarkupCtrlMouse.UpdateCtrlMouse;
 
7273
    UpdateCursor;
 
7274
  end;
 
7275
end;
 
7276
 
 
7277
procedure TCustomSynEdit.UpdateMouseOptions;
 
7278
begin
 
7279
  //
 
7280
end;
 
7281
 
7494
7282
procedure TCustomSynEdit.SetOptionFlag(Flag: TSynEditorOption; Value: boolean);
7495
7283
begin
7496
7284
  if (Value <> (Flag in fOptions)) then begin
7507
7295
    LastMouseCaret:=Point(-1,-1);
7508
7296
    RecalcCharsAndLinesInWin(False);
7509
7297
 
7510
 
    //DebugLn('TCustomSynEdit.SizeOrFontChanged fLinesInWindow=',dbgs(fLinesInWindow),' ClientHeight=',dbgs(ClientHeight),' ',dbgs(fTextHeight));
7511
 
    //debugln('TCustomSynEdit.SizeOrFontChanged A ClientWidth=',dbgs(ClientWidth),' FLeftGutter.Width=',dbgs(FLeftGutter.Width),' ScrollBarWidth=',dbgs(ScrollBarWidth),' fCharWidth=',dbgs(fCharWidth),' fCharsInWindow=',dbgs(fCharsInWindow),' Width=',dbgs(Width));
 
7298
    //DebugLn('TCustomSynEdit.SizeOrFontChanged LinesInWindow=',dbgs(LinesInWindow),' ClientHeight=',dbgs(ClientHeight),' ',dbgs(LineHeight));
 
7299
    //debugln('TCustomSynEdit.SizeOrFontChanged A ClientWidth=',dbgs(ClientWidth),' FLeftGutter.Width=',dbgs(FLeftGutter.Width),' ScrollBarWidth=',dbgs(ScrollBarWidth),' CharWidth=',dbgs(CharWidth),' CharsInWindow=',dbgs(CharsInWindow),' Width=',dbgs(Width));
7512
7300
    if bFont then begin
7513
7301
      UpdateScrollbars;
7514
7302
      Exclude(fStateFlags, sfCaretChanged);
7515
7303
      Invalidate;
7516
7304
    end else
7517
7305
      UpdateScrollbars;
7518
 
    Exclude(fStateFlags, sfScrollbarChanged);
7519
7306
    if not (eoScrollPastEol in Options) then
7520
7307
      LeftChar := LeftChar;
7521
7308
    if not (eoScrollPastEof in Options) then
7522
 
      TopLine := TopLine;
 
7309
      TopView := TopView;
7523
7310
  end;
7524
7311
end;
7525
7312
 
7526
7313
procedure TCustomSynEdit.RecalcCharsAndLinesInWin(CheckCaret: Boolean);
7527
7314
var
7528
 
  NewLinesInWindow: Integer;
7529
 
  w: Integer;
 
7315
  OldLinesInWindow: Integer;
 
7316
  l, r: Integer;
7530
7317
begin
7531
 
  w := ClientWidth - TextLeftPixelOffset - TextRightPixelOffset - ScrollBarWidth;
7532
 
  FCharsInWindow := Max(1, w div fCharWidth);
7533
 
 
7534
 
  NewLinesInWindow := Max(0,ClientHeight - ScrollBarWidth) div Max(1,fTextHeight);
7535
 
  if NewLinesInWindow <> FLinesInWindow then begin
7536
 
    FLinesInWindow := NewLinesInWindow;
7537
 
    FFoldedLinesView.LinesInWindow := fLinesInWindow;
7538
 
    FMarkupManager.LinesInWindow:= fLinesInWindow;
 
7318
  if FLeftGutter.Visible
 
7319
  then l := FLeftGutter.Width
 
7320
  else l := 0;
 
7321
  if FRightGutter.Visible
 
7322
  then r := FRightGutter.Width
 
7323
  else r := 0;
 
7324
 
 
7325
  OldLinesInWindow := FTextArea.LinesInWindow;
 
7326
 
 
7327
  // TODO: lock FTextArea, so size re-calc is done once only
 
7328
  FPaintArea.SetBounds(0, 0, ClientHeight - ScrollBarWidth, ClientWidth - ScrollBarWidth);
 
7329
  FPaintArea.LeftGutterWidth := l;
 
7330
  FPaintArea.RightGutterWidth := r;
 
7331
 
 
7332
  if FLeftGutter.Visible
 
7333
  then FPaintArea.Padding[bsLeft] := GutterTextDist
 
7334
  else FPaintArea.Padding[bsLeft] := 1;
 
7335
  if FRightGutter.Visible
 
7336
  then FPaintArea.Padding[bsRight] := 0 //GutterTextDist
 
7337
  else FPaintArea.Padding[bsRight] := 0;
 
7338
 
 
7339
  //CharsInWindow := Max(1, w div CharWidth);
 
7340
  if OldLinesInWindow <> FTextArea.LinesInWindow then
7539
7341
    StatusChanged([scLinesInWindow]);
7540
 
  end;
 
7342
 
 
7343
  FFoldedLinesView.LinesInWindow := LinesInWindow;
 
7344
  FMarkupManager.LinesInWindow := LinesInWindow;
7541
7345
 
7542
7346
  FScreenCaret.Lock;
7543
 
  FScreenCaret.ClipRect := Rect(TextLeftPixelOffset(False), 0,
7544
 
                                ClientWidth - TextRightPixelOffset - ScrollBarWidth + 1,
7545
 
                                ClientHeight - ScrollBarWidth);
7546
 
  FScreenCaret.ClipExtraPixel := w - fCharsInWindow * fCharWidth;
 
7347
  FScreenCaret.ClipRect := FTextArea.Bounds;
 
7348
  //FScreenCaret.ClipRect := Rect(TextLeftPixelOffset(False), 0,
 
7349
  //                              ClientWidth - TextRightPixelOffset - ScrollBarWidth + 1,
 
7350
  //                              ClientHeight - ScrollBarWidth);
 
7351
  FScreenCaret.ClipExtraPixel := FTextArea.Bounds.Right - FTextArea.Bounds.Left - CharsInWindow * CharWidth;
 
7352
  UpdateCaret;
7547
7353
  FScreenCaret.UnLock;
7548
7354
 
7549
7355
  if CheckCaret then begin
7550
7356
    if not (eoScrollPastEol in Options) then
7551
7357
      LeftChar := LeftChar;
7552
7358
    if not (eoScrollPastEof in Options) then
7553
 
      TopLine := TopLine;
 
7359
      TopView := TopView;
7554
7360
  end;
7555
7361
end;
7556
7362
 
7620
7426
  SetBlockEnd(ptAfter);
7621
7427
  if Mode <> smCurrent then
7622
7428
    FBlockSelection.ActiveSelectionMode := Mode;
7623
 
  AquirePrimarySelection;
7624
7429
 
7625
7430
  if MakeSelectionVisible then begin
7626
7431
    //l1 := FBlockSelection.FirstLineBytePos;;
7669
7474
var
7670
7475
  i: Integer;
7671
7476
begin
 
7477
  (* Highlighter or Font changed *)
 
7478
 
7672
7479
  FFontDummy.Assign(Font);
7673
7480
  with FFontDummy do begin
7674
7481
    // Keep GTK happy => By ensuring a change the XFLD fontname gets cleared
 
7482
    {$IFDEF LCLGTK1}
7675
7483
    Pitch := fpVariable;
7676
7484
    Style := [fsBold];
7677
7485
    Pitch := fpDefault; // maybe Fixed
 
7486
    {$ENDIF}
7678
7487
    // TODO: Clear style only, if Highlighter uses styles
7679
7488
    Style := [];        // Reserved for Highlighter
7680
7489
  end;
7681
7490
  //debugln(['TCustomSynEdit.RecalcCharExtent ',fFontDummy.Name,' ',fFontDummy.Size]);
7682
 
  with fTextDrawer do begin
7683
 
    //debugln('TCustomSynEdit.RecalcCharExtent A UseUTF8=',dbgs(UseUTF8),
7684
 
    //  ' Font.CanUTF8='+dbgs(Font.CanUTF8)+' CharHeight=',dbgs(CharHeight));
7685
 
    BaseFont := FFontDummy;
7686
 
 
7687
 
    if Assigned(fHighlighter) then
7688
 
      for i := 0 to Pred(fHighlighter.AttrCount) do
7689
 
        BaseStyle := fHighlighter.Attribute[i].Style;
7690
 
 
7691
 
    CharExtra := fExtraCharSpacing;
7692
 
    fTextHeight := CharHeight + fExtraLineSpacing;
7693
 
    fCharWidth := CharWidth;
7694
 
    FScreenCaret.Lock;
7695
 
    FScreenCaret.CharWidth := fCharWidth;
7696
 
    FScreenCaret.CharHeight := fTextHeight;
7697
 
    FScreenCaret.UnLock;
7698
 
  end;
7699
 
  {$IFDEF SYN_LAZARUS}
 
7491
  //debugln('TCustomSynEdit.RecalcCharExtent A UseUTF8=',dbgs(UseUTF8),
 
7492
  //  ' Font.CanUTF8='+dbgs(Font.CanUTF8)+' CharHeight=',dbgs(CharHeight));
 
7493
 
 
7494
  fTextDrawer.BaseFont := FFontDummy;
 
7495
  if Assigned(fHighlighter) then
 
7496
    for i := 0 to Pred(fHighlighter.AttrCount) do
 
7497
      fTextDrawer.BaseStyle := fHighlighter.Attribute[i].Style;
 
7498
  fTextDrawer.CharExtra := fExtraCharSpacing;
 
7499
 
7700
7500
  FUseUTF8:=fTextDrawer.UseUTF8;
7701
7501
  FLines.IsUtf8 := FUseUTF8;
 
7502
 
 
7503
  FScreenCaret.Lock;
 
7504
  try
 
7505
    FScreenCaret.CharWidth := CharWidth;
 
7506
    FScreenCaret.CharHeight := LineHeight - Max(0, ExtraLineSpacing);
 
7507
    SizeOrFontChanged(TRUE);
 
7508
  finally
 
7509
    FScreenCaret.UnLock;
 
7510
  end;
 
7511
  UpdateScrollBars;
7702
7512
  //debugln('TCustomSynEdit.RecalcCharExtent UseUTF8=',dbgs(UseUTF8),' Font.CanUTF8=',dbgs(Font.CanUTF8));
7703
 
  {$ENDIF}
7704
7513
end;
7705
7514
 
7706
7515
procedure TCustomSynEdit.HighlighterAttrChanged(Sender: TObject);
7707
7516
begin
7708
7517
  RecalcCharExtent;
7709
 
  SizeOrFontChanged(TRUE);                                                      //jr 2000-10-01
7710
7518
  Invalidate;
7711
7519
  // TODO: obey paintlock
7712
7520
  if fHighlighter.AttributeChangeNeedScan then begin
7713
7521
    FHighlighter.CurrentLines := FTheLinesView;
7714
7522
    FHighlighter.ScanAllRanges;
7715
7523
    fMarkupManager.TextChanged(0, FTheLinesView.Count - 1);
7716
 
    TopLine := TopLine;
 
7524
    TopView := TopView;
7717
7525
  end;
7718
7526
end;
7719
7527
 
7796
7604
    {$ELSE}
7797
7605
    DragAcceptFiles(Handle, TRUE);
7798
7606
    {$ENDIF}
7799
 
  {$IFDEF SYN_LAZARUS}
7800
7607
  SizeOrFontChanged(true);
7801
 
  {$ENDIF}
7802
7608
end;
7803
7609
 
7804
7610
procedure TCustomSynEdit.DestroyWnd;
7823
7629
  BB,BE            : TPoint;
7824
7630
  Line : PChar;
7825
7631
  Len, e, y: integer;
7826
 
  Spaces: String;
 
7632
  Spaces, Tabs: String;
7827
7633
 
7828
7634
  function GetLeadWSLen : integer;
7829
7635
  var
7843
7649
    if not SelAvail then begin
7844
7650
      BB := CaretXY;
7845
7651
      BE := CaretXY;
 
7652
      e := BE.y;
7846
7653
    end else begin
7847
7654
      BB := BlockBegin;
7848
7655
      BE := BlockEnd;
 
7656
      if (BE.X = 1)
 
7657
      then e := BE.y - 1
 
7658
      else e := BE.y;
7849
7659
    end;
7850
 
    if (BE.X = 1) then
7851
 
      e := BE.y - 1
7852
 
    else
7853
 
      e := BE.y;
7854
7660
 
7855
 
    Spaces := StringOfChar(#32, fBlockIndent);
 
7661
    Spaces := StringOfChar(#32, FBlockIndent);
 
7662
    Tabs   := StringOfChar( #9, FBlockTabIndent);
7856
7663
    fUndoList.Lock;
7857
7664
    fRedoList.Lock;
7858
7665
    try
7861
7668
        Line := PChar(FTheLinesView[y - 1]);
7862
7669
        Len := GetLeadWSLen;
7863
7670
        FTheLinesView.EditInsert(Len + 1, y, Spaces);
 
7671
        FTheLinesView.EditInsert(1,       y, Tabs);
7864
7672
      end;
7865
7673
    finally
7866
7674
      fUndoList.Unlock;
7867
7675
      fRedoList.Unlock;
7868
7676
    end;
7869
7677
 
7870
 
    fUndoList.AddChange(TSynEditUndoIndent.Create(BB.Y, e, fBlockIndent));
 
7678
    fUndoList.AddChange(TSynEditUndoIndent.Create(BB.Y, e, FBlockIndent, FBlockTabIndent));
7871
7679
  finally
7872
7680
    FTrimmedLinesView.ForceTrim; // Otherwise it may reset the block
7873
7681
    FCaret.LineBytePos := FBlockSelection.EndLineBytePos;
7884
7692
  FullStrToDelete: PChar;
7885
7693
  Line: PChar;
7886
7694
  Len, LogP1, PhyP1, LogP2, PhyP2, y, StrToDeleteLen, e : integer;
 
7695
  i, i2, j: Integer;
7887
7696
  SomethingDeleted : Boolean;
7888
7697
  HasTab: Boolean;
7889
7698
 
7904
7713
  if not SelAvail then begin
7905
7714
    BB := CaretXY;
7906
7715
    BE := CaretXY;
 
7716
    e := BE.y;
7907
7717
  end else begin
7908
7718
    BB := BlockBegin;
7909
7719
    BE := BlockEnd;
 
7720
    // convert selection to complete lines
 
7721
    if BE.X = 1 then
 
7722
      e := BE.y - 1
 
7723
    else
 
7724
      e := BE.y;
7910
7725
  end;
7911
 
  // convert selection to complete lines
7912
 
  if BE.X = 1 then
7913
 
    e := BE.y - 1
7914
 
  else
7915
 
    e := BE.y;
7916
7726
 
7917
7727
  IncPaintLock;
7918
7728
  FBlockSelection.IncPersistentLock;
7968
7778
      if LogP1 - LogP2 > 0 then
7969
7779
        FTheLinesView.EditDelete(LogP2, y, LogP1 - LogP2);
7970
7780
      SomethingDeleted := SomethingDeleted or (LogP1 - LogP2 > 0);
 
7781
 
 
7782
      // Todo: create FullTabStrToDelete for tabs
 
7783
      fUndoList.Unlock;
 
7784
      fRedoList.Unlock;
 
7785
      Line := PChar(FTheLinesView[y - 1]);
 
7786
      j := 0;
 
7787
      for i := 1 to FBlockTabIndent do begin
 
7788
        i2 := fTabWidth;
 
7789
        while (i2 > 0) and (Line[j] = #32) do begin
 
7790
          dec(i2);
 
7791
          inc(j);
 
7792
        end;
 
7793
        if (i2 > 0) and (Line[j] = #9) then inc(j);
 
7794
      end;
 
7795
      if j > 0 then
 
7796
        FTheLinesView.EditDelete(1, y, j);
 
7797
      fUndoList.Lock;
 
7798
      fRedoList.Lock;
 
7799
 
7971
7800
    end;
7972
7801
 
7973
7802
    fUndoList.Unlock;
8121
7950
    Result := Focused;
8122
7951
    if Result then
8123
7952
    begin
8124
 
      if (TheAction is TEditCut) or (TheAction is TEditCopy) then
 
7953
      if (TheAction is TEditCut) then
 
7954
        TEditAction(TheAction).Enabled := SelAvail and (not ReadOnly)
 
7955
      else if (TheAction is TEditCopy) then
8125
7956
        TEditAction(TheAction).Enabled := SelAvail
8126
7957
      else if TheAction is TEditPaste then
8127
 
        TEditAction(TheAction).Enabled := CanPaste
 
7958
        TEditAction(TheAction).Enabled := CanPaste and (not ReadOnly)
8128
7959
{$IFDEF SYN_COMPILER_5_UP}
8129
7960
      else if TheAction is TEditDelete then
8130
 
        TEditAction(TheAction).Enabled := TRUE
 
7961
        TEditAction(TheAction).Enabled := (not ReadOnly)
8131
7962
      else if TheAction is TEditUndo then
8132
 
        TEditAction(TheAction).Enabled := CanUndo
 
7963
        TEditAction(TheAction).Enabled := CanUndo and (not ReadOnly)
8133
7964
      else if TheAction is TEditSelectAll then
8134
7965
        TEditAction(TheAction).Enabled := TRUE;
8135
7966
{$ENDIF}
8144
7975
  TSynEditStringList(FLines).Modified := Value;
8145
7976
end;
8146
7977
 
8147
 
{$IFNDEF SYN_LAZARUS}
8148
 
function TCustomSynEdit.DoOnSpecialLineColors(Line: integer; var Foreground,
8149
 
  Background: TColor): boolean;
8150
 
begin
8151
 
  Result := FALSE;
8152
 
  if Assigned(fOnSpecialLineColors) then
8153
 
    fOnSpecialLineColors(Self, Line, Result, Foreground, Background);
8154
 
end;
8155
 
{$ENDIF}
8156
 
 
8157
7978
procedure TCustomSynEdit.InvalidateLine(Line: integer);
8158
7979
begin
8159
7980
  InvalidateLines(Line, Line);
8174
7995
end;
8175
7996
 
8176
7997
procedure TCustomSynEdit.FindMatchingBracket;
8177
 
{$IFDEF SYN_LAZARUS}
8178
 
{$ELSE}
8179
 
const
8180
 
  Brackets: array[0..5] of char = ('(', ')', '[', ']', '{', '}');
8181
 
var
8182
 
  Line: string;
8183
 
  i, PosX, PosY, Len: integer;
8184
 
  Test, BracketInc, BracketDec: char;
8185
 
  NumBrackets: integer;
8186
 
{$ENDIF}
8187
7998
begin
8188
 
  {$IFDEF SYN_LAZARUS}
8189
7999
  FindMatchingBracket(CaretXY,false,true,false,false);
8190
 
  {$ELSE}
8191
 
  // get char at caret
8192
 
  PosX := CaretX;
8193
 
  PosY := CaretY;
8194
 
  Line := LineText;
8195
 
  if Length(Line) >= PosX then begin
8196
 
    Test := Line[PosX];
8197
 
    // is it one of the recognized brackets?
8198
 
    for i := Low(Brackets) to High(Brackets) do
8199
 
      if Test = Brackets[i] then begin
8200
 
        // this is the bracket, get the matching one and the direction
8201
 
        BracketInc := Brackets[i];
8202
 
        BracketDec := Brackets[i xor 1]; // 0 -> 1, 1 -> 0, ...
8203
 
        // search for the matching bracket (that is until NumBrackets = 0)
8204
 
        NumBrackets := 1;
8205
 
        if Odd(i) then begin
8206
 
          // closing bracket -> search opening bracket
8207
 
          repeat
8208
 
            // search until start of line
8209
 
            while PosX > 1 do begin
8210
 
              Dec(PosX);
8211
 
              Test := Line[PosX];
8212
 
              if Test = BracketInc then
8213
 
                Inc(NumBrackets)
8214
 
              else if Test = BracketDec then begin
8215
 
                Dec(NumBrackets);
8216
 
                if NumBrackets = 0 then begin
8217
 
                  // matching bracket found, set caret and bail out
8218
 
                  CaretXY := Point(PosX, PosY);
8219
 
                  exit;
8220
 
                end;
8221
 
              end;
8222
 
            end;
8223
 
            // get previous line if possible
8224
 
            if PosY = 1 then break;
8225
 
            Dec(PosY);
8226
 
            Line := Lines[PosY - 1];
8227
 
            PosX := Length(Line) + 1;
8228
 
          until FALSE;
8229
 
        end else begin
8230
 
          // opening bracket -> search closing bracket
8231
 
          repeat
8232
 
            // search until end of line
8233
 
            Len := Length(Line);
8234
 
            while PosX < Len do begin
8235
 
              Inc(PosX);
8236
 
              Test := Line[PosX];
8237
 
              if Test = BracketInc then
8238
 
                Inc(NumBrackets)
8239
 
              else if Test = BracketDec then begin
8240
 
                Dec(NumBrackets);
8241
 
                if NumBrackets = 0 then begin
8242
 
                  // matching bracket found, set caret and bail out
8243
 
                  CaretXY := Point(PosX, PosY);
8244
 
                  exit;
8245
 
                end;
8246
 
              end;
8247
 
            end;
8248
 
            // get next line if possible
8249
 
            if PosY = Lines.Count then break;
8250
 
            Inc(PosY);
8251
 
            Line := Lines[PosY - 1];
8252
 
            PosX := 0;
8253
 
          until FALSE;
8254
 
        end;
8255
 
        // don't test the other brackets, we're done
8256
 
        break;
8257
 
      end;
8258
 
  end;
8259
 
  {$ENDIF}
8260
8000
end;
8261
8001
 
8262
8002
function TCustomSynEdit.FindMatchingBracket(PhysStartBracket: TPoint;
8303
8043
        fHighlighter.Next;
8304
8044
      i := TokenListCnt;
8305
8045
      while not fHighlighter.GetEol do begin
 
8046
        if i >= l then begin
 
8047
          l := l * 4;
 
8048
          SetLength(TokenPosList, l);
 
8049
        end;
8306
8050
        TokenPosList[i].X := fHighlighter.GetTokenPos + 1;
8307
8051
        TokenPosList[i].Attr := fHighlighter.GetTokenKind;
8308
8052
        if TokenPosList[i].X > PosX then begin
8312
8056
          exit;
8313
8057
        end;
8314
8058
        inc(i);
8315
 
        if i >= l then begin
8316
 
          l := l * 4;
8317
 
          SetLength(TokenPosList, l);
8318
 
        end;
8319
8059
        fHighlighter.Next;
8320
8060
      end;
8321
 
      MaxKnownTokenPos := Length(Line);
 
8061
      MaxKnownTokenPos := Length(Line) + 1;             // 1 based end+1 of last token (start pos of none existing after eol token)
 
8062
      if i >= l then begin
 
8063
        l := l * 4;
 
8064
        SetLength(TokenPosList, l);
 
8065
      end;
8322
8066
      TokenPosList[i].X := MaxKnownTokenPos;
8323
8067
      TokenListCnt := i + 1;
8324
8068
      Result := TokenPosList[i-1].Attr = BracketKind;
8356
8100
  procedure DoFindMatchingQuote(q: char);
8357
8101
  var
8358
8102
    Test: char;
8359
 
    Len: integer;
 
8103
    Len, PrevPosX, PrevCnt: integer;
8360
8104
  begin
8361
8105
    StartPt:=Point(PosX,PosY);
8362
8106
    GetHighlighterAttriAtRowColEx(StartPt, s1, BracketKind, TmpStart, TmpAttr);
8363
 
    if (TmpStart = PosX) and (Length(s1)>0) and (s1[Length(s1)] = q) then begin
 
8107
    // Checck if we have a complete token, e.g. Highlightec returned entire "string"
 
8108
    if (TmpStart = PosX) and (Length(s1)>1) and (s1[Length(s1)] = q) then begin
8364
8109
      PosX := PosX + Length(s1) - 1;
8365
8110
      DoMatchingBracketFound;
8366
8111
      exit;
8367
8112
    end;
8368
 
    if (TmpStart + Length(s1) - 1 = PosX) and (Length(s1)>0) and (s1[1] = q) then begin
 
8113
    if (TmpStart + Length(s1) - 1 = PosX) and (Length(s1)>1) and (s1[1] = q) then begin
8369
8114
      PosX := PosX - Length(s1) + 1;
8370
8115
      DoMatchingBracketFound;
8371
8116
      exit;
8372
8117
    end;
 
8118
 
8373
8119
    MaxKnownTokenPos := 0;
8374
8120
    Len := PosX;
 
8121
    PrevPosX := -1;
 
8122
    PrevCnt := 0;
8375
8123
    // search until start of line
8376
 
    while PosX > 1 do begin
 
8124
     while PosX > 1 do begin
8377
8125
      Dec(PosX);
8378
8126
      Test := Line[PosX];
8379
8127
      if (Test = q) and IsContextBracket then begin
8380
 
        DoMatchingBracketFound;
8381
 
        exit;
 
8128
        inc(PrevCnt);
 
8129
        if PrevPosX < 0 then PrevPosX := PosX;
8382
8130
      end;
8383
8131
    end;
 
8132
    // 1st, 3rd, 5th, ... are opening
 
8133
    if (PrevPosX > 0) and (PrevCnt mod 2 = 1) then begin
 
8134
      PosX := PrevPosX;
 
8135
      DoMatchingBracketFound;
 
8136
      exit;
 
8137
    end;
 
8138
 
8384
8139
    PosX := Len;
8385
8140
    Len := Length(Line);
8386
8141
    while PosX < Len do begin
8391
8146
        exit;
8392
8147
      end;
8393
8148
    end;
 
8149
 
 
8150
    if (PrevPosX > 0) then begin
 
8151
      PosX := PrevPosX;
 
8152
      DoMatchingBracketFound;
 
8153
      exit;
 
8154
    end;
8394
8155
  end;
8395
8156
 
8396
8157
  procedure DoFindMatchingBracket(i: integer);
8528
8289
 
8529
8290
                                                                                 //L505 begin
8530
8291
function TCustomSynEdit.GetHighlighterAttriAtRowCol(XY: TPoint;
8531
 
  var Token: string; var Attri: TSynHighlighterAttributes): boolean;
 
8292
  out Token: string; out Attri: TSynHighlighterAttributes): boolean;
8532
8293
var
8533
8294
  TmpType, TmpStart: Integer;
8534
8295
begin
8536
8297
end;
8537
8298
 
8538
8299
function TCustomSynEdit.GetHighlighterAttriAtRowColEx(XY: TPoint;
8539
 
  var Token: string; var TokenType, Start: Integer;
8540
 
  var Attri: TSynHighlighterAttributes): boolean;
 
8300
  out Token: string; out TokenType, Start: Integer;
 
8301
  out Attri: TSynHighlighterAttributes): boolean;
8541
8302
var
8542
8303
  PosX, PosY: integer;
8543
8304
  Line: string;
8579
8340
  Result:=(length(c)=1) and (c[1] in IdentChars);
8580
8341
end;
8581
8342
 
8582
 
procedure TCustomSynEdit.GetWordBoundsAtRowCol(const XY: TPoint; var StartX,
 
8343
procedure TCustomSynEdit.GetWordBoundsAtRowCol(const XY: TPoint; out StartX,
8583
8344
  EndX: integer); // all params are logical (byte) positions
8584
8345
var
8585
8346
  Line: string;
8703
8464
    Result := 0;
8704
8465
end;
8705
8466
 
8706
 
procedure TCustomSynEdit.RegisterCommandHandler(AHandlerProc:
8707
 
  THookedCommandEvent; AHandlerData: pointer);
 
8467
procedure TCustomSynEdit.RegisterCommandHandler(AHandlerProc: THookedCommandEvent;
 
8468
  AHandlerData: pointer; AFlags: THookedCommandFlags);
8708
8469
begin
8709
8470
  if not Assigned(AHandlerProc) then begin
8710
8471
{$IFDEF SYN_DEVELOPMENT_CHECKS}
8716
8477
    fHookedCommandHandlers := TList.Create;
8717
8478
  if FindHookedCmdEvent(AHandlerProc) = -1 then
8718
8479
    fHookedCommandHandlers.Add(THookedCommandHandlerEntry.Create(
8719
 
      AHandlerProc, AHandlerData))
 
8480
      AHandlerProc, AHandlerData, AFlags))
8720
8481
  else
8721
8482
{$IFDEF SYN_DEVELOPMENT_CHECKS}
8722
8483
    raise Exception.CreateFmt('Event handler (%p, %p) already registered',
8787
8548
  TSynStatusChangedHandlerList(FStatusChangedList).Remove(AStatusChangeProc);
8788
8549
end;
8789
8550
 
8790
 
procedure TCustomSynEdit.NotifyHookedCommandHandlers(AfterProcessing: boolean;
8791
 
  var Command: TSynEditorCommand;
8792
 
  var AChar: TUTF8Char; Data: pointer);
 
8551
procedure TCustomSynEdit.RegisterBeforeMouseDownHandler(AHandlerProc: TMouseEvent);
 
8552
begin
 
8553
  if FMouseDownEventList = nil then
 
8554
    FMouseDownEventList := TLazSynMouseDownEventList.Create;
 
8555
  FMouseDownEventList.Add(TMethod(AHandlerProc));
 
8556
end;
 
8557
 
 
8558
procedure TCustomSynEdit.UnregisterBeforeMouseDownHandler(AHandlerProc: TMouseEvent);
 
8559
begin
 
8560
  if FMouseDownEventList <> nil then
 
8561
    FMouseDownEventList.Remove(TMethod(AHandlerProc));
 
8562
end;
 
8563
 
 
8564
procedure TCustomSynEdit.RegisterBeforeKeyDownHandler(AHandlerProc: TKeyEvent);
 
8565
begin
 
8566
  if FKeyDownEventList = nil then
 
8567
    FKeyDownEventList := TLazSynKeyDownEventList.Create;
 
8568
  FKeyDownEventList.Add(TMethod(AHandlerProc));
 
8569
end;
 
8570
 
 
8571
procedure TCustomSynEdit.UnregisterBeforeKeyDownHandler(AHandlerProc: TKeyEvent);
 
8572
begin
 
8573
  if FKeyDownEventList <> nil then
 
8574
    FKeyDownEventList.Remove(TMethod(AHandlerProc));
 
8575
end;
 
8576
 
 
8577
procedure TCustomSynEdit.RegisterBeforeKeyPressHandler(AHandlerProc: TKeyPressEvent);
 
8578
begin
 
8579
  if FKeyPressEventList = nil then
 
8580
    FKeyPressEventList := TLazSynKeyPressEventList.Create;
 
8581
  FKeyPressEventList.Add(TMethod(AHandlerProc));
 
8582
end;
 
8583
 
 
8584
procedure TCustomSynEdit.UnregisterBeforeKeyPressHandler(AHandlerProc: TKeyPressEvent);
 
8585
begin
 
8586
  if FKeyPressEventList <> nil then
 
8587
    FKeyPressEventList.Remove(TMethod(AHandlerProc));
 
8588
end;
 
8589
 
 
8590
procedure TCustomSynEdit.RegisterBeforeUtf8KeyPressHandler(AHandlerProc: TUTF8KeyPressEvent);
 
8591
begin
 
8592
  if FUtf8KeyPressEventList = nil then
 
8593
    FUtf8KeyPressEventList := TLazSynUtf8KeyPressEventList.Create;
 
8594
  FUtf8KeyPressEventList.Add(TMethod(AHandlerProc));
 
8595
end;
 
8596
 
 
8597
procedure TCustomSynEdit.UnregisterBeforeUtf8KeyPressHandler(AHandlerProc: TUTF8KeyPressEvent);
 
8598
begin
 
8599
  if FUtf8KeyPressEventList <> nil then
 
8600
    FUtf8KeyPressEventList.Remove(TMethod(AHandlerProc));
 
8601
end;
 
8602
 
 
8603
procedure TCustomSynEdit.NotifyHookedCommandHandlers(var Command: TSynEditorCommand;
 
8604
  var AChar: TUTF8Char; Data: pointer; ATime: THookedCommandFlag);
8793
8605
var
8794
8606
  Handled: boolean;
8795
8607
  i: integer;
8798
8610
  Handled := FALSE;
8799
8611
  for i := 0 to GetHookedCommandHandlersCount - 1 do begin
8800
8612
    Entry := THookedCommandHandlerEntry(fHookedCommandHandlers[i]);
 
8613
    if not(ATime in Entry.FFlags) then continue;
8801
8614
    // NOTE: Command should NOT be set to ecNone, because this might interfere
8802
8615
    // with other handlers.  Set Handled to False instead (and check its value
8803
8616
    // to not process the command twice).
8804
 
    Entry.fEvent(Self, AfterProcessing, Handled, Command, AChar, Data,
 
8617
    Entry.fEvent(Self, ATime in [hcfPostExec, hcfFinish], Handled, Command, AChar, Data,
8805
8618
      Entry.fData);
8806
8619
  end;
8807
8620
  if Handled then
8828
8641
procedure TCustomSynEdit.DoOnStatusChange(Changes: TSynStatusChanges);
8829
8642
begin
8830
8643
  TSynStatusChangedHandlerList(FStatusChangedList).CallStatusChangedHandlers(Self, Changes);
8831
 
  if Assigned(fOnStatusChange) then begin
 
8644
  if Assigned(fOnStatusChange) then
8832
8645
    fOnStatusChange(Self, fStatusChanges);
8833
 
    fStatusChanges := [];
8834
 
  end;
 
8646
  fStatusChanges := [];
8835
8647
end;
8836
8648
 
8837
8649
procedure TCustomSynEdit.UndoRedoAdded(Sender: TObject);
8879
8691
 
8880
8692
function TCustomSynEdit.ScreenColumnToXValue(Col : integer) : integer;
8881
8693
begin
8882
 
  Result := fTextOffset + Pred(Col) * fCharWidth;
 
8694
  Result := FTextArea.ScreenColumnToXValue(Col);
8883
8695
end;
8884
8696
 
8885
8697
procedure TCustomSynEdit.PrimarySelectionRequest(
8916
8728
  end;
8917
8729
end;
8918
8730
 
8919
 
{ TSynEditPlugin }
 
8731
{ TLazSynEditPlugin }
8920
8732
 
8921
 
constructor TSynEditPlugin.Create(AOwner: TComponent);
 
8733
constructor TLazSynEditPlugin.Create(AOwner: TComponent);
8922
8734
begin
8923
8735
  if AOwner is TCustomSynEdit then begin
8924
8736
    inherited Create(nil);
8928
8740
    inherited Create(AOwner);
8929
8741
end;
8930
8742
 
8931
 
destructor TSynEditPlugin.Destroy;
 
8743
destructor TLazSynEditPlugin.Destroy;
8932
8744
begin
8933
8745
  Editor := nil;
8934
8746
  inherited Destroy;
8935
8747
end;
8936
8748
 
8937
 
procedure TSynEditPlugin.SetEditor(const AValue: TCustomSynEdit);
 
8749
procedure TLazSynEditPlugin.BeforeEditorChange;
 
8750
begin
 
8751
  if (Editor <> nil) then begin
 
8752
    DoEditorRemoving(Editor);
 
8753
    UnRegisterFromEditor(Editor);
 
8754
  end;
 
8755
end;
 
8756
 
 
8757
procedure TLazSynEditPlugin.AfterEditorChange;
 
8758
begin
 
8759
  if Editor <> nil then begin
 
8760
    RegisterToEditor(Editor);
 
8761
    DoEditorAdded(Editor);
 
8762
  end;
 
8763
end;
 
8764
 
 
8765
procedure TLazSynEditPlugin.RegisterToEditor(AValue: TCustomSynEdit);
 
8766
begin
 
8767
  if AValue.fPlugins <> nil then
 
8768
    AValue.fPlugins.Add(Self);
 
8769
end;
 
8770
 
 
8771
procedure TLazSynEditPlugin.UnRegisterFromEditor(AValue: TCustomSynEdit);
 
8772
begin
 
8773
  if AValue.fPlugins <> nil then
 
8774
    AValue.fPlugins.Remove(Self);
 
8775
end;
 
8776
 
 
8777
procedure TLazSynEditPlugin.SetEditor(const AValue: TCustomSynEdit);
8938
8778
begin
8939
8779
  if AValue = FriendEdit then exit;
8940
 
  if (FriendEdit <> nil) and (Editor.fPlugins <> nil) then
8941
 
    Editor.fPlugins.Remove(Self);
 
8780
 
 
8781
  BeforeEditorChange;
8942
8782
  FriendEdit := AValue;
8943
 
  if FriendEdit <> nil then
8944
 
    Editor.fPlugins.Add(Self);
 
8783
  AfterEditorChange;
8945
8784
end;
8946
8785
 
8947
 
function TSynEditPlugin.GetEditor: TCustomSynEdit;
 
8786
function TLazSynEditPlugin.GetEditor: TCustomSynEdit;
8948
8787
begin
8949
 
  Result := FriendEdit as TSynEdit;
 
8788
  Result := FriendEdit as TCustomSynEdit;
8950
8789
end;
8951
8790
 
8952
 
function TSynEditPlugin.OwnedByEditor: Boolean;
 
8791
function TLazSynEditPlugin.OwnedByEditor: Boolean;
8953
8792
begin
8954
8793
  Result := Owner = nil;
8955
8794
end;
8956
8795
 
 
8796
procedure TLazSynEditPlugin.DoEditorDestroyed(const AValue: TCustomSynEdit);
 
8797
begin
 
8798
  if Editor <> AValue then exit;
 
8799
  if OwnedByEditor then
 
8800
    Free
 
8801
  else
 
8802
    Editor := nil;
 
8803
end;
 
8804
 
 
8805
procedure TLazSynEditPlugin.DoEditorAdded(AValue: TCustomSynEdit);
 
8806
begin
 
8807
  //
 
8808
end;
 
8809
 
 
8810
procedure TLazSynEditPlugin.DoEditorRemoving(AValue: TCustomSynEdit);
 
8811
begin
 
8812
  //
 
8813
end;
 
8814
 
8957
8815
procedure Register;
8958
8816
begin
8959
8817
  RegisterClasses([TSynGutterPartList, TSynRightGutterPartList,
8991
8849
var
8992
8850
  i: Integer;
8993
8851
begin
8994
 
  // Finish Combo ?
8995
 
  for i := 0 to Count - 1 do
8996
 
    THookedKeyTranslationEvent(Items[i])(Sender, Code, SState, Data,
8997
 
      IsStartOfCombo, Handled, Command, True, ComboKeyStrokes);
8998
 
  if Handled then
8999
 
    exit;
9000
 
  // New Stroke ?
9001
 
  for i := 0 to Count - 1 do
9002
 
    THookedKeyTranslationEvent(Items[i])(Sender, Code, SState, Data,
9003
 
      IsStartOfCombo, Handled, Command, False, ComboKeyStrokes);
 
8852
  if ComboKeyStrokes <> nil then begin
 
8853
    // Finish Combo
 
8854
    for i := 0 to Count - 1 do
 
8855
      THookedKeyTranslationEvent(Items[i])(Sender, Code, SState, Data,
 
8856
        IsStartOfCombo, Handled, Command, True, ComboKeyStrokes);
 
8857
  end
 
8858
  else begin
 
8859
    // New Stroke
 
8860
    for i := 0 to Count - 1 do
 
8861
      THookedKeyTranslationEvent(Items[i])(Sender, Code, SState, Data,
 
8862
        IsStartOfCombo, Handled, Command, False, ComboKeyStrokes);
 
8863
  end;
 
8864
end;
 
8865
 
 
8866
{ TLazSynUtf8KeyPressEventList }
 
8867
 
 
8868
procedure TLazSynUtf8KeyPressEventList.CallUtf8KeyPressHandlers(Sender: TObject;
 
8869
  var UTF8Key: TUTF8Char);
 
8870
var
 
8871
  i: LongInt;
 
8872
begin
 
8873
  i:=Count;
 
8874
  while NextDownIndex(i) do
 
8875
    TUTF8KeyPressEvent(Items[i])(Sender, UTF8Key);
 
8876
end;
 
8877
 
 
8878
{ TLazSynKeyPressEventList }
 
8879
 
 
8880
procedure TLazSynKeyPressEventList.CallKeyPressHandlers(Sender: TObject; var Key: char);
 
8881
var
 
8882
  i: LongInt;
 
8883
begin
 
8884
  i:=Count;
 
8885
  while NextDownIndex(i) do
 
8886
    TKeyPressEvent(Items[i])(Sender, Key);
 
8887
end;
 
8888
 
 
8889
{ TLazSynMouseDownEventList }
 
8890
 
 
8891
procedure TLazSynMouseDownEventList.CallMouseDownHandlers(Sender: TObject;
 
8892
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
 
8893
var
 
8894
  i: LongInt;
 
8895
begin
 
8896
  i:=Count;
 
8897
  while NextDownIndex(i) do
 
8898
    TMouseEvent(Items[i])(Sender, Button, Shift, X, Y);
 
8899
end;
 
8900
 
 
8901
{ TLazSynKeyDownEventList }
 
8902
 
 
8903
procedure TLazSynKeyDownEventList.CallKeyDownHandlers(Sender: TObject; var Key: Word;
 
8904
  Shift: TShiftState);
 
8905
var
 
8906
  i: LongInt;
 
8907
begin
 
8908
  i:=Count;
 
8909
  while NextDownIndex(i) do
 
8910
    TKeyEvent(Items[i])(Sender, Key, Shift);
9004
8911
end;
9005
8912
 
9006
8913
{ TSynStatusChangedHandlerList }