git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.jvcl@19 7f62d464-2af8-f54e-996c-e91b33f51cbe
6567 lines
189 KiB
ObjectPascal
6567 lines
189 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: JvEditorCommon.PAS, released on 2004-01-25
|
|
|
|
The Initial Developers of the Original Code are: Andrei Prygounkov <a dott prygounkov att gmx dott de>
|
|
Copyright (c) 1999, 2002 Andrei Prygounkov
|
|
All Rights Reserved.
|
|
|
|
Contributor(s):
|
|
Burov Dmitry, translation of russian text.
|
|
Andreas Hausladen
|
|
Peter Thörnqvist
|
|
Remko Bonte
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
|
|
located at http://jvcl.delphi-jedi.org
|
|
-----------------------------------------------------------------------------}
|
|
// $Id: JvEditorCommon.pas 12594 2009-11-03 12:38:16Z ahuser $
|
|
|
|
{ history
|
|
(JVCL Library versions) :
|
|
1.00:
|
|
- first release;
|
|
1.01:
|
|
- reduce caret blinking - method KeyUp;
|
|
- fix bug with setting SelLength to 0;
|
|
- changing SelStart now reset SelLength to 0;
|
|
- very simple tab - two blanks;
|
|
1.02:
|
|
- SmartTab;
|
|
- KeepTrailingBlanks;
|
|
- CursorBeyondEOF;
|
|
- AutoIndent;
|
|
- BackSpaceUnindents;
|
|
- two-key commands;
|
|
- automatically expands tabs when setting Lines property;
|
|
1.04:
|
|
- some bugs fixed in Completion;
|
|
- fix bug with reading SelLength property;
|
|
- new method TJvEditorStrings .SetLockText;
|
|
- new dynamic method TextAllChanged;
|
|
1.11:
|
|
- method StatusChanged;
|
|
- fixed bug with setting Lines.Text property;
|
|
- new method GetText with TIEditReader syntax;
|
|
1.14:
|
|
- selected color intialized with system colors;
|
|
1.17:
|
|
some improvements and bug fixes by Rafal Smotrzyk - rsmotrzyk att mikroplan dott com dott pl :
|
|
- AutoIndent now worked when SmartTab Off;
|
|
- method GetTextLen for TMemo compatibility;
|
|
- Indent, Unindent commands;
|
|
- WM_COPY, WM_CUT, WM_PASTE message handling;
|
|
1.17.1:
|
|
- painting and scrolling changed:
|
|
bug with scrolling JvEditor if other StayOnTop
|
|
window overlapes JvEditor window FIXED;
|
|
- right click now not unselect text;
|
|
- changing RightMargin, RightMarginVisible and RightMarginColor
|
|
Invalidates window;
|
|
1.17.2:
|
|
another good stuf by Rafal Smotrzyk - rsmotrzyk att mikroplan dott com dott pl :
|
|
- fixed bug with backspace pressed when text selected;
|
|
- fixed bug with disabling Backspace Unindents when SmartTab off;
|
|
- fixed bug in GetTabStop method when SmartTab off;
|
|
- new commands: DeleteWord, DeleteLine, ToUpperCase, ToLowerCase;
|
|
1.17.3:
|
|
- TabStops;
|
|
1.17.4:
|
|
- undo for selection modifiers;
|
|
- UndoBuffer.BeginCompound, UndoBuffer.EndCompound for
|
|
compound commands, that must interpreted by UndoBuffer as one operation;
|
|
now not implemented, but must be used for feature compatibility;
|
|
- fixed bug with undoable Delete on end of line;
|
|
- new command ChangeCase;
|
|
1.17.5:
|
|
- UndoBuffer.BeginCompound, UndoBuffer.EndCompound fully implemented;
|
|
- UndoBuffer property in TJvCustomEditor;
|
|
1.17.6:
|
|
- fixed bug with compound undo;
|
|
- fixed bug with scrolling (from v 1.171);
|
|
1.17.7:
|
|
- UndoBuffer.BeginCompound and UndoBuffer.EndCompound moved to TJvCustomEditor;
|
|
- Macro support: BeginRecord, EndRecord, PlayMacro; not complete;
|
|
- additional support for compound operations: prevent updating and other;
|
|
1.17.8:
|
|
- bug fixed with compound commands in macro;
|
|
1.21.2:
|
|
- fixed bug with pressing End-key if CursorBeoyondEOF enabled
|
|
(greetings to Martijn Laan)
|
|
1.21.4:
|
|
- fixed bug in commands ecNextWord and ecPrevWord
|
|
(greetings to Ildar Noureeslamov)
|
|
1.21.6:
|
|
- in OnGetLineAttr now it is possible to change attributes of right
|
|
trailing blanks.
|
|
1.23:
|
|
- fixed bug in completion (range check error)
|
|
(greetings to Willo vd Merwe)
|
|
1.51.1 (JVCL Library 1.51 with Update 1):
|
|
- methods Lines.Add and Lines.Insert now properly updates editor window.
|
|
1.51.2 (JVCL Library 1.51 with Update 2):
|
|
- "Courier New" is default font now.
|
|
1.51.3 (JVCL Library 1.51 with Update 2)::
|
|
- fixed bug: double click on empty editor raise exception;
|
|
- fixed bug: backspace at EOF raise exception;
|
|
- fixed bug: gutter not repainted on vertical scrolling;
|
|
1.53:
|
|
- fixed bug: GetWordOnCaret returns invalid Word if caret stays on start of Word;
|
|
1.54.1:
|
|
- new: undo now works in overwrite mode;
|
|
1.54.2:
|
|
- fixed bug: double click not selects Word on first line;
|
|
- selection work better after consecutive moving to begin_of_line and
|
|
end_of_line, and in other cases;
|
|
- 4 block format supported now: NonInclusive (default), Inclusive,
|
|
Line (initial support), Column;
|
|
- painting was improved;
|
|
1.60:
|
|
- DblClick work better (thanks to Constantin M. Lushnikov);
|
|
- fixed bug: caret moved when mouse moves over JvEditor after
|
|
click on any other windows placed over JvEditor, which loses focus
|
|
after this click; (anyone understand me ? :)
|
|
- bug fixed: accelerator key do not work on window,
|
|
where JvEditor is placed (thanks to Luis David Cardenas Bucio);
|
|
1.61:
|
|
- support for mouse with wheel (thanks to Michael Serpik);
|
|
- ANY font can be used (thanks to Rients Politiek);
|
|
- bug fixed: completion ranges error on first line
|
|
(thanks to Walter Campelo);
|
|
- new functions: CanCopy, CanPaste, CanCut in TJvCustomEditor
|
|
and function CanUndo in TJvUndoBuffer (TJvCustomEditor.UndoBuffer);
|
|
2.00:
|
|
- removed dependencies from JvUtils.pas unit;
|
|
- bugfixed: TJvDeleteUndo and TJvBackspaceUndo do not work always properly
|
|
(thanks to Pavel Chromy);
|
|
- bugfixed: workaround bug with some fonts in Win9x
|
|
(thanks to Dmitry Rubinstain);
|
|
2.10.2: (changes by Andreas Hausladen)
|
|
- speed optimation (font cache, many Lines.Text references were removed)
|
|
- fixed bug: TJvBackspaceUndo, TJvInsertUndo, TJvDeleteUndo still do not work
|
|
always properly
|
|
- fixed bug: caret movement and selections set Modified to TRUE
|
|
- Undo restores Modified-field
|
|
- added [Ctrl][Backspace] (ecBackspaceWord) and [Shift][Backspace] command
|
|
- added [Shift]+MouseDown selections
|
|
- added [Alt]+MouseDown selections (column)
|
|
- new event TKeyboard.OnCommand2
|
|
- fixed bug: CodeCompletition catches VK_HOME, VK_END
|
|
- fixed bug: on empty editor pressing [Ctrl][End] raises "Index out of
|
|
bounds (-1)"
|
|
- fixed bug: caret moves into gutter on horz. scrolling
|
|
- added OnGutterClick and OnGutterDblClick events
|
|
- renamed all "Identifer" to "Identifier"
|
|
2.10.3 (changes by Andreas Hausladen)
|
|
- added new mouse wheel functionality: [Ctrl]+Wheel and [Shift]+Wheel
|
|
- faster TJvReplaceUndo and ReplaceWord/ReplaceWord2
|
|
- bug fixed: first complete selected line stops drawing selection on cell 80
|
|
- added SelectAll, ClearSelection
|
|
- full support for SelBlockFormat = bfColumn and bfLine
|
|
- improved TJvCompletion.ReplaceWord
|
|
- undo system overworked
|
|
- fixed bug: [Shift][Tab] is the same as [Tab]
|
|
- reduced TextAllChanged() calls
|
|
- added: Un-/IndentColumns, Un-/IndentLines, Un-/IndentSelLines
|
|
- new Undo: TJvUnindentColumnUndo, TJvIndentColumnUndo
|
|
- moved: FSelBegX, FSelBegY, ... FSelected into TJvSelectionRec
|
|
- added GetAutoIndentStop and removed AutoIndent code from GetTabStop
|
|
- fixed bug: CanPaste raises Exception SCannotOpenClipboard (new: catches exception)
|
|
- fixed bug: in readonly mode [Return] does nothing
|
|
- added BlockOverwrite property
|
|
- added PeristentBlocks
|
|
2.10.4 (changed by peter3, Andreas Hausladen)
|
|
- fixed bug where pressing Enter/Return while the completion list is open inserts a line break (andreas)
|
|
- fixed GetNextWordPosEx (andreas)
|
|
- added default popupmenu if none assigned (JvFixedEditPopup)
|
|
- added handling of WM_CLEAR, WM_GETTEXTLENGTH, EM_SETREADONLY, EM_SETSEL, EM_GETSEL and EM_CANUNDO
|
|
3.0 (changes by Andreas Hausladen)
|
|
- speed optimation: GetTextLen is now faster
|
|
- fixed: GetSelStart returned caret position
|
|
- fixed: ecBackspace with BackSpaceUnindents=True may destroy the line
|
|
- fixed a bug in InsertText
|
|
- optimized ExpandTabs
|
|
|
|
2004-01-25: file split into JvEditor and JvEditorCommon
|
|
|
|
Further history: see CVS/SVN
|
|
}
|
|
|
|
unit JvEditorCommon;
|
|
|
|
{$I jvcl.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF UNITVERSIONING}
|
|
JclUnitVersioning,
|
|
{$ENDIF UNITVERSIONING}
|
|
Windows, Messages, ShellAPI, SysUtils, Classes, Contnrs, Graphics, Controls,
|
|
Forms, StdCtrls, ExtCtrls, Menus, ActnList,
|
|
JvConsts, JvFixedEditPopup, JvStdEditActions, JvUnicodeCanvas, JvComponent,
|
|
JvExControls;
|
|
|
|
const
|
|
Max_X = 1024; {max symbols per row}
|
|
Max_X_Scroll = Max_X;
|
|
{max symbols per row for scrollbar}
|
|
GutterRightMargin = 2;
|
|
|
|
WM_EDITCOMMAND = WM_USER + $101;
|
|
WM_COMPOUND = WM_USER + $102;
|
|
|
|
type
|
|
EJvEditorError = class(Exception);
|
|
TJvCustomEditorBase = class; // base class for both Ansi and Unicode editor
|
|
TJvCompletionBase = class;
|
|
|
|
TCellRect = record
|
|
Width: Integer;
|
|
Height: Integer;
|
|
end;
|
|
|
|
TLineAttr = packed record { CompareMem() requires "packed" }
|
|
FC: TColor;
|
|
BC: TColor;
|
|
Style: TFontStyles;
|
|
Border: TColor;
|
|
end;
|
|
|
|
TLineAttrs = array {[0..Max_X]} of TLineAttr;
|
|
|
|
TDynIntArray = array of Integer;
|
|
TDynBoolArray = array of Boolean;
|
|
|
|
TModifiedAction =
|
|
(maAll, maInsert, maDelete, maInsertColumn, maDeleteColumn, maReplace);
|
|
|
|
TBookmark = record
|
|
X: Integer;
|
|
Y: Integer;
|
|
Valid: Boolean;
|
|
end;
|
|
TBookmarkNum = 0..9;
|
|
TBookmarks = array [TBookmarkNum] of TBookmark;
|
|
|
|
{ Borland Block Type:
|
|
00 - inclusive;
|
|
01 - line;
|
|
02 - column;
|
|
03 - noninclusive; }
|
|
TJvSelBlockFormat = (bfInclusive, bfLine, bfColumn, bfNonInclusive);
|
|
|
|
TOnPaintGutter = procedure(Sender: TObject; Canvas: TCanvas) of object;
|
|
TOnGutterClick = procedure(Sender: TObject; Line: Integer) of object;
|
|
|
|
TJvLineChangeEvent = procedure(Sender: TObject; Line: Integer) of object;
|
|
TJvCaretChangedEvent = procedure(Sender: TObject; LastCaretX, LastCaretY: Integer) of object;
|
|
|
|
{$IFDEF UNICODE}
|
|
TEditCommand = type LongWord;
|
|
{$ELSE}
|
|
TEditCommand = type Word;
|
|
{$ENDIF UNICODE}
|
|
TMacro = string; { used as buffer (array of char) }
|
|
|
|
TJvEditKey = class(TObject)
|
|
public
|
|
Key1: Word;
|
|
Key2: Word;
|
|
Shift1: TShiftState;
|
|
Shift2: TShiftState;
|
|
Command: TEditCommand;
|
|
constructor Create(const ACommand: TEditCommand;
|
|
const AKey1: Word; const AShift1: TShiftState);
|
|
constructor Create2(const ACommand: TEditCommand;
|
|
const AKey1: Word; const AShift1: TShiftState;
|
|
const AKey2: Word; const AShift2: TShiftState);
|
|
end;
|
|
|
|
TCommand2Event = procedure(Sender: TObject; const Key1: Word; const Shift1: TShiftState;
|
|
const Key2: Word; const Shift2: TShiftState; var Command: TEditCommand) of object;
|
|
|
|
TJvKeyboard = class(TPersistent)
|
|
private
|
|
FList: TObjectList;
|
|
FOnCommand2: TCommand2Event;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure Add(const ACommand: TEditCommand;
|
|
const AKey1: Word; const AShift1: TShiftState);
|
|
procedure Add2(const ACommand: TEditCommand;
|
|
const AKey1: Word; const AShift1: TShiftState;
|
|
const AKey2: Word; const AShift2: TShiftState);
|
|
procedure Add2Ctrl(const ACommand: TEditCommand;
|
|
const AKey1: Word; const AShift1: TShiftState; const AKey2: Word);
|
|
procedure Remove(const AKey1: Word; const AShift1: TShiftState);
|
|
procedure Remove2(const AKey1: Word; const AShift1: TShiftState;
|
|
const AKey2: Word; const AShift2: TShiftState);
|
|
procedure RemoveCtrl(const ACommand: TEditCommand);
|
|
procedure Clear;
|
|
function Command(const AKey: Word; const AShift: TShiftState): TEditCommand;
|
|
function Command2(const AKey1: Word; const AShift1: TShiftState;
|
|
const AKey2: Word; const AShift2: TShiftState): TEditCommand;
|
|
procedure SetDefLayout;
|
|
|
|
property OnCommand2: TCommand2Event read FOnCommand2 write FOnCommand2;
|
|
end;
|
|
|
|
{ TJvSelectionRec contains all text selection information }
|
|
PJvSelectionRec = ^TJvSelectionRec;
|
|
TJvSelectionRec = record
|
|
IsSelected: Boolean; // maybe a function that checks BegX/Y EndX/Y would be better
|
|
Selecting: Boolean;
|
|
SelBlockFormat: TJvSelBlockFormat;
|
|
SelBegX: Integer;
|
|
SelBegY: Integer;
|
|
SelEndX: Integer;
|
|
SelEndY: Integer;
|
|
SelStartX: Integer;
|
|
SelStartY: Integer;
|
|
SelLineOrgBegX, SelLineOrgEndX: Integer;
|
|
end;
|
|
|
|
TJvLineSelectStyle =
|
|
(lssUnselected, lssBreakpoint, lssDebugPoint, lssErrorPoint);
|
|
|
|
TAdjustPersistentBlockMode =
|
|
(amInsert, amDelete, amDeleteLine, amLineConcat, amLineBreak);
|
|
|
|
TCompletionList = (cmIdentifiers, cmTemplates);
|
|
TOnCompletion = procedure(Sender: TObject; var Cancel: Boolean) of object;
|
|
|
|
TJvUndo = class;
|
|
|
|
IJvUndoCompound = interface
|
|
['{D326A114-0A57-4654-A7F0-16D3BBD0A2CE}']
|
|
end;
|
|
IJvBackspaceUndo = interface
|
|
['{88BE2C69-2C5C-48C0-AC46-888146DD70AD}']
|
|
end;
|
|
IJvBackspaceUnindentUndo = interface
|
|
['{A78B524C-684E-43BD-B8A4-A540CD0B022D}']
|
|
end;
|
|
|
|
TJvUndoBuffer = class(TList)
|
|
protected
|
|
FJvEditor: TJvCustomEditorBase;
|
|
FPtr: Integer;
|
|
InUndo: Boolean;
|
|
function LastUndo: TJvUndo;
|
|
function IsNewGroup(AUndo: TJvUndo): Boolean;
|
|
function CanRedo: Boolean;
|
|
procedure ClearRedo;
|
|
function IsCaretGroup: Boolean;
|
|
public
|
|
procedure Add(AUndo: TJvUndo);
|
|
procedure Undo;
|
|
procedure Redo;
|
|
procedure Clear; override;
|
|
procedure Delete;
|
|
function CanUndo: Boolean;
|
|
end;
|
|
|
|
TJvUndo = class(TInterfacedObject)
|
|
protected
|
|
FJvEditor: TJvCustomEditorBase;
|
|
FModified: Boolean; // Editor.FModified
|
|
FSelection: PJvSelectionRec;
|
|
function UndoBuffer: TJvUndoBuffer;
|
|
protected
|
|
property JvEditor: TJvCustomEditorBase read FJvEditor;
|
|
public
|
|
constructor Create(AJvEditor: TJvCustomEditorBase);
|
|
destructor Destroy; override;
|
|
procedure Undo; {$IFDEF COMPILER12_UP}virtual; {$ELSE}dynamic;{$ENDIF COMPILER12_UP} abstract;
|
|
procedure Redo; dynamic; {abstract;}
|
|
procedure SaveSelection;
|
|
procedure RestoreSelection;
|
|
end;
|
|
|
|
TJvCaretUndo = class(TJvUndo)
|
|
protected
|
|
FCaretX: Integer;
|
|
FCaretY: Integer;
|
|
property CaretX: Integer read FCaretX write FCaretX;
|
|
property CaretY: Integer read FCaretY write FCaretY;
|
|
public
|
|
constructor Create(AJvEditor: TJvCustomEditorBase; ACaretX, ACaretY: Integer);
|
|
procedure Undo; override;
|
|
end;
|
|
|
|
TJvSelectUndo = class(TJvCaretUndo)
|
|
public
|
|
constructor Create(AJvEditor: TJvCustomEditorBase; ACaretX, ACaretY: Integer);
|
|
procedure Undo; override;
|
|
end;
|
|
|
|
TJvUnselectUndo = class(TJvSelectUndo);
|
|
|
|
TJvBeginCompoundUndo = class(TJvUndo)
|
|
public
|
|
procedure Undo; override;
|
|
end;
|
|
|
|
TJvEndCompoundUndo = class(TJvBeginCompoundUndo);
|
|
|
|
TJvControlScrollBar95 = class(TObject)
|
|
private
|
|
FKind: TScrollBarKind;
|
|
FPosition: Integer;
|
|
FMin: Integer;
|
|
FMax: Integer;
|
|
FSmallChange: TScrollBarInc;
|
|
FLargeChange: TScrollBarInc;
|
|
FPage: Integer;
|
|
FHandle: THandle;
|
|
FOnScroll: TScrollEvent;
|
|
procedure SetParam(Index, Value: Integer);
|
|
protected
|
|
procedure Scroll(ScrollCode: TScrollCode; var ScrollPos: Integer); dynamic;
|
|
public
|
|
constructor Create;
|
|
procedure SetParams(AMin, AMax, APosition, APage: Integer);
|
|
procedure DoScroll(var Msg: TWMScroll);
|
|
property Kind: TScrollBarKind read FKind write FKind default sbHorizontal;
|
|
property SmallChange: TScrollBarInc read FSmallChange write FSmallChange default 1;
|
|
property LargeChange: TScrollBarInc read FLargeChange write FLargeChange default 1;
|
|
property Min: Integer index 0 read FMin write SetParam default 0;
|
|
property Max: Integer index 1 read FMax write SetParam default 100;
|
|
property Position: Integer index 2 read FPosition write SetParam default 0;
|
|
property Page: Integer index 3 read FPage write SetParam;
|
|
property Handle: THandle read FHandle write FHandle;
|
|
property OnScroll: TScrollEvent read FOnScroll write FOnScroll;
|
|
end;
|
|
|
|
TJvEditorClient = class(TObject)
|
|
public
|
|
FJvEditor: TJvCustomEditorBase;
|
|
Top: Integer;
|
|
function Left: Integer;
|
|
function Height: Integer;
|
|
function Width: Integer;
|
|
function ClientWidth: Integer;
|
|
function ClientHeight: Integer;
|
|
function ClientRect: TRect;
|
|
function BoundsRect: TRect;
|
|
function GetCanvas: TJvUnicodeCanvas;
|
|
property Canvas: TJvUnicodeCanvas read GetCanvas;
|
|
end;
|
|
|
|
TJvGutter = class(TObject)
|
|
private
|
|
FJvEditor: TJvCustomEditorBase;
|
|
public
|
|
procedure Paint;
|
|
procedure Invalidate;
|
|
end;
|
|
|
|
TJvLineInformation = class(TObject)
|
|
private
|
|
FLine: Integer;
|
|
FSelectStyle: TJvLineSelectStyle;
|
|
FData: Pointer;
|
|
FEditor: TJvCustomEditorBase;
|
|
procedure SetLine(Value: Integer);
|
|
procedure SetSelectStyle(const Value: TJvLineSelectStyle);
|
|
protected
|
|
procedure RepaintLine(LineNum: Integer); virtual;
|
|
procedure CheckEmpty; virtual; // releases the object if Data=nil and SelectStyle=lssUnselected
|
|
public
|
|
constructor Create(AEditor: TJvCustomEditorBase; ALine: Integer);
|
|
destructor Destroy; override;
|
|
|
|
property Line: Integer read FLine write SetLine;
|
|
property SelectStyle: TJvLineSelectStyle read FSelectStyle write SetSelectStyle;
|
|
property Data: Pointer read FData write FData;
|
|
property Editor: TJvCustomEditorBase read FEditor;
|
|
end;
|
|
|
|
TJvLineInformationList = class(TObject)
|
|
private
|
|
FEditor: TJvCustomEditorBase;
|
|
FList: TObjectList;
|
|
FDebugColor: TColor;
|
|
FDebugTextColor: TColor;
|
|
FBreakpointColor: TColor;
|
|
FBreakpointTextColor: TColor;
|
|
FErrorPointTextColor: TColor;
|
|
FErrorPointColor: TColor;
|
|
function GetCount: Integer;
|
|
function GetData(Index: Integer): Pointer;
|
|
function GetItems(Index: Integer): TJvLineInformation;
|
|
function GetLineCount: Integer;
|
|
function GetLines(Index: Integer): TJvLineInformation;
|
|
function GetSelectStyle(Index: Integer): TJvLineSelectStyle;
|
|
procedure SetData(Index: Integer; Value: Pointer);
|
|
procedure SetSelectStyle(Index: Integer; const Value: TJvLineSelectStyle);
|
|
procedure SetBreakpointColor(const Value: TColor);
|
|
procedure SetBreakpointTextColor(const Value: TColor);
|
|
procedure SetDebugColor(const Value: TColor);
|
|
procedure SetDebugTextColor(const Value: TColor);
|
|
procedure SetErrorPointColor(const Value: TColor);
|
|
procedure SetErrorPointTextColor(const Value: TColor);
|
|
protected
|
|
function CreateLineInfo(Index: Integer): TJvLineInformation;
|
|
// Returns the line information assoziated with the line or creates a new.
|
|
// If Index not in [0..Count-1] the function raises EListError
|
|
public
|
|
constructor Create(AEditor: TJvCustomEditorBase);
|
|
destructor Destroy; override;
|
|
|
|
procedure Clear;
|
|
// Clear() removes all extra line information objects
|
|
procedure DeleteLine(Line: Integer);
|
|
// DeleteLine() deletes all information for "Line" and updates all
|
|
// following lines by decrementing their line number
|
|
procedure InsertLine(Line: Integer);
|
|
// InsertLine() updates all line information line number which are below
|
|
// "Line"
|
|
|
|
property Count: Integer read GetCount;
|
|
property Items[Index: Integer]: TJvLineInformation read GetItems;
|
|
|
|
property LineCount: Integer read GetLineCount;
|
|
// LineCount returns Editor.Lines.Count
|
|
property Lines[Index: Integer]: TJvLineInformation read GetLines; default;
|
|
// Lines[] returns nil if the line has no extra information
|
|
property SelectStyle[Index: Integer]: TJvLineSelectStyle read GetSelectStyle write SetSelectStyle;
|
|
// SelectStyle[] returns/sets the select style for the line
|
|
property Data[Index: Integer]: Pointer read GetData write SetData;
|
|
// Data[] returns/sets the user defined data for the line
|
|
|
|
property DebugPointColor: TColor read FDebugColor write SetDebugColor;
|
|
property DebugPointTextColor: TColor read FDebugTextColor write SetDebugTextColor;
|
|
property BreakpointColor: TColor read FBreakpointColor write SetBreakpointColor;
|
|
property BreakpointTextColor: TColor read FBreakpointTextColor write SetBreakpointTextColor;
|
|
property ErrorPointColor: TColor read FErrorPointColor write SetErrorPointColor;
|
|
property ErrorPointTextColor: TColor read FErrorPointTextColor write SetErrorPointTextColor;
|
|
|
|
property Editor: TJvCustomEditorBase read FEditor;
|
|
end;
|
|
|
|
TJvBracketHighlighting = class(TPersistent)
|
|
private
|
|
FStart: TRect;
|
|
FStop: TRect;
|
|
|
|
FActive: Boolean;
|
|
FFontColor: TColor;
|
|
FBorderColor: TColor;
|
|
FColor: TColor;
|
|
FWordPairs: TStrings;
|
|
FCaseSensitiveWordPairs: Boolean;
|
|
FStringChar: string;
|
|
FCommentPairs: TStrings;
|
|
FStringChars: string;
|
|
FStringEscape: string;
|
|
FShowBetweenHighlighting: Boolean;
|
|
procedure SetWordPairs(Value: TStrings);
|
|
procedure SetCommentPairs(const Value: TStrings);
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
|
|
function CreateStringMap(const Text: string): TDynBoolArray;
|
|
published
|
|
property Active: Boolean read FActive write FActive default False;
|
|
property BorderColor: TColor read FBorderColor write FBorderColor default clSilver;
|
|
property Color: TColor read FColor write FColor default clNone;
|
|
property FontColor: TColor read FFontColor write FFontColor default clNone;
|
|
property ShowBetweenHighlighting: Boolean read FShowBetweenHighlighting write FShowBetweenHighlighting default False;
|
|
|
|
property CaseSensitiveWordPairs: Boolean read FCaseSensitiveWordPairs write FCaseSensitiveWordPairs default True;
|
|
property WordPairs: TStrings read FWordPairs write SetWordPairs;
|
|
{ example: "begin=end", "repeat=until", "for=do", "asm=end" }
|
|
property StringChars: string read FStringChars write FStringChars;
|
|
{ example: '"''' }
|
|
property StringEscape: string read FStringEscape write FStringEscape;
|
|
{ example: '\"' }
|
|
property CommentPairs: TStrings read FCommentPairs write SetCommentPairs; // not implemented yet
|
|
{ example: "/*=*/", "(*=*)" }
|
|
end;
|
|
|
|
TJvErrorHighlighting = class;
|
|
|
|
TJvErrorHighlightingItem = class(TObject)
|
|
private
|
|
FCol: Integer;
|
|
FLine: Integer;
|
|
FLen: Integer;
|
|
FErrorText: string;
|
|
FData: TObject;
|
|
FTag: Integer;
|
|
FOwner: TJvErrorHighlighting;
|
|
procedure SetCol(const Value: Integer);
|
|
procedure SetLine(const Value: Integer);
|
|
public
|
|
constructor Create(AOwner: TJvErrorHighlighting;
|
|
ACol, ALine, ALen: Integer; const AErrorText: string);
|
|
destructor Destroy; override;
|
|
|
|
property Col: Integer read FCol write SetCol;
|
|
property Line: Integer read FLine write SetLine;
|
|
property Len: Integer read FLen;
|
|
property ErrorText: string read FErrorText;
|
|
property Data: TObject read FData write FData;
|
|
property Tag: Integer read FTag write FTag;
|
|
end;
|
|
|
|
TJvErrorHighlighting = class(TObject)
|
|
private
|
|
FItems: TObjectList;
|
|
FEditor: TJvCustomEditorBase;
|
|
FNeedsRepaint: Boolean;
|
|
FPaintLock: Integer;
|
|
function GetCount: Integer;
|
|
function GetItem(Index: Integer): TJvErrorHighlightingItem;
|
|
protected
|
|
procedure RepaintLine(Line: Integer);
|
|
public
|
|
constructor Create(AEditor: TJvCustomEditorBase);
|
|
destructor Destroy; override;
|
|
|
|
function Add(ACol, ALine, ALen: Integer; const AErrorText: string): Integer;
|
|
procedure Remove(Item: TJvErrorHighlightingItem);
|
|
procedure Delete(Index: Integer);
|
|
procedure Clear;
|
|
procedure BeginUpdate;
|
|
procedure EndUpdate;
|
|
|
|
procedure DeleteLine(Line: Integer);
|
|
// DeleteLine() deletes all error information for "Line" and updates all
|
|
// following lines by decrementing their line number
|
|
procedure InsertLine(Line: Integer);
|
|
// InsertLine() updates all error information line number which are below
|
|
// "Line"
|
|
|
|
function GetLineErrorMap(Y: Integer): TDynBoolArray;
|
|
function ErrorAt(X, Y: Integer): TJvErrorHighlightingItem;
|
|
procedure PaintError(Canvas: TCanvas; Col, Line: Integer; const R: TRect;
|
|
Len: Integer; const MyDi: TDynIntArray);
|
|
|
|
property Count: Integer read GetCount;
|
|
property Items[Index: Integer]: TJvErrorHighlightingItem read GetItem; default;
|
|
|
|
property Editor: TJvCustomEditorBase read FEditor;
|
|
end;
|
|
|
|
TJvCustomEditorBase = class(TJvCustomControl, IFixedPopupIntf, IStandardEditActions)
|
|
private
|
|
{ internal objects }
|
|
FScrollBarHorz: TJvControlScrollBar95;
|
|
FScrollBarVert: TJvControlScrollBar95;
|
|
FEditorClient: TJvEditorClient;
|
|
FCompletion: TJvCompletionBase; // must be initialized by a decendent
|
|
|
|
FGutter: TJvGutter;
|
|
FKeyboard: TJvKeyboard;
|
|
FUpdateLock: Integer;
|
|
FUndoBuffer: TJvUndoBuffer;
|
|
FGroupUndo: Boolean;
|
|
FUndoAfterSave: Boolean;
|
|
FBracketHighlighting: TJvBracketHighlighting;
|
|
FErrorHighlighting: TJvErrorHighlighting;
|
|
FCurrentLineHighlight: TColor;
|
|
|
|
{ internal - Columns and rows attributes }
|
|
FCols: Integer;
|
|
FRows: Integer;
|
|
FLeftCol: Integer;
|
|
FTopRow: Integer;
|
|
// FLeftColMax, FTopRowMax : Integer;
|
|
FLastVisibleCol: Integer;
|
|
FLastVisibleRow: Integer;
|
|
FVisibleColCount: Integer;
|
|
FVisibleRowCount: Integer;
|
|
|
|
{ internal - other flags and attributes }
|
|
FFontCache: TList; // collects all used fonts for faster font creation
|
|
FAllRepaint: Boolean;
|
|
FCellRect: TCellRect;
|
|
IgnoreKeyPress: Boolean;
|
|
WaitSecondKey: Boolean;
|
|
Key1: Word;
|
|
Shift1: TShiftState;
|
|
|
|
{ internal - selection attributes }
|
|
FUpdateSelBegY: Integer;
|
|
FUpdateSelEndY: Integer;
|
|
FPersistentBlocksCaretChanged: Boolean;
|
|
FSelBackColor: TColor;
|
|
FSelForeColor: TColor;
|
|
FLineInformations: TJvLineInformationList;
|
|
|
|
{ mouse support }
|
|
TimerScroll: TTimer;
|
|
MouseMoveY: Integer;
|
|
MouseMoveXX: Integer;
|
|
MouseMoveYY: Integer;
|
|
FDoubleClick: Boolean;
|
|
FMouseDown: Boolean;
|
|
|
|
{ internal }
|
|
FTabStops: string;
|
|
|
|
FCompound: Integer;
|
|
|
|
{ visual attributes - properties }
|
|
FBorderStyle: TBorderStyle;
|
|
FGutterColor: TColor;
|
|
FGutterWidth: Integer;
|
|
FRightMarginVisible: Boolean;
|
|
FRightMargin: Integer;
|
|
FRightMarginColor: TColor;
|
|
FScrollBars: TScrollStyle;
|
|
FDoubleClickLine: Boolean;
|
|
FSmartTab: Boolean;
|
|
FBackSpaceUnindents: Boolean;
|
|
FAutoIndent: Boolean;
|
|
FKeepTrailingBlanks: Boolean;
|
|
FCursorBeyondEOF: Boolean;
|
|
FCursorBeyondEOL: Boolean;
|
|
FBlockOverwrite: Boolean;
|
|
FPersistentBlocks: Boolean;
|
|
FHideCaret: Boolean;
|
|
|
|
{ non-visual attributes - properties }
|
|
FInsertMode: Boolean;
|
|
FReadOnly: Boolean;
|
|
FModified: Boolean;
|
|
FRecording: Boolean;
|
|
FBeepOnError: Boolean;
|
|
FUseFixedPopup: Boolean;
|
|
|
|
{ events }
|
|
FOnChange: TNotifyEvent;
|
|
FOnSelectionChange: TNotifyEvent;
|
|
FOnChangeStatus: TNotifyEvent;
|
|
FOnScroll: TNotifyEvent;
|
|
FOnResize: TNotifyEvent;
|
|
FOnDblClick: TNotifyEvent;
|
|
FOnPaintGutter: TOnPaintGutter;
|
|
FOnGutterClick: TOnGutterClick;
|
|
FOnGutterDblClick: TOnGutterClick;
|
|
|
|
FOnCompletionIdentifier: TOnCompletion;
|
|
FOnCompletionTemplate: TOnCompletion;
|
|
FOnCompletionDrawItem: TDrawItemEvent;
|
|
FOnCompletionMeasureItem: TMeasureItemEvent;
|
|
|
|
FOnLineInserted: TJvLineChangeEvent;
|
|
FOnLineDeleted: TJvLineChangeEvent;
|
|
FOnCaretChanged: TJvCaretChangedEvent;
|
|
|
|
function GetKeepTrailingBlanks: Boolean;
|
|
|
|
{ internal message processing }
|
|
procedure WMEditCommand(var Msg: TMessage); message WM_EDITCOMMAND;
|
|
procedure WMCompound(var Msg: TMessage); message WM_COMPOUND;
|
|
procedure CMResetCaptureControl(var Msg: TMessage); message CM_RESETCAPTURECONTROL;
|
|
procedure WMHScroll(var Msg: TWMHScroll); message WM_HSCROLL;
|
|
procedure WMVScroll(var Msg: TWMVScroll); message WM_VSCROLL;
|
|
procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
|
|
procedure WMCopy(var Msg: TMessage); message WM_COPY;
|
|
procedure WMCut(var Msg: TMessage); message WM_CUT;
|
|
procedure WMPaste(var Msg: TMessage); message WM_PASTE;
|
|
procedure WMUndo(var Msg: TMessage); message WM_UNDO;
|
|
|
|
// (p3) added to be compatible with JvFixedEditPopup
|
|
procedure WMClear(var Msg: TMessage); message WM_CLEAR;
|
|
procedure EMSetReadOnly(var Msg: TMessage); message EM_SETREADONLY;
|
|
procedure EMSetSelection(var Msg: TMessage); message EM_SETSEL;
|
|
procedure EMGetSelection(var Msg: TMessage); message EM_GETSEL;
|
|
procedure EMCanUndo(var Msg: TMessage); message EM_CANUNDO;
|
|
procedure WMGetTextLength(var Msg: TMessage); message WM_GETTEXTLENGTH;
|
|
protected
|
|
FMyDi: TDynIntArray; //array [0..Max_X] of Integer;
|
|
FSelection: TJvSelectionRec;
|
|
FCaretX: Integer;
|
|
FCaretY: Integer;
|
|
FTabPos: array [0..Max_X] of Boolean;
|
|
{ FMacro - buffer of TEditCommand, each command represents by two chars }
|
|
FMacro: TMacro;
|
|
FDefMacro: TMacro;
|
|
|
|
procedure UpdateEditorSize; virtual;
|
|
procedure UpdateEditorView; virtual;
|
|
procedure ScrollTimer(Sender: TObject);
|
|
|
|
function GetDefTabStop(X: Integer; Next: Boolean): Integer; virtual;
|
|
function GetTabStop(X, Y: Integer; Next: Boolean): Integer; virtual; abstract;
|
|
function GetBackStop(X, Y: Integer): Integer; virtual; abstract;
|
|
function GetAutoIndentStop(Y: Integer): Integer; virtual; abstract;
|
|
{$IFDEF SUPPORTS_UNICODE}
|
|
function ExpandTabsUnicode(const S: UnicodeString): UnicodeString; // ClipboardPaste
|
|
function GetUnicodeTextLine(Y: Integer; out Text: UnicodeString): Boolean; virtual; abstract;
|
|
function GetUnicodeWordOnCaret: UnicodeString; virtual; abstract;
|
|
{$ELSE}
|
|
function ExpandTabsAnsi(const S: AnsiString): AnsiString; // ClipboardPaste
|
|
function GetAnsiTextLine(Y: Integer; out Text: AnsiString): Boolean; virtual; abstract;
|
|
function GetAnsiWordOnCaret: AnsiString; virtual; abstract;
|
|
{$ENDIF SUPPORTS_UNICODE}
|
|
|
|
{ triggers when Lines changes }
|
|
procedure DoLinesChange(Sender: TObject); virtual;
|
|
procedure ReLine; virtual; abstract;
|
|
procedure TextAllChangedInternal(Unselect: Boolean); virtual;
|
|
|
|
{ triggers for descendants }
|
|
procedure Changed; dynamic;
|
|
procedure TextAllChanged; dynamic;
|
|
procedure StatusChanged; dynamic;
|
|
procedure SelectionChanged; dynamic;
|
|
procedure GetAttr(Line, ColBeg, ColEnd: Integer); virtual;
|
|
procedure ChangeAttr(Line, ColBeg, ColEnd: Integer); virtual;
|
|
procedure GutterPaint(Canvas: TCanvas); dynamic;
|
|
procedure GutterClick(Line: Integer); dynamic;
|
|
procedure GutterDblClick(Line: Integer); dynamic;
|
|
procedure BookmarkChanged(Bookmark: Integer); dynamic;
|
|
procedure CompletionIdentifier(var Cancel: Boolean); dynamic;
|
|
procedure CompletionTemplate(var Cancel: Boolean); dynamic;
|
|
procedure DoCompletionIdentifier(var Cancel: Boolean);
|
|
procedure DoCompletionTemplate(var Cancel: Boolean);
|
|
protected
|
|
procedure Resize; override;
|
|
procedure CreateWnd; override;
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
procedure Loaded; override;
|
|
procedure ScrollBarScroll(Sender: TObject; ScrollCode: TScrollCode; var
|
|
ScrollPos: Integer);
|
|
procedure Scroll(Vert: Boolean; ScrollPos: Integer); dynamic;
|
|
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
|
|
procedure KeyPress(var Key: Char); override;
|
|
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
|
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
|
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
|
function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; override;
|
|
procedure DblClick; override;
|
|
|
|
procedure GetDlgCode(var Code: TDlgCodes); override;
|
|
procedure FocusSet(PrevWnd: THandle); override;
|
|
procedure FocusKilled(NextWnd: THandle); override;
|
|
procedure DoPaste; dynamic;
|
|
procedure DoCopy; dynamic;
|
|
procedure DoCut; dynamic;
|
|
procedure CursorChanged; override;
|
|
procedure FontChanged; override;
|
|
function DoEraseBackground(Canvas: TCanvas; Param: Integer): Boolean; override;
|
|
|
|
{ IFixedPopupIntf method assignment }
|
|
procedure IFixedPopupIntf.Cut = ClipboardCut;
|
|
procedure IFixedPopupIntf.Copy = ClipboardCopy;
|
|
procedure IFixedPopupIntf.Paste = ClipboardPaste;
|
|
procedure IFixedPopupIntf.Delete = DeleteSelected;
|
|
|
|
{ IStandardEditActions method assignment }
|
|
procedure IStandardEditActions.Cut = ClipboardCut;
|
|
procedure IStandardEditActions.Copy = ClipboardCopy;
|
|
procedure IStandardEditActions.Paste = ClipboardPaste;
|
|
procedure IStandardEditActions.Delete = DeleteSelected;
|
|
protected
|
|
{ get/set methods for properties }
|
|
procedure SetGutterWidth(AWidth: Integer);
|
|
procedure SetGutterColor(AColor: TColor);
|
|
procedure SetBorderStyle(Value: TBorderStyle);
|
|
function GetSelStart: Integer;
|
|
procedure SetSelStart(ASelStart: Integer);
|
|
procedure SetSelLength(ASelLength: Integer);
|
|
function GetSelLength: Integer;
|
|
procedure SetSelBlockFormat(Value: TJvSelBlockFormat);
|
|
function GetSelBlockFormat: TJvSelBlockFormat;
|
|
procedure SetMode(Index: Integer; Value: Boolean);
|
|
procedure SetCaretPosition(Index, Pos: Integer);
|
|
procedure SetCols(ACols: Integer);
|
|
procedure SetRows(ARows: Integer);
|
|
procedure SetScrollBars(Value: TScrollStyle);
|
|
procedure SetRightMarginVisible(Value: Boolean);
|
|
procedure SetRightMargin(Value: Integer);
|
|
procedure SetRightMarginColor(Value: TColor);
|
|
procedure SetSelBackColor(const Value: TColor);
|
|
procedure SetSelForeColor(const Value: TColor);
|
|
procedure SetBracketHighlighting(Value: TJvBracketHighlighting);
|
|
procedure SetCurrentLineHighlight(const Value: TColor);
|
|
function GetPopupMenu: TPopupMenu; override;
|
|
|
|
function GetLineCount: Integer; virtual; abstract;
|
|
function GetLineLength(Index: Integer): Integer; virtual; abstract;
|
|
function FindNotBlankCharPosInLine(Line: Integer): Integer; virtual; abstract;
|
|
|
|
procedure LockUpdate;
|
|
procedure UnlockUpdate;
|
|
property UpdateLock: Integer read FUpdateLock;
|
|
property Compound: Integer read FCompound;
|
|
property EditorClient: TJvEditorClient read FEditorClient;
|
|
protected
|
|
function GetClipboardBlockFormat: TJvSelBlockFormat;
|
|
procedure SetClipboardBlockFormat(const Value: TJvSelBlockFormat);
|
|
procedure SetSel(SelX, SelY: Integer);
|
|
function IsNewSelection: Boolean;
|
|
function IsEmptySelection: Boolean;
|
|
procedure PaintSelection;
|
|
procedure SetUnSelected;
|
|
procedure RemoveSelectedBlock;
|
|
procedure PersistentBlocksSetUnSelected;
|
|
procedure SetSelUpdateRegion(BegY, EndY: Integer);
|
|
procedure AdjustSelLineMode(Restore: Boolean);
|
|
procedure AdjustPersistentBlockSelection(X, Y: Integer;
|
|
Mode: TAdjustPersistentBlockMode; Args: array of Integer);
|
|
protected
|
|
LineAttrs: TLineAttrs;
|
|
|
|
procedure Paint; override;
|
|
procedure PaintLine(Line: Integer; ColBeg, ColEnd: Integer); overload;
|
|
procedure PaintLineText(Line: Integer; ColBeg, ColEnd: Integer;
|
|
var ColPainted: Integer); virtual; abstract;
|
|
procedure GetBracketHighlightAttr(Line: Integer; var Attrs: TLineAttrs); virtual;
|
|
procedure HighlightBrackets(X, Y: Integer; BetweenSearch: Boolean = False); virtual;
|
|
procedure GetBracketHighlightingWords(var Direction: Integer;
|
|
const Start: string; var Stop: string; var CaseSensitive: Boolean); virtual;
|
|
function FontCacheFind(LA: TLineAttr): TFont;
|
|
procedure FontCacheClear;
|
|
procedure InsertChar(const Key: Word); virtual; abstract;
|
|
|
|
procedure Mouse2Cell(X, Y: Integer; var CX, CY: Integer);
|
|
|
|
procedure DrawRightMargin;
|
|
procedure SetCaretInternal(X, Y: Integer);
|
|
procedure CheckBeyondEOL(var CX: Integer; CY: Integer);
|
|
|
|
procedure NotUndoable;
|
|
procedure NotRedoable;
|
|
procedure ChangeBookmark(Bookmark: TBookmarkNum; Valid: Boolean);
|
|
procedure BeginRecord;
|
|
procedure EndRecord(var AMacro: TMacro);
|
|
procedure PlayMacro(const AMacro: TMacro);
|
|
|
|
function DoCommand(ACommand: TEditCommand; var X, Y: Integer;
|
|
var CaretUndo: Boolean): Boolean; virtual; abstract;
|
|
procedure LineDeleted(Line: Integer); virtual;
|
|
procedure LineInserted(Line: Integer); virtual;
|
|
|
|
property LineCount: Integer read GetLineCount;
|
|
property LineLength[Index: Integer]: Integer read GetLineLength;
|
|
|
|
property Completion: TJvCompletionBase read FCompletion write FCompletion;
|
|
public
|
|
Bookmarks: TBookmarks;
|
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure SetLeftTop(ALeftCol, ATopRow: Integer);
|
|
procedure PaintLine(Line: Integer); overload;
|
|
|
|
function CanUndo: Boolean; { IFixedPopupIntf }
|
|
function CanRedo: Boolean;
|
|
function CanCopy: Boolean; { IFixedPopupIntf }
|
|
function CanPaste: Boolean; { IFixedPopupIntf }
|
|
function CanCut: Boolean; { IFixedPopupIntf }
|
|
function CanSelectAll: Boolean; { IFixedPopupIntf }
|
|
procedure SelectAll; { IFixedPopupIntf }
|
|
function HasSelection: Boolean; { IFixedPopupIntf }
|
|
|
|
procedure ClipboardCopy; dynamic; abstract;
|
|
procedure ClipboardPaste; dynamic; abstract;
|
|
procedure ClipboardCut; dynamic;
|
|
procedure DeleteSelected; dynamic; abstract;
|
|
procedure ClearSelection; dynamic;
|
|
|
|
procedure Undo;
|
|
procedure Redo; // not implemented yet
|
|
|
|
procedure CaretChanged(LastCaretX, LastCaretY: Integer); virtual;
|
|
|
|
procedure SelectRange(BegX, BegY, EndX, EndY: Integer);
|
|
function CalcCellRect(X, Y: Integer): TRect;
|
|
procedure SetCaret(X, Y: Integer);
|
|
procedure CaretFromPos(Pos: Integer; var X, Y: Integer);
|
|
function PosFromCaret(X, Y: Integer): Integer;
|
|
procedure Mouse2Caret(X, Y: Integer; var CX, CY: Integer);
|
|
{ MousePosToCell returns the cell position of the cell where the mouse
|
|
cursor is. }
|
|
procedure MousePosToCell(X, Y: Integer; var CX, CY: Integer);
|
|
procedure CaretCoord(X, Y: Integer; var CX, CY: Integer);
|
|
function PosFromMouse(X, Y: Integer): Integer;
|
|
|
|
procedure PaintCaret(bShow: Boolean);
|
|
function GetTextLen: Integer;
|
|
procedure SelectWordOnCaret; virtual; abstract;
|
|
|
|
procedure BeginUpdate;
|
|
procedure EndUpdate;
|
|
procedure MakeRowVisible(ARow: Integer);
|
|
|
|
procedure Command(ACommand: TEditCommand); virtual;
|
|
procedure PostCommand(ACommand: TEditCommand);
|
|
|
|
procedure IndentColumns(X: Integer; BegY, EndY: Integer); virtual; abstract;
|
|
procedure UnIndentColumns(X: Integer; BegY, EndY: Integer); virtual; abstract;
|
|
procedure IndentLines(UnIndent: Boolean; BegY, EndY: Integer);
|
|
procedure IndentSelLines(UnIndent: Boolean);
|
|
|
|
procedure BeginCompound;
|
|
procedure EndCompound;
|
|
procedure PostBeginCompound;
|
|
procedure PostEndCompound;
|
|
|
|
property Gutter: TJvGutter read FGutter;
|
|
|
|
property LeftCol: Integer read FLeftCol;
|
|
property TopRow: Integer read FTopRow;
|
|
property VisibleColCount: Integer read FVisibleColCount;
|
|
property VisibleRowCount: Integer read FVisibleRowCount;
|
|
property LastVisibleCol: Integer read FLastVisibleCol;
|
|
property LastVisibleRow: Integer read FLastVisibleRow;
|
|
property Cols: Integer read FCols write SetCols;
|
|
property Rows: Integer read FRows write SetRows;
|
|
property CaretX: Integer index 0 read FCaretX write SetCaretPosition;
|
|
property CaretY: Integer index 1 read FCaretY write SetCaretPosition;
|
|
property Modified: Boolean read FModified write FModified;
|
|
property SelBlockFormat: TJvSelBlockFormat read GetSelBlockFormat write SetSelBlockFormat default bfNonInclusive;
|
|
property SelStart: Integer read GetSelStart write SetSelStart;
|
|
property SelLength: Integer read GetSelLength write SetSelLength;
|
|
property Keyboard: TJvKeyboard read FKeyboard;
|
|
property CellRect: TCellRect read FCellRect;
|
|
property UndoBuffer: TJvUndoBuffer read FUndoBuffer;
|
|
property GroupUndo: Boolean read FGroupUndo write FGroupUndo default True;
|
|
property UndoAfterSave: Boolean read FUndoAfterSave write FUndoAfterSave;
|
|
property Recording: Boolean read FRecording;
|
|
property UseFixedPopup: Boolean read FUseFixedPopup write FUseFixedPopup;
|
|
|
|
property LineInformations: TJvLineInformationList read FLineInformations;
|
|
public
|
|
{ published in descendants }
|
|
property BeepOnError: Boolean read FBeepOnError write FBeepOnError default False;
|
|
property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle;
|
|
property ScrollBars: TScrollStyle read FScrollBars write SetScrollBars default ssBoth;
|
|
property Cursor default crIBeam;
|
|
property Color default clWindow;
|
|
property TabStop default True;
|
|
property ParentFont default False;
|
|
property ParentColor default False;
|
|
|
|
property GutterWidth: Integer read FGutterWidth write SetGutterWidth default 0;
|
|
property GutterColor: TColor read FGutterColor write SetGutterColor default clBtnFace;
|
|
property RightMarginVisible: Boolean read FRightMarginVisible write SetRightMarginVisible default True;
|
|
property RightMargin: Integer read FRightMargin write SetRightMargin default 80;
|
|
property RightMarginColor: TColor read FRightMarginColor write SetRightMarginColor default clSilver;
|
|
property InsertMode: Boolean index 0 read FInsertMode write SetMode default True;
|
|
property ReadOnly: Boolean index 1 read FReadOnly write SetMode default False;
|
|
property DoubleClickLine: Boolean read FDoubleClickLine write FDoubleClickLine default False;
|
|
property TabStops: string read FTabStops write FTabStops;
|
|
property SmartTab: Boolean read FSmartTab write FSmartTab default True;
|
|
property BackSpaceUnindents: Boolean read FBackSpaceUnindents write FBackSpaceUnindents default True;
|
|
property AutoIndent: Boolean read FAutoIndent write FAutoIndent default True;
|
|
property KeepTrailingBlanks: Boolean read GetKeepTrailingBlanks write FKeepTrailingBlanks default False;
|
|
property CursorBeyondEOF: Boolean read FCursorBeyondEOF write FCursorBeyondEOF default False;
|
|
property CursorBeyondEOL: Boolean read FCursorBeyondEOL write FCursorBeyondEOL default True;
|
|
property BlockOverwrite: Boolean read FBlockOverwrite write FBlockOverwrite default True;
|
|
property PersistentBlocks: Boolean read FPersistentBlocks write FPersistentBlocks default False;
|
|
property BracketHighlighting: TJvBracketHighlighting read FBracketHighlighting write SetBracketHighlighting;
|
|
property SelForeColor: TColor read FSelForeColor write SetSelForeColor default clHighlightText;
|
|
property SelBackColor: TColor read FSelBackColor write SetSelBackColor default clHighlight;
|
|
property HideCaret: Boolean read FHideCaret write FHideCaret default False;
|
|
property CurrentLineHighlight: TColor read FCurrentLineHighlight write SetCurrentLineHighlight default clNone;
|
|
property ErrorHighlighting: TJvErrorHighlighting read FErrorHighlighting;
|
|
|
|
property OnChangeStatus: TNotifyEvent read FOnChangeStatus write FOnChangeStatus;
|
|
property OnScroll: TNotifyEvent read FOnScroll write FOnScroll;
|
|
property OnResize: TNotifyEvent read FOnResize write FOnResize;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
|
property OnSelectionChange: TNotifyEvent read FOnSelectionChange write FOnSelectionChange;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
|
|
property OnPaintGutter: TOnPaintGutter read FOnPaintGutter write FOnPaintGutter;
|
|
property OnGutterClick: TOnGutterClick read FOnGutterClick write FOnGutterClick;
|
|
property OnGutterDblClick: TOnGutterClick read FOnGutterDblClick write FOnGutterDblClick;
|
|
property OnCaretChanged: TJvCaretChangedEvent read FOnCaretChanged write FOnCaretChanged;
|
|
|
|
property OnCompletionIdentifier: TOnCompletion read FOnCompletionIdentifier write FOnCompletionIdentifier;
|
|
property OnCompletionTemplate: TOnCompletion read FOnCompletionTemplate write FOnCompletionTemplate;
|
|
property OnCompletionDrawItem: TDrawItemEvent read FOnCompletionDrawItem write FOnCompletionDrawItem;
|
|
property OnCompletionMeasureItem: TMeasureItemEvent read FOnCompletionMeasureItem write FOnCompletionMeasureItem;
|
|
|
|
property OnLineInserted: TJvLineChangeEvent read FOnLineInserted write FOnLineInserted;
|
|
property OnLineDeleted: TJvLineChangeEvent read FOnLineDeleted write FOnLineDeleted;
|
|
|
|
property DockManager;
|
|
end;
|
|
|
|
TJvCompletionBase = class(TPersistent)
|
|
private
|
|
FJvEditor: TJvCustomEditorBase;
|
|
FPopupList: TListBox;
|
|
FItemIndex: Integer;
|
|
FMode: TCompletionList;
|
|
FDefMode: TCompletionList;
|
|
FItemHeight: Integer;
|
|
FTimer: TTimer;
|
|
FEnabled: Boolean;
|
|
FVisible: Boolean;
|
|
FDropDownCount: Integer;
|
|
FDropDownWidth: Integer;
|
|
FListBoxStyle: TListBoxStyle;
|
|
procedure OnTimer(Sender: TObject);
|
|
function GetItemIndex: Integer;
|
|
procedure SetItemIndex(AValue: Integer);
|
|
function GetInterval: Cardinal;
|
|
procedure SetInterval(AValue: Cardinal);
|
|
function GetItems: TStrings;
|
|
protected
|
|
function DoKeyDown(Key: Word; Shift: TShiftState): Boolean; virtual;
|
|
procedure DoKeyPress(Key: Char); virtual;
|
|
|
|
procedure FindSelItem(var Eq: Boolean); virtual; abstract;
|
|
procedure MakeItems; virtual; abstract;
|
|
procedure ReplaceWordItemIndex(SubStrStart: Integer); virtual; abstract;
|
|
function GetTemplateCount: Integer; virtual; abstract;
|
|
function GetIdentifierCount: Integer; virtual; abstract;
|
|
{$IFDEF SUPPORTS_UNICODE}
|
|
function GetUnicodeSeparator: UnicodeString; virtual; abstract;
|
|
{$ELSE}
|
|
function GetAnsiSeparator: AnsiString; virtual; abstract;
|
|
{$ENDIF SUPPORTS_UNICODE}
|
|
|
|
function GetItemCount: Integer;
|
|
property JvEditor: TJvCustomEditorBase read FJvEditor;
|
|
property Items: TStrings read GetItems;
|
|
public
|
|
constructor Create(AJvEditor: TJvCustomEditorBase);
|
|
destructor Destroy; override;
|
|
procedure DropDown(const AMode: TCompletionList; const ShowAlways: Boolean);
|
|
procedure DoCompletion(const AMode: TCompletionList);
|
|
procedure CloseUp(const Apply: Boolean);
|
|
procedure SelectItem;
|
|
property ItemIndex: Integer read GetItemIndex write SetItemIndex;
|
|
property Visible: Boolean read FVisible write FVisible;
|
|
property Mode: TCompletionList read FMode write FMode;
|
|
published
|
|
property DropDownCount: Integer read FDropDownCount write FDropDownCount default 6;
|
|
property DropDownWidth: Integer read FDropDownWidth write FDropDownWidth default 300;
|
|
property Enabled: Boolean read FEnabled write FEnabled default False;
|
|
property ItemHeight: Integer read FItemHeight write FItemHeight;
|
|
property Interval: Cardinal read GetInterval write SetInterval default 800;
|
|
property ListBoxStyle: TListBoxStyle read FListBoxStyle write FListBoxStyle default lbStandard;
|
|
end;
|
|
|
|
//=== Highligther Editor =====================================================
|
|
|
|
type
|
|
TJvHighlighter = (hlNone, hlPascal, hlCBuilder, hlSql, hlPython, hlJava, hlJScript, hlVB,
|
|
hlHtml, hlPerl, hlIni, hlCocoR, hlPhp, hlNQC, hlCSharp,
|
|
hlSyntaxHighlighter);
|
|
TLongTokenType = 0..255;
|
|
|
|
const
|
|
lgNone = TLongTokenType(0);
|
|
lgComment1 = TLongTokenType(1);
|
|
lgComment2 = TLongTokenType(2);
|
|
lgString = TLongTokenType(4);
|
|
lgTag = TLongTokenType(5);
|
|
lgPreproc = TLongTokenType(6);
|
|
lgPreproc1 = lgPreproc;
|
|
lgPreproc2 = TLongTokenType(7);
|
|
lgUndefined = High(TLongTokenType);
|
|
|
|
type
|
|
TDelphiColor = record
|
|
ForeColor, BackColor: TColor;
|
|
Style: TFontStyles;
|
|
end;
|
|
|
|
const
|
|
DelphiColor_Comment: TDelphiColor = (ForeColor: clNavy; BackColor: clWindow; Style: [fsItalic]);
|
|
DelphiColor_Preproc: TDelphiColor = (ForeColor: clGreen; BackColor: clWindow; Style: []);
|
|
DelphiColor_Number: TDelphiColor = (ForeColor: clNavy; BackColor: clWindow; Style: []);
|
|
DelphiColor_Strings: TDelphiColor = (ForeColor: clBlue; BackColor: clWindow; Style: []);
|
|
DelphiColor_Symbol: TDelphiColor = (ForeColor: clBlack; BackColor: clWindow; Style: []);
|
|
DelphiColor_Reserved: TDelphiColor = (ForeColor: clBlack; BackColor: clWindow; Style: [fsBold]);
|
|
DelphiColor_Identifier: TDelphiColor = (ForeColor: clBlack; BackColor: clWindow; Style: []);
|
|
DelphiColor_PlainText: TDelphiColor = (ForeColor: clWindowText; BackColor: clWindow; Style: []);
|
|
|
|
type
|
|
TJvSymbolColor = class(TPersistent)
|
|
private
|
|
FStyle: TFontStyles;
|
|
FForeColor: TColor;
|
|
FBackColor: TColor;
|
|
public
|
|
constructor Create;
|
|
procedure SetColor(const ForeColor, BackColor: TColor; const Style: TFontStyles);
|
|
procedure Assign(Source: TPersistent); override;
|
|
published
|
|
property Style: TFontStyles read FStyle write FStyle default [];
|
|
property ForeColor: TColor read FForeColor write FForeColor {default clWindowText}; // disabled, otherwise the default values are ignored
|
|
property BackColor: TColor read FBackColor write FBackColor {default clWindow};
|
|
end;
|
|
|
|
TJvColors = class(TPersistent)
|
|
private
|
|
FComment: TJvSymbolColor;
|
|
FNumber: TJvSymbolColor;
|
|
FString: TJvSymbolColor;
|
|
FSymbol: TJvSymbolColor;
|
|
FReserved: TJvSymbolColor;
|
|
FIdentifier: TJvSymbolColor;
|
|
FPreproc: TJvSymbolColor;
|
|
FFunctionCall: TJvSymbolColor;
|
|
FDeclaration: TJvSymbolColor;
|
|
FStatement: TJvSymbolColor;
|
|
FPlainText: TJvSymbolColor;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
published
|
|
property Comment: TJvSymbolColor read FComment write FComment;
|
|
property Number: TJvSymbolColor read FNumber write FNumber;
|
|
property Strings: TJvSymbolColor read FString write FString;
|
|
property Symbol: TJvSymbolColor read FSymbol write FSymbol;
|
|
property Reserved: TJvSymbolColor read FReserved write FReserved;
|
|
property Identifier: TJvSymbolColor read FIdentifier write FIdentifier;
|
|
property Preproc: TJvSymbolColor read FPreproc write FPreproc;
|
|
property FunctionCall: TJvSymbolColor read FFunctionCall write FFunctionCall;
|
|
property Declaration: TJvSymbolColor read FDeclaration write FDeclaration;
|
|
property Statement: TJvSymbolColor read FStatement write FStatement;
|
|
property PlainText: TJvSymbolColor read FPlainText write FPlainText;
|
|
end;
|
|
|
|
IJvHLEditor = interface
|
|
['{E165FE73-AE7E-40A8-AC9B-7FD20D55A15E}']
|
|
function GetColors: TJvColors;
|
|
procedure SetColors(const Value: TJvColors);
|
|
function GetSyntaxHighlighting: Boolean;
|
|
procedure SetSyntaxHighlighting(Value: Boolean);
|
|
function GetHighlighter: TJvHighlighter;
|
|
procedure SetHighlighter(const Value: TJvHighlighter);
|
|
property Colors: TJvColors read GetColors write SetColors;
|
|
property SyntaxHighlighting: Boolean read GetSyntaxHighlighting write SetSyntaxHighlighting;
|
|
property Highlighter: TJvHighlighter read GetHighlighter write SetHighlighter;
|
|
end;
|
|
|
|
const
|
|
{ Editor commands }
|
|
{ When add new commands, please add them into JvInterpreter_JvEditor.pas unit also ! }
|
|
ecCharFirst = $00;
|
|
{$IFDEF UNICODE}
|
|
ecCharLast = $FFFF;
|
|
ecCommandFirst = $10000;
|
|
ecIntern = $400000; { use on internal updates }
|
|
ecUser = $800000; { use this for descendants }
|
|
{$ELSE}
|
|
ecCharLast = $FF;
|
|
ecCommandFirst = $100;
|
|
ecIntern = $1000; { use on internal updates }
|
|
ecUser = $8000; { use this for descendants }
|
|
{$ENDIF UNICODE}
|
|
|
|
{Cursor}
|
|
ecLeft = ecCommandFirst + 1;
|
|
ecUp = ecLeft + 1;
|
|
ecRight = ecLeft + 2;
|
|
ecDown = ecLeft + 3;
|
|
{Cursor with select}
|
|
ecSelLeft = ecCommandFirst + 9;
|
|
ecSelUp = ecSelLeft + 1;
|
|
ecSelRight = ecSelLeft + 2;
|
|
ecSelDown = ecSelLeft + 3;
|
|
{Cursor with column select}
|
|
ecSelColumnLeft = ecIntern + 0;
|
|
ecSelColumnUp = ecSelColumnLeft + 1;
|
|
ecSelColumnRight = ecSelColumnLeft + 2;
|
|
ecSelColumnDown = ecSelColumnLeft + 3;
|
|
{Cursor On words [translated] }
|
|
ecPrevWord = ecSelDown + 1;
|
|
ecNextWord = ecPrevWord + 1;
|
|
ecSelPrevWord = ecPrevWord + 2;
|
|
ecSelNextWord = ecPrevWord + 3;
|
|
ecSelWord = ecPrevWord + 4;
|
|
|
|
ecWindowTop = ecSelWord + 1;
|
|
ecWindowBottom = ecWindowTop + 1;
|
|
ecPrevPage = ecWindowTop + 2;
|
|
ecNextPage = ecWindowTop + 3;
|
|
ecSelPrevPage = ecWindowTop + 4;
|
|
ecSelNextPage = ecWindowTop + 5;
|
|
|
|
ecBeginLine = ecSelNextPage + 1;
|
|
ecEndLine = ecBeginLine + 1;
|
|
ecBeginDoc = ecBeginLine + 2;
|
|
ecEndDoc = ecBeginLine + 3;
|
|
ecSelBeginLine = ecBeginLine + 4;
|
|
ecSelEndLine = ecBeginLine + 5;
|
|
ecSelBeginDoc = ecBeginLine + 6;
|
|
ecSelEndDoc = ecBeginLine + 7;
|
|
ecSelAll = ecBeginLine + 8;
|
|
|
|
ecScrollLineUp = ecSelAll + 1;
|
|
ecScrollLineDown = ecScrollLineUp + 1;
|
|
|
|
ecInclusiveBlock = ecCommandFirst + 100;
|
|
ecLineBlock = ecCommandFirst + 101;
|
|
ecColumnBlock = ecCommandFirst + 102;
|
|
ecNonInclusiveBlock = ecCommandFirst + 103;
|
|
|
|
ecInsertPara = ecCommandFirst + 121;
|
|
ecBackspace = ecInsertPara + 1;
|
|
ecDelete = ecInsertPara + 2;
|
|
ecChangeInsertMode = ecInsertPara + 3;
|
|
ecTab = ecInsertPara + 4;
|
|
ecBackTab = ecInsertPara + 5;
|
|
ecIndent = ecInsertPara + 6;
|
|
ecUnindent = ecInsertPara + 7;
|
|
ecBackspaceWord = ecIntern + 10;
|
|
|
|
ecDeleteSelected = ecInsertPara + 10;
|
|
ecClipboardCopy = ecInsertPara + 11;
|
|
ecClipboardCut = ecClipboardCopy + 1;
|
|
ecClipboardPaste = ecClipboardCopy + 2;
|
|
|
|
ecDeleteLine = ecClipboardPaste + 1;
|
|
ecDeleteWord = ecDeleteLine + 1;
|
|
|
|
ecToUpperCase = ecDeleteLine + 2;
|
|
ecToLowerCase = ecToUpperCase + 1;
|
|
ecChangeCase = ecToUpperCase + 2;
|
|
|
|
ecUndo = ecChangeCase + 1;
|
|
ecRedo = ecUndo + 1;
|
|
ecBeginCompound = ecUndo + 2;
|
|
ecEndCompound = ecUndo + 3;
|
|
|
|
ecBeginUpdate = ecUndo + 4;
|
|
ecEndUpdate = ecUndo + 5;
|
|
|
|
ecSetBookmark0 = ecEndUpdate + 1;
|
|
ecSetBookmark1 = ecSetBookmark0 + 1;
|
|
ecSetBookmark2 = ecSetBookmark0 + 2;
|
|
ecSetBookmark3 = ecSetBookmark0 + 3;
|
|
ecSetBookmark4 = ecSetBookmark0 + 4;
|
|
ecSetBookmark5 = ecSetBookmark0 + 5;
|
|
ecSetBookmark6 = ecSetBookmark0 + 6;
|
|
ecSetBookmark7 = ecSetBookmark0 + 7;
|
|
ecSetBookmark8 = ecSetBookmark0 + 8;
|
|
ecSetBookmark9 = ecSetBookmark0 + 9;
|
|
|
|
ecGotoBookmark0 = ecSetBookmark9 + 1;
|
|
ecGotoBookmark1 = ecGotoBookmark0 + 1;
|
|
ecGotoBookmark2 = ecGotoBookmark0 + 2;
|
|
ecGotoBookmark3 = ecGotoBookmark0 + 3;
|
|
ecGotoBookmark4 = ecGotoBookmark0 + 4;
|
|
ecGotoBookmark5 = ecGotoBookmark0 + 5;
|
|
ecGotoBookmark6 = ecGotoBookmark0 + 6;
|
|
ecGotoBookmark7 = ecGotoBookmark0 + 7;
|
|
ecGotoBookmark8 = ecGotoBookmark0 + 8;
|
|
ecGotoBookmark9 = ecGotoBookmark0 + 9;
|
|
|
|
ecCompletionIdentifiers = ecGotoBookmark9 + 1;
|
|
ecCompletionTemplates = ecCompletionIdentifiers + 1;
|
|
|
|
ecRecordMacro = ecCompletionTemplates + 1;
|
|
ecPlayMacro = ecRecordMacro + 1;
|
|
ecBeginRecord = ecRecordMacro + 2;
|
|
ecEndRecord = ecRecordMacro + 3;
|
|
|
|
twoKeyCommand = High(TEditCommand);
|
|
|
|
function KeyPressed(VK: Integer): Boolean;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
const
|
|
UnitVersioning: TUnitVersionInfo = (
|
|
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_39/run/JvEditorCommon.pas $';
|
|
Revision: '$Revision: 12594 $';
|
|
Date: '$Date: 2009-11-03 13:38:16 +0100 (mar., 03 nov. 2009) $';
|
|
LogPath: 'JVCL\run'
|
|
);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
implementation
|
|
|
|
uses
|
|
Consts,
|
|
{$IFDEF SUPPORTS_INLINE}
|
|
Types,
|
|
{$ENDIF SUPPORTS_INLINE}
|
|
RTLConsts, Math, Clipbrd,
|
|
JvJCLUtils, JvThemes, JvResources;
|
|
|
|
type
|
|
TJvEditorCompletionList = class(TListBox)
|
|
private
|
|
FTimer: TTimer;
|
|
YY: Integer;
|
|
// HintWindow : THintWindow;
|
|
procedure CMHintShow(var Msg: TMessage); message CM_HINTSHOW;
|
|
procedure WMCancelMode(var Msg: TMessage); message WM_CancelMode;
|
|
procedure OnTimer(Sender: TObject);
|
|
protected
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
procedure CreateWnd; override;
|
|
procedure DestroyWnd; override;
|
|
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
|
procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
function KeyPressed(VK: Integer): Boolean;
|
|
begin
|
|
Result := GetKeyState(VK) and $8000 = $8000;
|
|
end;
|
|
|
|
//=== { TJvUndoBuffer } ======================================================
|
|
|
|
procedure RedoNotImplemented;
|
|
begin
|
|
raise EJvEditorError.CreateRes(@RsERedoNotYetImplemented);
|
|
end;
|
|
|
|
procedure TJvUndoBuffer.Add(AUndo: TJvUndo);
|
|
begin
|
|
if InUndo then
|
|
Exit;
|
|
ClearRedo;
|
|
inherited Add(AUndo);
|
|
FPtr := Count - 1;
|
|
end;
|
|
|
|
procedure TJvUndoBuffer.Undo;
|
|
|
|
function IsIntf(AInstance: TObject; IID: TGUID): Boolean; overload;
|
|
begin
|
|
Result := (AInstance <> nil) and (AInstance.GetInterfaceEntry(IID) <> nil);
|
|
end;
|
|
|
|
function IsIntf(AClass: TClass; IID: TGUID): Boolean; overload;
|
|
begin
|
|
Result := (AClass <> nil) and (AClass.GetInterfaceEntry(IID) <> nil);
|
|
end;
|
|
|
|
var
|
|
UndoClass: TClass;
|
|
Compound: Integer;
|
|
IsOnlyCaret: Boolean;
|
|
Selection: TJvSelectionRec;
|
|
WasModified: Boolean;
|
|
begin
|
|
if InUndo then
|
|
Exit;
|
|
|
|
Selection := FJvEditor.FSelection;
|
|
WasModified := FJvEditor.Modified;
|
|
|
|
IsOnlyCaret := True;
|
|
InUndo := True;
|
|
try
|
|
if LastUndo <> nil then
|
|
begin
|
|
Compound := 0;
|
|
UndoClass := LastUndo.ClassType;
|
|
while (LastUndo <> nil) and
|
|
((UndoClass = LastUndo.ClassType) or
|
|
{(LastUndo is TJvDeleteTrailUndo) or
|
|
(LastUndo is TJvReLineUndo) or}
|
|
IsIntf(LastUndo, IJvUndoCompound) or
|
|
(Compound > 0)) or
|
|
{((UndoClass = TJvBackspaceUndo) and
|
|
(LastUndo is TJvBackspaceUnindentUndo)) do}
|
|
IsIntf(UndoClass, IJvBackspaceUndo) and
|
|
IsIntf(LastUndo, IJvBackspaceUnindentUndo) do
|
|
begin
|
|
if LastUndo.ClassType = TJvBeginCompoundUndo then
|
|
begin
|
|
Dec(Compound);
|
|
UndoClass := nil;
|
|
end
|
|
else
|
|
if LastUndo.ClassType = TJvEndCompoundUndo then
|
|
Inc(Compound);
|
|
LastUndo.Undo;
|
|
if LastUndo <> nil then
|
|
begin
|
|
LastUndo.RestoreSelection;
|
|
FJvEditor.Modified := LastUndo.FModified;
|
|
end;
|
|
Dec(FPtr);
|
|
{if (UndoClass = TJvDeleteTrailUndo) or
|
|
(UndoClass = TJvReLineUndo) then}
|
|
if IsIntf(UndoClass, IJvUndoCompound) then
|
|
UndoClass := LastUndo.ClassType;
|
|
if (UndoClass <> TJvCaretUndo) and
|
|
(UndoClass <> TJvSelectUndo) and
|
|
(UndoClass <> TJvUnselectUndo) then
|
|
IsOnlyCaret := False;
|
|
if not FJvEditor.GroupUndo then
|
|
Break;
|
|
end;
|
|
if not FJvEditor.Modified then
|
|
IsOnlyCaret := True;
|
|
|
|
// paint selection
|
|
if not CompareMem(@Selection, @FJvEditor.FSelection, SizeOf(TJvSelectionRec)) then
|
|
FJvEditor.PaintSelection;
|
|
|
|
FJvEditor.UpdateEditorView;
|
|
if FJvEditor.FUpdateLock = 0 then
|
|
if not IsOnlyCaret then
|
|
FJvEditor.Changed
|
|
else
|
|
if WasModified then
|
|
FJvEditor.StatusChanged;
|
|
end;
|
|
finally
|
|
InUndo := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvUndoBuffer.Redo;
|
|
begin
|
|
if CanRedo then
|
|
begin
|
|
Inc(FPtr);
|
|
LastUndo.Redo;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvUndoBuffer.Clear;
|
|
begin
|
|
while Count > 0 do
|
|
begin
|
|
TJvUndo(Items[0]).Free;
|
|
inherited Delete(0);
|
|
end;
|
|
inherited Clear;
|
|
end;
|
|
|
|
procedure TJvUndoBuffer.ClearRedo;
|
|
begin
|
|
while (Count > 0) and (FPtr < Count - 1) do
|
|
begin
|
|
TJvUndo(Items[FPtr + 1]).Free;
|
|
inherited Delete(FPtr + 1);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvUndoBuffer.Delete;
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
TJvUndo(Items[Count - 1]).Free;
|
|
inherited Delete(Count - 1);
|
|
end;
|
|
end;
|
|
|
|
function TJvUndoBuffer.LastUndo: TJvUndo;
|
|
begin
|
|
if (FPtr >= 0) and (Count > 0) then
|
|
Result := TJvUndo(Items[FPtr])
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TJvUndoBuffer.IsNewGroup(AUndo: TJvUndo): Boolean;
|
|
begin
|
|
Result := (LastUndo = nil) or (LastUndo.ClassType <> AUndo.ClassType)
|
|
end;
|
|
|
|
function TJvUndoBuffer.IsCaretGroup: Boolean;
|
|
begin
|
|
Result := (LastUndo <> nil) and (LastUndo.ClassType = TJvCaretUndo);
|
|
end;
|
|
|
|
function TJvUndoBuffer.CanUndo: Boolean;
|
|
begin
|
|
Result := (LastUndo <> nil);
|
|
end;
|
|
|
|
function TJvUndoBuffer.CanRedo: Boolean;
|
|
begin
|
|
{
|
|
Result := FPtr < Count;
|
|
}
|
|
Result := False;
|
|
ClearRedo;
|
|
end;
|
|
|
|
//=== { TJvUndo } ============================================================
|
|
|
|
constructor TJvUndo.Create(AJvEditor: TJvCustomEditorBase);
|
|
begin
|
|
inherited Create;
|
|
FJvEditor := AJvEditor;
|
|
FModified := FJvEditor.FModified;
|
|
UndoBuffer.Add(Self);
|
|
FSelection := nil;
|
|
end;
|
|
|
|
destructor TJvUndo.Destroy;
|
|
begin
|
|
if Assigned(FSelection) then
|
|
Dispose(FSelection);
|
|
// (rom) added inherited Destroy
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvUndo.Redo;
|
|
begin
|
|
RedoNotImplemented;
|
|
end;
|
|
|
|
procedure TJvUndo.RestoreSelection;
|
|
begin
|
|
if Assigned(FSelection) then
|
|
begin
|
|
FJvEditor.FSelection := FSelection^;
|
|
FJvEditor.SetSelUpdateRegion(FSelection^.SelBegY, FSelection^.SelEndY);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvUndo.SaveSelection;
|
|
begin
|
|
if not Assigned(FSelection) then
|
|
New(FSelection);
|
|
FSelection^ := FJvEditor.FSelection;
|
|
end;
|
|
|
|
function TJvUndo.UndoBuffer: TJvUndoBuffer;
|
|
begin
|
|
if FJvEditor <> nil then
|
|
Result := FJvEditor.FUndoBuffer
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
//=== { TJvCaretUndo } =======================================================
|
|
|
|
constructor TJvCaretUndo.Create(AJvEditor: TJvCustomEditorBase;
|
|
ACaretX, ACaretY: Integer);
|
|
begin
|
|
inherited Create(AJvEditor);
|
|
FCaretX := ACaretX;
|
|
FCaretY := ACaretY;
|
|
end;
|
|
|
|
procedure TJvCaretUndo.Undo;
|
|
begin
|
|
with UndoBuffer do
|
|
begin
|
|
Dec(FPtr);
|
|
while JvEditor.FGroupUndo and (FPtr >= 0) and not IsNewGroup(Self) do
|
|
Dec(FPtr);
|
|
Inc(FPtr);
|
|
with TJvCaretUndo(Items[FPtr]) do
|
|
JvEditor.SetCaretInternal(FCaretX, FCaretY);
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvSelectUndo } ======================================================
|
|
|
|
constructor TJvSelectUndo.Create(AJvEditor: TJvCustomEditorBase;
|
|
ACaretX, ACaretY: Integer);
|
|
begin
|
|
inherited Create(AJvEditor, ACaretX, ACaretY);
|
|
SaveSelection;
|
|
end;
|
|
|
|
procedure TJvSelectUndo.Undo;
|
|
var
|
|
LastSel: TJvSelectUndo;
|
|
LastCaret: TJvCaretUndo;
|
|
begin
|
|
LastSel := Self;
|
|
LastCaret := nil;
|
|
{ Undo TJvSelectUndo and TJvCaretUndo in one action. This prevents
|
|
unnecessary caret movement with scolling. }
|
|
with UndoBuffer do
|
|
begin
|
|
while (FPtr >= 0) and ((not IsNewGroup(Self)) or (IsCaretGroup)) do
|
|
begin
|
|
if LastUndo.ClassType = TJvCaretUndo then
|
|
LastCaret := TJvCaretUndo(LastUndo)
|
|
else
|
|
LastSel := TJvSelectUndo(LastUndo);
|
|
Dec(FPtr);
|
|
if not FJvEditor.FGroupUndo then
|
|
Break;
|
|
end;
|
|
Inc(FPtr);
|
|
end;
|
|
|
|
LastSel.RestoreSelection;
|
|
|
|
if LastCaret <> nil then
|
|
LastCaret.Undo
|
|
else
|
|
FJvEditor.SetCaretInternal(LastSel.FCaretX, LastSel.FCaretY);
|
|
end;
|
|
|
|
//=== { TJvBeginCompoundUndo } ===============================================
|
|
|
|
procedure TJvBeginCompoundUndo.Undo;
|
|
begin
|
|
{ nothing }
|
|
end;
|
|
|
|
//=== { TJvControlScrollBar95 } ==============================================
|
|
|
|
const
|
|
SBKIND: array [TScrollBarKind] of Integer = (SB_HORZ, SB_VERT);
|
|
|
|
constructor TJvControlScrollBar95.Create;
|
|
begin
|
|
inherited Create;
|
|
FPage := 1;
|
|
FSmallChange := 1;
|
|
FLargeChange := 1;
|
|
end;
|
|
|
|
procedure TJvControlScrollBar95.SetParams(AMin, AMax, APosition, APage: Integer);
|
|
var
|
|
ScrollInfo: TScrollInfo;
|
|
begin
|
|
if AMax < AMin then
|
|
raise EInvalidOperation.CreateRes(@SScrollBarRange);
|
|
if APosition < AMin then
|
|
APosition := AMin;
|
|
if APosition > AMax then
|
|
APosition := AMax;
|
|
if Handle > 0 then
|
|
begin
|
|
with ScrollInfo do
|
|
begin
|
|
cbSize := SizeOf(TScrollInfo);
|
|
fMask := SIF_DISABLENOSCROLL;
|
|
if (AMin >= 0) or (AMax >= 0) then
|
|
fMask := fMask or SIF_RANGE;
|
|
if APosition >= 0 then
|
|
fMask := fMask or SIF_POS;
|
|
if APage >= 0 then
|
|
fMask := fMask or SIF_PAGE;
|
|
nPos := APosition;
|
|
nMin := AMin;
|
|
nMax := AMax;
|
|
nPage := APage;
|
|
end;
|
|
SetScrollInfo(
|
|
Handle, // handle of window with scroll bar
|
|
SBKIND[Kind], // scroll bar flag
|
|
ScrollInfo, // pointer to structure with scroll parameters
|
|
True); // redraw flag
|
|
end;
|
|
end;
|
|
|
|
procedure TJvControlScrollBar95.SetParam(Index, Value: Integer);
|
|
begin
|
|
case Index of
|
|
0:
|
|
FMin := Value;
|
|
1:
|
|
FMax := Value;
|
|
2:
|
|
FPosition := Value;
|
|
3:
|
|
FPage := Value;
|
|
end;
|
|
if FMax < FMin then
|
|
raise EInvalidOperation.CreateRes(@SScrollBarRange);
|
|
if FPosition < FMin then
|
|
FPosition := FMin;
|
|
if FPosition > FMax then
|
|
FPosition := FMax;
|
|
SetParams(FMin, FMax, FPosition, FPage);
|
|
end;
|
|
|
|
procedure TJvControlScrollBar95.DoScroll(var Msg: TWMScroll);
|
|
var
|
|
ScrollPos: Integer;
|
|
NewPos: Longint;
|
|
ScrollInfo: TScrollInfo;
|
|
begin
|
|
with Msg do
|
|
begin
|
|
NewPos := FPosition;
|
|
case TScrollCode(ScrollCode) of
|
|
scLineUp:
|
|
Dec(NewPos, FSmallChange);
|
|
scLineDown:
|
|
Inc(NewPos, FSmallChange);
|
|
scPageUp:
|
|
Dec(NewPos, FLargeChange);
|
|
scPageDown:
|
|
Inc(NewPos, FLargeChange);
|
|
scPosition, scTrack:
|
|
with ScrollInfo do
|
|
begin
|
|
cbSize := SizeOf(ScrollInfo);
|
|
fMask := SIF_ALL;
|
|
GetScrollInfo(Handle, SBKIND[Kind], ScrollInfo);
|
|
NewPos := nTrackPos;
|
|
end;
|
|
scTop:
|
|
NewPos := FMin;
|
|
scBottom:
|
|
NewPos := FMax;
|
|
end;
|
|
if NewPos < FMin then
|
|
NewPos := FMin;
|
|
if NewPos > FMax then
|
|
NewPos := FMax;
|
|
ScrollPos := NewPos;
|
|
Scroll(TScrollCode(ScrollCode), ScrollPos);
|
|
end;
|
|
Position := ScrollPos;
|
|
end;
|
|
|
|
procedure TJvControlScrollBar95.Scroll(ScrollCode: TScrollCode; var ScrollPos: Integer);
|
|
begin
|
|
if Assigned(FOnScroll) then
|
|
FOnScroll(Self, ScrollCode, ScrollPos);
|
|
end;
|
|
|
|
//=== { TJvEditKey } =========================================================
|
|
|
|
constructor TJvEditKey.Create(const ACommand: TEditCommand; const AKey1: Word;
|
|
const AShift1: TShiftState);
|
|
begin
|
|
inherited Create;
|
|
Key1 := AKey1;
|
|
Shift1 := AShift1;
|
|
Command := ACommand;
|
|
end;
|
|
|
|
constructor TJvEditKey.Create2(const ACommand: TEditCommand; const AKey1: Word;
|
|
const AShift1: TShiftState; const AKey2: Word; const AShift2: TShiftState);
|
|
begin
|
|
inherited Create;
|
|
Key1 := AKey1;
|
|
Shift1 := AShift1;
|
|
Key2 := AKey2;
|
|
Shift2 := AShift2;
|
|
Command := ACommand;
|
|
end;
|
|
|
|
//=== { TJvKeyboard } ========================================================
|
|
|
|
constructor TJvKeyboard.Create;
|
|
begin
|
|
inherited Create;
|
|
FList := TObjectList.Create;
|
|
end;
|
|
|
|
destructor TJvKeyboard.Destroy;
|
|
begin
|
|
FList.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvKeyboard.Assign(Source: TPersistent);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Source is TJvKeyboard then
|
|
begin
|
|
Clear;
|
|
for I := 0 to TJvKeyboard(Source).FList.Count - 1 do
|
|
with TJvEditKey(TJvKeyboard(Source).FList[I]) do
|
|
Add2(Command, Key1, Shift1, Key2, Shift2);
|
|
end
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TJvKeyboard.Add(const ACommand: TEditCommand; const AKey1: Word;
|
|
const AShift1: TShiftState);
|
|
begin
|
|
FList.Add(TJvEditKey.Create(ACommand, AKey1, AShift1));
|
|
end;
|
|
|
|
procedure TJvKeyboard.Add2(const ACommand: TEditCommand; const AKey1: Word;
|
|
const AShift1: TShiftState; const AKey2: Word; const AShift2: TShiftState);
|
|
begin
|
|
FList.Add(TJvEditKey.Create2(ACommand, AKey1, AShift1, AKey2, AShift2));
|
|
end;
|
|
|
|
procedure TJvKeyboard.Add2Ctrl(const ACommand: TEditCommand;
|
|
const AKey1: Word; const AShift1: TShiftState; const AKey2: Word);
|
|
begin
|
|
Add2(ACommand, AKey1, AShift1, AKey2, [ssCtrl]);
|
|
Add2(ACommand, AKey1, AShift1, AKey2, []);
|
|
end;
|
|
|
|
procedure TJvKeyboard.Remove(const AKey1: Word; const AShift1: TShiftState);
|
|
begin
|
|
Remove2(AKey1, AShift1, 0, []);
|
|
end;
|
|
|
|
procedure TJvKeyboard.Remove2(const AKey1: Word; const AShift1: TShiftState;
|
|
const AKey2: Word; const AShift2: TShiftState);
|
|
var
|
|
I: Integer;
|
|
ek: TJvEditKey;
|
|
begin
|
|
for I := FList.Count - 1 downto 0 do
|
|
begin
|
|
ek := TJvEditKey(FList[I]);
|
|
if (ek.Key1 = AKey1) and (ek.Shift1 = AShift1) and
|
|
(ek.Key2 = AKey2) and (ek.Shift2 = AShift2) then
|
|
FList.Delete(I);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvKeyboard.RemoveCtrl(const ACommand: TEditCommand);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := FList.Count - 1 downto 0 do
|
|
if TJvEditKey(FList[I]).Command = ACommand then
|
|
FList.Delete(I);
|
|
end;
|
|
|
|
procedure TJvKeyboard.Clear;
|
|
begin
|
|
FList.Clear;
|
|
end;
|
|
|
|
function TJvKeyboard.Command(const AKey: Word; const AShift: TShiftState): TEditCommand;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to FList.Count - 1 do
|
|
with TJvEditKey(FList[I]) do
|
|
if (Key1 = AKey) and (Shift1 = AShift) then
|
|
begin
|
|
if Key2 = 0 then
|
|
Result := Command
|
|
else
|
|
Result := twoKeyCommand;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
function TJvKeyboard.Command2(const AKey1: Word; const AShift1: TShiftState;
|
|
const AKey2: Word; const AShift2: TShiftState): TEditCommand;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to FList.Count - 1 do
|
|
with TJvEditKey(FList[I]) do
|
|
if (Key1 = AKey1) and (Shift1 = AShift1) and
|
|
(Key2 = AKey2) and (Shift2 = AShift2) then
|
|
begin
|
|
Result := Command;
|
|
Exit;
|
|
end;
|
|
// no command found: trigger event
|
|
if Assigned(FOnCommand2) then
|
|
FOnCommand2(Self, AKey1, AShift1, AKey2, AShift2, Result);
|
|
end;
|
|
|
|
procedure TJvKeyboard.SetDefLayout;
|
|
begin
|
|
Clear;
|
|
Add(ecLeft, VK_LEFT, []);
|
|
Add(ecRight, VK_RIGHT, []);
|
|
Add(ecUp, VK_UP, []);
|
|
Add(ecDown, VK_DOWN, []);
|
|
Add(ecSelLeft, VK_LEFT, [ssShift]);
|
|
Add(ecSelRight, VK_RIGHT, [ssShift]);
|
|
Add(ecSelUp, VK_UP, [ssShift]);
|
|
Add(ecSelDown, VK_DOWN, [ssShift]);
|
|
Add(ecSelColumnLeft, VK_LEFT, [ssShift, ssAlt]);
|
|
Add(ecSelColumnRight, VK_RIGHT, [ssShift, ssAlt]);
|
|
Add(ecSelColumnUp, VK_UP, [ssShift, ssAlt]);
|
|
Add(ecSelColumnDown, VK_DOWN, [ssShift, ssAlt]);
|
|
|
|
Add(ecBeginLine, VK_HOME, []);
|
|
Add(ecSelBeginLine, VK_HOME, [ssShift]);
|
|
Add(ecBeginDoc, VK_HOME, [ssCtrl]);
|
|
Add(ecSelBeginDoc, VK_HOME, [ssCtrl, ssShift]);
|
|
Add(ecEndLine, VK_END, []);
|
|
Add(ecSelEndLine, VK_END, [ssShift]);
|
|
Add(ecEndDoc, VK_END, [ssCtrl]);
|
|
Add(ecSelEndDoc, VK_END, [ssCtrl, ssShift]);
|
|
Add(ecPrevWord, VK_LEFT, [ssCtrl]);
|
|
Add(ecNextWord, VK_RIGHT, [ssCtrl]);
|
|
Add(ecSelPrevWord, VK_LEFT, [ssCtrl, ssShift]);
|
|
Add(ecSelNextWord, VK_RIGHT, [ssCtrl, ssShift]);
|
|
Add(ecSelAll, Ord('A'), [ssCtrl]);
|
|
|
|
Add(ecWindowTop, VK_PRIOR, [ssCtrl]);
|
|
Add(ecWindowBottom, VK_NEXT, [ssCtrl]);
|
|
Add(ecPrevPage, VK_PRIOR, []);
|
|
Add(ecNextPage, VK_NEXT, []);
|
|
Add(ecSelPrevPage, VK_PRIOR, [ssShift]);
|
|
Add(ecSelNextPage, VK_NEXT, [ssShift]);
|
|
Add(ecScrollLineUp, VK_UP, [ssCtrl]);
|
|
Add(ecScrollLineDown, VK_DOWN, [ssCtrl]);
|
|
|
|
Add(ecChangeInsertMode, VK_INSERT, []);
|
|
|
|
Add(ecInsertPara, VK_RETURN, []);
|
|
Add(ecBackspace, VK_BACK, []);
|
|
Add(ecBackspace, VK_BACK, [ssShift]);
|
|
Add(ecBackspaceWord, VK_BACK, [ssCtrl]);
|
|
Add(ecDelete, VK_DELETE, []);
|
|
Add(ecTab, VK_TAB, []);
|
|
Add(ecBackTab, VK_TAB, [ssShift]);
|
|
Add(ecDeleteSelected, VK_DELETE, [ssCtrl]);
|
|
Add(ecClipboardCopy, VK_INSERT, [ssCtrl]);
|
|
Add(ecClipboardCut, VK_DELETE, [ssShift]);
|
|
Add(ecClipboardPaste, VK_INSERT, [ssShift]);
|
|
|
|
Add(ecClipboardCopy, Ord('C'), [ssCtrl]);
|
|
Add(ecClipboardCut, Ord('X'), [ssCtrl]);
|
|
Add(ecClipboardPaste, Ord('V'), [ssCtrl]);
|
|
|
|
Add(ecSetBookmark0, Ord('0'), [ssCtrl, ssShift]);
|
|
Add(ecSetBookmark1, Ord('1'), [ssCtrl, ssShift]);
|
|
Add(ecSetBookmark2, Ord('2'), [ssCtrl, ssShift]);
|
|
Add(ecSetBookmark3, Ord('3'), [ssCtrl, ssShift]);
|
|
Add(ecSetBookmark4, Ord('4'), [ssCtrl, ssShift]);
|
|
Add(ecSetBookmark5, Ord('5'), [ssCtrl, ssShift]);
|
|
Add(ecSetBookmark6, Ord('6'), [ssCtrl, ssShift]);
|
|
Add(ecSetBookmark7, Ord('7'), [ssCtrl, ssShift]);
|
|
Add(ecSetBookmark8, Ord('8'), [ssCtrl, ssShift]);
|
|
Add(ecSetBookmark9, Ord('9'), [ssCtrl, ssShift]);
|
|
|
|
Add(ecGotoBookmark0, Ord('0'), [ssCtrl]);
|
|
Add(ecGotoBookmark1, Ord('1'), [ssCtrl]);
|
|
Add(ecGotoBookmark2, Ord('2'), [ssCtrl]);
|
|
Add(ecGotoBookmark3, Ord('3'), [ssCtrl]);
|
|
Add(ecGotoBookmark4, Ord('4'), [ssCtrl]);
|
|
Add(ecGotoBookmark5, Ord('5'), [ssCtrl]);
|
|
Add(ecGotoBookmark6, Ord('6'), [ssCtrl]);
|
|
Add(ecGotoBookmark7, Ord('7'), [ssCtrl]);
|
|
Add(ecGotoBookmark8, Ord('8'), [ssCtrl]);
|
|
Add(ecGotoBookmark9, Ord('9'), [ssCtrl]);
|
|
|
|
Add2Ctrl(ecSetBookmark0, Ord('K'), [ssCtrl], Ord('0'));
|
|
Add2Ctrl(ecSetBookmark1, Ord('K'), [ssCtrl], Ord('1'));
|
|
Add2Ctrl(ecSetBookmark2, Ord('K'), [ssCtrl], Ord('2'));
|
|
Add2Ctrl(ecSetBookmark3, Ord('K'), [ssCtrl], Ord('3'));
|
|
Add2Ctrl(ecSetBookmark4, Ord('K'), [ssCtrl], Ord('4'));
|
|
Add2Ctrl(ecSetBookmark5, Ord('K'), [ssCtrl], Ord('5'));
|
|
Add2Ctrl(ecSetBookmark6, Ord('K'), [ssCtrl], Ord('6'));
|
|
Add2Ctrl(ecSetBookmark7, Ord('K'), [ssCtrl], Ord('7'));
|
|
Add2Ctrl(ecSetBookmark8, Ord('K'), [ssCtrl], Ord('8'));
|
|
Add2Ctrl(ecSetBookmark9, Ord('K'), [ssCtrl], Ord('9'));
|
|
|
|
Add2Ctrl(ecGotoBookmark0, Ord('Q'), [ssCtrl], Ord('0'));
|
|
Add2Ctrl(ecGotoBookmark1, Ord('Q'), [ssCtrl], Ord('1'));
|
|
Add2Ctrl(ecGotoBookmark2, Ord('Q'), [ssCtrl], Ord('2'));
|
|
Add2Ctrl(ecGotoBookmark3, Ord('Q'), [ssCtrl], Ord('3'));
|
|
Add2Ctrl(ecGotoBookmark4, Ord('Q'), [ssCtrl], Ord('4'));
|
|
Add2Ctrl(ecGotoBookmark5, Ord('Q'), [ssCtrl], Ord('5'));
|
|
Add2Ctrl(ecGotoBookmark6, Ord('Q'), [ssCtrl], Ord('6'));
|
|
Add2Ctrl(ecGotoBookmark7, Ord('Q'), [ssCtrl], Ord('7'));
|
|
Add2Ctrl(ecGotoBookmark8, Ord('Q'), [ssCtrl], Ord('8'));
|
|
Add2Ctrl(ecGotoBookmark9, Ord('Q'), [ssCtrl], Ord('9'));
|
|
|
|
Add2Ctrl(ecNonInclusiveBlock, Ord('O'), [ssCtrl], Ord('K'));
|
|
Add2Ctrl(ecInclusiveBlock, Ord('O'), [ssCtrl], Ord('I'));
|
|
Add2Ctrl(ecColumnBlock, Ord('O'), [ssCtrl], Ord('C'));
|
|
Add2Ctrl(ecLineBlock, Ord('O'), [ssCtrl], Ord('L'));
|
|
|
|
Add(ecUndo, Ord('Z'), [ssCtrl]);
|
|
Add(ecUndo, VK_BACK, [ssAlt]);
|
|
// Add(ecRedo, Ord('Z'), [ssShift, ssCtrl]);
|
|
|
|
Add(ecCompletionIdentifiers, VK_SPACE, [ssCtrl]);
|
|
Add(ecCompletionTemplates, Ord('J'), [ssCtrl]);
|
|
|
|
{ cursor movement - default and classic }
|
|
Add2Ctrl(ecEndDoc, Ord('Q'), [ssCtrl], Ord('C'));
|
|
Add2Ctrl(ecEndLine, Ord('Q'), [ssCtrl], Ord('D'));
|
|
Add2Ctrl(ecWindowTop, Ord('Q'), [ssCtrl], Ord('E'));
|
|
Add2Ctrl(ecBeginDoc, Ord('Q'), [ssCtrl], Ord('R'));
|
|
Add2Ctrl(ecBeginLine, Ord('Q'), [ssCtrl], Ord('S'));
|
|
Add2Ctrl(ecWindowTop, Ord('Q'), [ssCtrl], Ord('T'));
|
|
Add2Ctrl(ecWindowBottom, Ord('Q'), [ssCtrl], Ord('U'));
|
|
|
|
Add(ecDeleteWord, Ord('T'), [ssCtrl]);
|
|
Add(ecInsertPara, Ord('N'), [ssCtrl]);
|
|
Add(ecDeleteLine, Ord('Y'), [ssCtrl]);
|
|
|
|
Add2Ctrl(ecSelWord, Ord('K'), [ssCtrl], Ord('T'));
|
|
Add2Ctrl(ecToUpperCase, Ord('K'), [ssCtrl], Ord('O'));
|
|
Add2Ctrl(ecToLowerCase, Ord('K'), [ssCtrl], Ord('N'));
|
|
Add2Ctrl(ecChangeCase, Ord('O'), [ssCtrl], Ord('U'));
|
|
Add2Ctrl(ecIndent, Ord('K'), [ssCtrl], Ord('I'));
|
|
Add2Ctrl(ecUnindent, Ord('K'), [ssCtrl], Ord('U'));
|
|
Add(ecIndent, Ord('I'), [ssShift, ssCtrl]);
|
|
Add(ecUnindent, Ord('U'), [ssShift, ssCtrl]);
|
|
|
|
Add(ecRecordMacro, Ord('R'), [ssCtrl, ssShift]);
|
|
Add(ecPlayMacro, Ord('P'), [ssCtrl, ssShift]);
|
|
end;
|
|
|
|
//=== { TJvEditorClient } ====================================================
|
|
|
|
function TJvEditorClient.GetCanvas: TJvUnicodeCanvas;
|
|
begin
|
|
Result := TJvUnicodeCanvas(FJvEditor.Canvas);
|
|
end;
|
|
|
|
function TJvEditorClient.Left: Integer;
|
|
begin
|
|
Result := FJvEditor.GutterWidth + 2;
|
|
end;
|
|
|
|
function TJvEditorClient.Height: Integer;
|
|
begin
|
|
Result := FJvEditor.ClientHeight;
|
|
end;
|
|
|
|
function TJvEditorClient.Width: Integer;
|
|
begin
|
|
Result := Max(FJvEditor.ClientWidth - Left, 0);
|
|
end;
|
|
|
|
function TJvEditorClient.ClientWidth: Integer;
|
|
begin
|
|
Result := Width;
|
|
end;
|
|
|
|
function TJvEditorClient.ClientHeight: Integer;
|
|
begin
|
|
Result := Height;
|
|
end;
|
|
|
|
function TJvEditorClient.ClientRect: TRect;
|
|
begin
|
|
Result := Bounds(Left, Top, Width, Height);
|
|
end;
|
|
|
|
function TJvEditorClient.BoundsRect: TRect;
|
|
begin
|
|
Result := Bounds(0, 0, Width, Height);
|
|
end;
|
|
|
|
//=== { TJvGutter } ==========================================================
|
|
|
|
procedure TJvGutter.Invalidate;
|
|
{var
|
|
R : TRect;}
|
|
begin
|
|
// Owner.Invalidate;
|
|
// R := Bounds(0, 0, FJvEditor.GutterWidth, FJvEditor.Height);
|
|
// InvalidateRect(FJvEditor.Handle, @R, False);
|
|
Paint;
|
|
end;
|
|
|
|
procedure TJvGutter.Paint;
|
|
begin
|
|
with FJvEditor, Canvas do
|
|
begin
|
|
Brush.Style := bsSolid;
|
|
Brush.Color := FGutterColor;
|
|
FillRect(Bounds(0, FEditorClient.Top, GutterWidth, FEditorClient.Height));
|
|
Pen.Width := 1;
|
|
Pen.Color := Color;
|
|
MoveTo(GutterWidth - 2, FEditorClient.Top);
|
|
LineTo(GutterWidth - 2, FEditorClient.Top + FEditorClient.Height);
|
|
Pen.Width := 2;
|
|
MoveTo(GutterWidth + 1, FEditorClient.Top);
|
|
LineTo(GutterWidth + 1, FEditorClient.Top + FEditorClient.Height);
|
|
Pen.Width := 1;
|
|
Pen.Color := clGray;
|
|
MoveTo(GutterWidth - 1, FEditorClient.Top);
|
|
LineTo(GutterWidth - 1, FEditorClient.Top + FEditorClient.Height);
|
|
|
|
GutterPaint(Canvas);
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvLineInformation } =================================================
|
|
|
|
constructor TJvLineInformation.Create(AEditor: TJvCustomEditorBase; ALine: Integer);
|
|
begin
|
|
inherited Create;
|
|
FEditor := AEditor;
|
|
FLine := ALine;
|
|
FSelectStyle := lssUnselected;
|
|
end;
|
|
|
|
destructor TJvLineInformation.Destroy;
|
|
begin
|
|
if not (csDestroying in Editor.ComponentState) then
|
|
begin
|
|
Editor.FLineInformations.FList.Extract(Self);
|
|
RepaintLine(Line);
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvLineInformation.CheckEmpty;
|
|
begin
|
|
if (Data = nil) and (SelectStyle = lssUnselected) then
|
|
Free;
|
|
end;
|
|
|
|
procedure TJvLineInformation.RepaintLine(LineNum: Integer);
|
|
begin
|
|
if Assigned(Editor) then
|
|
if (LineNum >= 0) and (LineNum < Editor.LineCount) then
|
|
Editor.PaintLine(Line, 0, Editor.VisibleColCount);
|
|
end;
|
|
|
|
procedure TJvLineInformation.SetLine(Value: Integer);
|
|
var
|
|
LastLine: Integer;
|
|
begin
|
|
if Value <> FLine then
|
|
begin
|
|
LastLine := FLine;
|
|
FLine := Value;
|
|
RepaintLine(LastLine);
|
|
RepaintLine(Line);
|
|
CheckEmpty;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvLineInformation.SetSelectStyle(const Value: TJvLineSelectStyle);
|
|
begin
|
|
if Value <> FSelectStyle then
|
|
begin
|
|
FSelectStyle := Value;
|
|
RepaintLine(Line);
|
|
CheckEmpty;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvLineInformationList } =============================================
|
|
|
|
constructor TJvLineInformationList.Create(AEditor: TJvCustomEditorBase);
|
|
begin
|
|
inherited Create;
|
|
FEditor := AEditor;
|
|
FList := TObjectList.Create;
|
|
FDebugColor := clNavy;
|
|
FDebugTextColor := clWhite;
|
|
FBreakpointColor := clRed;
|
|
FBreakpointTextColor := clWhite;
|
|
FErrorPointColor := clMaroon;
|
|
FErrorPointTextColor := clWhite;
|
|
end;
|
|
|
|
destructor TJvLineInformationList.Destroy;
|
|
begin
|
|
FList.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvLineInformationList.Clear;
|
|
begin
|
|
FList.Clear;
|
|
end;
|
|
|
|
procedure TJvLineInformationList.DeleteLine(Line: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Dec(Line);
|
|
for I := Count - 1 downto 0 do
|
|
if Items[I].Line = Line then
|
|
FList.Delete(I)
|
|
else
|
|
if Items[I].Line > Line then
|
|
Items[I].Line := Items[I].Line - 1;
|
|
end;
|
|
|
|
procedure TJvLineInformationList.InsertLine(Line: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Dec(Line);
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].Line >= Line then
|
|
Items[I].Line := Items[I].Line + 1;
|
|
end;
|
|
|
|
function TJvLineInformationList.GetCount: Integer;
|
|
begin
|
|
Result := FList.Count;
|
|
end;
|
|
|
|
function TJvLineInformationList.GetData(Index: Integer): Pointer;
|
|
var
|
|
Item: TJvLineInformation;
|
|
begin
|
|
Item := Lines[Index];
|
|
if Item <> nil then
|
|
Result := Item.Data
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TJvLineInformationList.GetItems(Index: Integer): TJvLineInformation;
|
|
begin
|
|
Result := TJvLineInformation(FList[Index]);
|
|
end;
|
|
|
|
function TJvLineInformationList.GetLineCount: Integer;
|
|
begin
|
|
Result := Editor.LineCount;
|
|
end;
|
|
|
|
function TJvLineInformationList.GetLines(Index: Integer): TJvLineInformation;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
Result := TJvLineInformation(FList[I]);
|
|
if Result.Line = Index then
|
|
Exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TJvLineInformationList.GetSelectStyle(Index: Integer): TJvLineSelectStyle;
|
|
var
|
|
Item: TJvLineInformation;
|
|
begin
|
|
Item := Lines[Index];
|
|
if Item <> nil then
|
|
Result := Item.SelectStyle
|
|
else
|
|
Result := lssUnselected;
|
|
end;
|
|
|
|
procedure TJvLineInformationList.SetData(Index: Integer; Value: Pointer);
|
|
begin
|
|
CreateLineInfo(Index).Data := Value;
|
|
end;
|
|
|
|
procedure TJvLineInformationList.SetSelectStyle(Index: Integer;
|
|
const Value: TJvLineSelectStyle);
|
|
begin
|
|
CreateLineInfo(Index).SelectStyle := Value;
|
|
end;
|
|
|
|
function TJvLineInformationList.CreateLineInfo(Index: Integer): TJvLineInformation;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Index < 0 then
|
|
raise EListError.CreateResFmt(@SListIndexError, [LineCount]);
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
Result := TJvLineInformation(FList[I]);
|
|
if Result.Line = Index then
|
|
Exit;
|
|
end;
|
|
Result := TJvLineInformation.Create(FEditor, Index);
|
|
FList.Add(Result);
|
|
end;
|
|
|
|
procedure TJvLineInformationList.SetBreakpointColor(const Value: TColor);
|
|
begin
|
|
if Value <> FBreakpointColor then
|
|
begin
|
|
FBreakpointColor := Value;
|
|
if Count > 0 then
|
|
Editor.Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvLineInformationList.SetBreakpointTextColor(const Value: TColor);
|
|
begin
|
|
if Value <> FBreakpointTextColor then
|
|
begin
|
|
FBreakpointTextColor := Value;
|
|
if Count > 0 then
|
|
Editor.Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvLineInformationList.SetDebugColor(const Value: TColor);
|
|
begin
|
|
if Value <> FDebugColor then
|
|
begin
|
|
FDebugColor := Value;
|
|
if Count > 0 then
|
|
Editor.Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvLineInformationList.SetDebugTextColor(const Value: TColor);
|
|
begin
|
|
if Value <> FDebugTextColor then
|
|
begin
|
|
FDebugTextColor := Value;
|
|
if Count > 0 then
|
|
Editor.Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvLineInformationList.SetErrorPointColor(const Value: TColor);
|
|
begin
|
|
if Value <> FErrorPointColor then
|
|
begin
|
|
FErrorPointColor := Value;
|
|
if Count > 0 then
|
|
Editor.Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvLineInformationList.SetErrorPointTextColor(const Value: TColor);
|
|
begin
|
|
if Value <> FErrorPointTextColor then
|
|
begin
|
|
FErrorPointTextColor := Value;
|
|
if Count > 0 then
|
|
Editor.Invalidate;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvBracketHighlighting } =============================================
|
|
|
|
constructor TJvBracketHighlighting.Create;
|
|
begin
|
|
inherited Create;
|
|
FStart.Left := -1;
|
|
FStop.Left := -1;
|
|
|
|
FWordPairs := TStringList.Create;
|
|
FCommentPairs := TStringList.Create;
|
|
FCaseSensitiveWordPairs := True;
|
|
FStringChar := '''';
|
|
FStringEscape := '''''';
|
|
|
|
FActive := False;
|
|
FBorderColor := clSilver;
|
|
FColor := clNone;
|
|
FFontColor := clNone;
|
|
end;
|
|
|
|
destructor TJvBracketHighlighting.Destroy;
|
|
begin
|
|
FCommentPairs.Free;
|
|
FWordPairs.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvBracketHighlighting.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TJvBracketHighlighting then
|
|
begin
|
|
with TJvBracketHighlighting(Source) do
|
|
begin
|
|
Self.FActive := FActive;
|
|
Self.FFontColor := FFontColor;
|
|
Self.FBorderColor := FBorderColor;
|
|
Self.FColor := FColor;
|
|
Self.FWordPairs.Assign(FWordPairs);
|
|
Self.FCaseSensitiveWordPairs := FCaseSensitiveWordPairs;
|
|
Self.FStringChar := FStringChar;
|
|
Self.SetCommentPairs(FCommentPairs);
|
|
end;
|
|
end
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TJvBracketHighlighting.SetWordPairs(Value: TStrings);
|
|
begin
|
|
if Value <> FWordPairs then
|
|
FWordPairs.Assign(Value);
|
|
end;
|
|
|
|
procedure TJvBracketHighlighting.SetCommentPairs(const Value: TStrings);
|
|
begin
|
|
if Value <> FCommentPairs then
|
|
FCommentPairs.Assign(Value);
|
|
end;
|
|
|
|
function TJvBracketHighlighting.CreateStringMap(const Text: string): TDynBoolArray;
|
|
var
|
|
LenText: Integer;
|
|
i, j, Idx, InStr: Integer;
|
|
begin
|
|
LenText := Length(Text);
|
|
SetLength(Result, LenText);
|
|
for i := 0 to High(Result) do
|
|
Result[i] := False;
|
|
|
|
if StringChars <> '' then
|
|
begin
|
|
InStr := 0;
|
|
i := 0;
|
|
while i < LenText do
|
|
begin
|
|
if (StringEscape <> '') and // skip string escape "char"
|
|
IsSubString(Text, i + 1, StringEscape) then
|
|
begin
|
|
for j := 0 to Length(StringEscape) - 1 do
|
|
Result[i + j] := True;
|
|
Inc(i, Length(StringEscape));
|
|
Continue;
|
|
end;
|
|
|
|
Idx := Pos(Text[i + 1], StringChars);
|
|
if Idx > 0 then
|
|
begin
|
|
if InStr = Idx then
|
|
InStr := 0 // string end
|
|
else
|
|
if InStr = 0 then
|
|
InStr := Idx;
|
|
end;
|
|
if InStr <> 0 then
|
|
Result[i] := True;
|
|
Inc(i);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvCustomEditorBase } ================================================
|
|
|
|
var
|
|
BlockTypeFormat: Integer = 0;
|
|
|
|
constructor TJvCustomEditorBase.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
ControlStyle := [csCaptureMouse, csClickEvents {, csOpaque}, csDoubleClicks,
|
|
csReplicatable];
|
|
IncludeThemeStyle(Self, [csNeedsBorderPaint]);
|
|
FInsertMode := True;
|
|
FKeyboard := TJvKeyboard.Create;
|
|
FRows := 1;
|
|
FCols := 1;
|
|
FUndoBuffer := TJvUndoBuffer.Create;
|
|
FUndoBuffer.FJvEditor := Self;
|
|
FGroupUndo := True;
|
|
FBracketHighlighting := TJvBracketHighlighting.Create;
|
|
FCurrentLineHighlight := clNone;
|
|
FErrorHighlighting := TJvErrorHighlighting.Create(Self);
|
|
|
|
FRightMarginVisible := True;
|
|
FRightMargin := 80;
|
|
FBorderStyle := bsSingle;
|
|
Ctl3D := True;
|
|
Height := 100;
|
|
Width := 150;
|
|
ParentColor := False;
|
|
Cursor := crIBeam;
|
|
TabStop := True;
|
|
FTabStops := '3 5';
|
|
FSmartTab := True;
|
|
FBackSpaceUnindents := True;
|
|
FAutoIndent := True;
|
|
FKeepTrailingBlanks := False;
|
|
FCursorBeyondEOF := False;
|
|
FCursorBeyondEOL := True;
|
|
FBlockOverwrite := True;
|
|
FPersistentBlocks := False;
|
|
FBeepOnError := False;
|
|
|
|
FScrollBars := ssBoth;
|
|
FScrollBarHorz := TJvControlScrollBar95.Create;
|
|
FScrollBarVert := TJvControlScrollBar95.Create;
|
|
FScrollBarVert.Kind := sbVertical;
|
|
FScrollBarHorz.OnScroll := ScrollBarScroll;
|
|
FScrollBarVert.OnScroll := ScrollBarScroll;
|
|
|
|
Color := clWindow;
|
|
FGutterColor := clBtnFace;
|
|
FSelBackColor := clHighLight;
|
|
FSelForeColor := clHighLightText;
|
|
FRightMarginColor := clSilver;
|
|
|
|
FEditorClient := TJvEditorClient.Create;
|
|
FEditorClient.FJvEditor := Self;
|
|
FGutter := TJvGutter.Create;
|
|
FGutter.FJvEditor := Self;
|
|
|
|
FLeftCol := 0;
|
|
FTopRow := 0;
|
|
FSelection.IsSelected := False;
|
|
FSelection.Selecting := False;
|
|
FCaretX := 0;
|
|
FCaretY := 0;
|
|
|
|
TimerScroll := TTimer.Create(Self);
|
|
TimerScroll.Enabled := False;
|
|
TimerScroll.Interval := 100;
|
|
TimerScroll.OnTimer := ScrollTimer;
|
|
|
|
FKeyboard.SetDefLayout;
|
|
|
|
FSelection.SelBlockFormat := bfNonInclusive;
|
|
if BlockTypeFormat = 0 then
|
|
BlockTypeFormat := RegisterClipboardFormat('Borland IDE Block Type');
|
|
|
|
{ we can change font only after all objects are created }
|
|
Font.Name := 'Courier New';
|
|
Font.Size := 10;
|
|
|
|
FFontCache := TList.Create;
|
|
FLineInformations := TJvLineInformationList.Create(Self);
|
|
end;
|
|
|
|
destructor TJvCustomEditorBase.Destroy;
|
|
begin
|
|
FBracketHighlighting.Free;
|
|
FErrorHighlighting.Free;
|
|
FLineInformations.Free;
|
|
FScrollBarHorz.Free;
|
|
FScrollBarVert.Free;
|
|
FEditorClient.Free;
|
|
FKeyboard.Free;
|
|
FUndoBuffer.Free;
|
|
FGutter.Free;
|
|
FontCacheClear; // free cached font instances
|
|
FFontCache.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.Assign(Source: TPersistent);
|
|
var
|
|
Src: TJvCustomEditorBase;
|
|
begin
|
|
if Source is TJvCustomEditorBase then
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
Src := TJvCustomEditorBase(Source);
|
|
|
|
FSelForeColor := Src.SelForeColor;
|
|
FSelBackColor := Src.SelBackColor;
|
|
Color := Src.Color;
|
|
RightMarginColor := Src.RightMarginColor;
|
|
{ The following options are set directly by JvHLEditorPropertyForm
|
|
FKeyboard.Assign(Src.Keyboard);
|
|
FGroupUndo := Src.GroupUndo;
|
|
FUndoAfterSave := Src.UndoAfterSave;
|
|
FTabStops := Src.TabStops;
|
|
FDoubleClickLine := Src.DoubleClickLine;
|
|
FSmartTab := Src.SmartTab;
|
|
FBackSpaceUnindents := Src.BackSpaceUnindents;
|
|
FAutoIndent := Src.AutoIndent;
|
|
FKeepTrailingBlanks := Src.KeepTrailingBlanks;
|
|
FCursorBeyondEOF := Src.CursorBeyondEOF;
|
|
FCursorBeyondEOL := Src.CursorBeyondEOL;
|
|
FBlockOverwrite := Src.BlockOverwrite;
|
|
FPersistentBlocks := Src.PersistentBlocks;}
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.WMEditCommand(var Msg: TMessage);
|
|
begin
|
|
Command(Msg.WParam);
|
|
Msg.Result := Ord(True);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.WMCompound(var Msg: TMessage);
|
|
begin
|
|
if Msg.WParam = 0 then
|
|
BeginCompound
|
|
else
|
|
EndCompound;
|
|
Msg.Result := Ord(True);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.CMResetCaptureControl(var Msg: TMessage);
|
|
begin
|
|
SetCaptureControl(TControl(Msg.LParam));
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.WMHScroll(var Msg: TWMHScroll);
|
|
begin
|
|
FScrollBarHorz.DoScroll(Msg);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.WMVScroll(var Msg: TWMVScroll);
|
|
begin
|
|
FScrollBarVert.DoScroll(Msg);
|
|
end;
|
|
|
|
|
|
|
|
procedure TJvCustomEditorBase.WMSetCursor(var Msg: TWMSetCursor);
|
|
var
|
|
P: TPoint;
|
|
begin
|
|
GetCursorPos(P);
|
|
P := ScreenToClient(P);
|
|
if (P.X < GutterWidth) and (Cursor = crIBeam) then
|
|
begin
|
|
Msg.Result := 1;
|
|
Windows.SetCursor(Screen.Cursors[crArrow])
|
|
end
|
|
else
|
|
inherited;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.WMCopy(var Msg: TMessage);
|
|
begin
|
|
DoCopy;
|
|
Msg.Result := Ord(True);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.WMCut(var Msg: TMessage);
|
|
begin
|
|
DoCut;
|
|
Msg.Result := Ord(True);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.WMPaste(var Msg: TMessage);
|
|
begin
|
|
DoPaste;
|
|
Msg.Result := Ord(True);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.WMUndo(var Msg: TMessage);
|
|
begin
|
|
Undo;
|
|
Msg.Result := Ord(True);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.WMClear(var Msg: TMessage);
|
|
begin
|
|
if not ReadOnly then
|
|
DeleteSelected;
|
|
Msg.Result := Ord(ReadOnly);
|
|
end;
|
|
|
|
|
|
|
|
procedure TJvCustomEditorBase.EMSetReadOnly(var Msg: TMessage);
|
|
begin
|
|
ReadOnly := Msg.WParam = 1;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.EMSetSelection(var Msg: TMessage);
|
|
begin
|
|
if (Msg.WParam = 0) and (Msg.LParam = -1) then
|
|
SelectAll
|
|
else
|
|
begin
|
|
SelStart := Msg.WParam;
|
|
SelLength := Msg.LParam;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.EMGetSelection(var Msg: TMessage);
|
|
var
|
|
LSelStart, LSelEnd: Integer;
|
|
begin
|
|
LSelStart := SelStart;
|
|
LSelEnd := SelStart + SelLength;
|
|
if Pointer(Msg.WParam) <> nil then
|
|
PLongint(Msg.WParam)^ := LSelStart;
|
|
if Pointer(Msg.LParam) <> nil then
|
|
PLongint(Msg.LParam)^ := LSelEnd;
|
|
if (LSelEnd > 65535) or (LSelStart > 65535) then
|
|
Msg.Result := -1
|
|
else
|
|
begin
|
|
Msg.ResultLo := LongRec(LSelStart).Lo;
|
|
Msg.ResultHi := LongRec(LSelEnd).Lo;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.EMCanUndo(var Msg: TMessage);
|
|
begin
|
|
Msg.Result := Ord(UndoBuffer.CanUndo);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.WMGetTextLength(var Msg: TMessage);
|
|
begin
|
|
Msg.Result := GetTextLen;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.UpdateEditorSize;
|
|
const
|
|
BiggestSymbol = 'W';
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (csLoading in ComponentState) or
|
|
not HandleAllocated then // CreateWnd calls this method in this case
|
|
Exit;
|
|
FEditorClient.Canvas.Font := Font;
|
|
FontCacheClear; // clear font cache
|
|
|
|
FCellRect.Height := FEditorClient.Canvas.TextHeight(BiggestSymbol) + 1;
|
|
// workaround the bug in Windows-9x
|
|
// fixed by Dmitry Rubinstain
|
|
FCellRect.Width := FEditorClient.Canvas.TextWidth(BiggestSymbol + BiggestSymbol) div 2;
|
|
|
|
SetLength(FMyDi, Max_X);
|
|
for I := 0 to High(FMyDi) do
|
|
FMyDi[I] := FCellRect.Width;
|
|
|
|
FVisibleColCount := Trunc(FEditorClient.ClientWidth / FCellRect.Width);
|
|
FVisibleRowCount := Trunc(FEditorClient.ClientHeight / FCellRect.Height);
|
|
FLastVisibleCol := FLeftCol + FVisibleColCount - 1;
|
|
FLastVisibleRow := FTopRow + FVisibleRowCount - 1;
|
|
Rows := LineCount;
|
|
Cols := Max_X_Scroll;
|
|
FScrollBarHorz.Page := FVisibleColCount;
|
|
FScrollBarVert.Page := FVisibleRowCount;
|
|
FScrollBarHorz.LargeChange := Max(FVisibleColCount, 1);
|
|
FScrollBarVert.LargeChange := Max(FVisibleRowCount, 1);
|
|
FScrollBarVert.Max := Max(1, FRows - 1 + FVisibleRowCount - 1);
|
|
|
|
FGutter.Invalidate;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.UpdateEditorView;
|
|
begin
|
|
UpdateEditorSize;
|
|
if Showing and (UpdateLock = 0) then
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.ScrollTimer(Sender: TObject);
|
|
begin
|
|
if (MouseMoveY < 0) or (MouseMoveY > ClientHeight) then
|
|
begin
|
|
if MouseMoveY < -20 then
|
|
Dec(MouseMoveYY, FVisibleRowCount)
|
|
else
|
|
if MouseMoveY < 0 then
|
|
Dec(MouseMoveYY)
|
|
else
|
|
if MouseMoveY > ClientHeight + 20 then
|
|
Inc(MouseMoveYY, FVisibleRowCount)
|
|
else
|
|
if MouseMoveY > ClientHeight then
|
|
Inc(MouseMoveYY);
|
|
PaintCaret(False);
|
|
SetSel(MouseMoveXX, MouseMoveYY);
|
|
SetCaret(MouseMoveXX, MouseMoveYY);
|
|
PaintCaret(True);
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_UNICODE}
|
|
function TJvCustomEditorBase.ExpandTabsUnicode(const S: UnicodeString): UnicodeString;
|
|
var
|
|
Ps, I: Integer;
|
|
Sp: UnicodeString;
|
|
Tabs, LenSp: Integer;
|
|
P: PChar;
|
|
{$ELSE}
|
|
function TJvCustomEditorBase.ExpandTabsAnsi(const S: AnsiString): AnsiString;
|
|
var
|
|
Ps, I: Integer;
|
|
Sp: AnsiString;
|
|
Tabs, LenSp: Integer;
|
|
P: PAnsiChar;
|
|
{$ENDIF SUPPORTS_UNICODE}
|
|
begin
|
|
Ps := Pos(Tab, S);
|
|
if Ps > 0 then
|
|
begin
|
|
// How may Tab chars?
|
|
Tabs := 1;
|
|
for I := Ps + 1 to Length(S) do
|
|
if S[I] = Tab then
|
|
Inc(Tabs);
|
|
|
|
Sp := Spaces(GetDefTabStop(0, True));
|
|
LenSp := Length(Sp);
|
|
|
|
// needed memory
|
|
SetLength(Result, Length(S) - Tabs + Tabs * LenSp);
|
|
P := {$IFDEF SUPPORTS_UNICODE}PChar{$ELSE}PAnsiChar{$ENDIF SUPPORTS_UNICODE}(Result);
|
|
|
|
// copy the chars before the Tab
|
|
if Ps > 1 then
|
|
begin
|
|
Move(S[1], P[0], Ps - 1);
|
|
Inc(P, Ps - 1);
|
|
end;
|
|
|
|
for I := Ps to Length(S) do
|
|
if S[I] <> Tab then
|
|
begin
|
|
P[0] := S[I];
|
|
Inc(P);
|
|
end
|
|
else
|
|
if LenSp > 0 then
|
|
begin
|
|
Move(Sp[1], P[0], LenSp);
|
|
Inc(P, LenSp);
|
|
end;
|
|
end
|
|
else
|
|
Result := S;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.GetDefTabStop(X: Integer; Next: Boolean): Integer;
|
|
var
|
|
I: Integer;
|
|
S: string;
|
|
A, B: Integer;
|
|
begin
|
|
if Next then
|
|
begin
|
|
I := 0;
|
|
S := Trim(SubStrBySeparator(FTabStops, I, ' '));
|
|
A := 0;
|
|
B := 1;
|
|
while S <> '' do
|
|
begin
|
|
A := B;
|
|
B := StrToInt(S) - 1;
|
|
if B > X then
|
|
begin
|
|
Result := B;
|
|
Exit;
|
|
end;
|
|
Inc(I);
|
|
S := Trim(SubStrBySeparator(FTabStops, I, ' '));
|
|
end;
|
|
{ after last tab pos }
|
|
Result := X + ((B - A) - ((X - B) mod (B - A)));
|
|
end
|
|
else
|
|
begin
|
|
I := 0;
|
|
S := Trim(SubStrBySeparator(FTabStops, I, ' '));
|
|
A := 0;
|
|
B := 0;
|
|
while S <> '' do
|
|
begin
|
|
A := B;
|
|
B := StrToInt(S) - 1;
|
|
if B >= X then
|
|
begin
|
|
Result := A;
|
|
Exit;
|
|
end;
|
|
Inc(I);
|
|
S := Trim(SubStrBySeparator(FTabStops, I, ' '));
|
|
end;
|
|
{ after last tab pos }
|
|
Result := X - ((B - A) - ((X - B) mod (B - A)));
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.TextAllChangedInternal(Unselect: Boolean);
|
|
begin
|
|
FontCacheClear;
|
|
if Unselect then
|
|
begin
|
|
FSelection.IsSelected := False;
|
|
FSelection.Selecting := False;
|
|
end;
|
|
HighlightBrackets(CaretX, CaretY);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.DoLinesChange(Sender: TObject);
|
|
begin
|
|
if FUpdateLock = 0 then
|
|
Repaint;
|
|
if CaretY >= LineCount then
|
|
begin
|
|
if LineCount = 0 then
|
|
CaretY := 0
|
|
else
|
|
CaretY := LineCount - 1;
|
|
end;
|
|
// Must update the number of rows or it would trigger Mantis 3905.
|
|
Rows := LineCount;
|
|
Changed;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.Changed;
|
|
begin
|
|
FModified := True;
|
|
if Assigned(FOnChange) then
|
|
FOnChange(Self);
|
|
StatusChanged;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.TextAllChanged;
|
|
begin
|
|
TextAllChangedInternal(True);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.StatusChanged;
|
|
begin
|
|
HighlightBrackets(CaretX, CaretY);
|
|
if Assigned(FOnChangeStatus) then
|
|
FOnChangeStatus(Self);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SelectionChanged;
|
|
begin
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.GetAttr(Line, ColBeg, ColEnd: Integer);
|
|
begin
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.ChangeAttr(Line, ColBeg, ColEnd: Integer);
|
|
|
|
procedure ChangeSelectedAttr(LineStyle: TJvLineSelectStyle);
|
|
|
|
procedure DoChange(const iBeg, iEnd: Integer);
|
|
var
|
|
I: Integer;
|
|
Color: TColor;
|
|
begin
|
|
if LineStyle = lssUnselected then
|
|
for I := iBeg to iEnd do
|
|
begin
|
|
LineAttrs[I+1].FC := SelForeColor;
|
|
LineAttrs[I+1].BC := SelBackColor;
|
|
LineAttrs[I+1].Border := clNone;
|
|
end
|
|
else
|
|
// exchange fore and background color
|
|
for I := iBeg to iEnd do
|
|
begin
|
|
Color := LineAttrs[I+1].FC;
|
|
LineAttrs[I+1].FC := LineAttrs[I+1].BC;
|
|
LineAttrs[I+1].BC := Color;
|
|
LineAttrs[I+1].Border := clNone;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
with FSelection do
|
|
begin
|
|
if SelBlockFormat = bfColumn then
|
|
begin
|
|
if (Line >= SelBegY) and (Line <= SelEndY) then
|
|
DoChange(SelBegX, SelEndX - 1 + Ord(True)); {always Inclusive}
|
|
end
|
|
else
|
|
begin
|
|
if (Line = SelBegY) and (Line = SelEndY) then
|
|
DoChange(SelBegX, SelEndX - 1 + Ord(SelBlockFormat = bfInclusive))
|
|
else
|
|
begin
|
|
if Line = SelBegY then
|
|
DoChange(SelBegX, LeftCol + SelBegX + VisibleColCount);
|
|
if (Line > SelBegY) and (Line < SelEndY) then
|
|
DoChange(ColBeg, ColEnd);
|
|
if Line = SelEndY then
|
|
DoChange(ColBeg, SelEndX - 1 + Ord(SelBlockFormat = bfInclusive));
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
I, TmpI: Integer;
|
|
LineStyle: TJvLineSelectStyle;
|
|
begin
|
|
// line style
|
|
LineStyle := LineInformations.SelectStyle[Line];
|
|
case LineStyle of
|
|
lssBreakpoint:
|
|
begin
|
|
LineAttrs[ColBeg].FC := LineInformations.BreakpointTextColor;
|
|
LineAttrs[ColBeg].BC := LineInformations.BreakpointColor;
|
|
end;
|
|
lssDebugPoint:
|
|
begin
|
|
LineAttrs[ColBeg].FC := LineInformations.DebugPointTextColor;
|
|
LineAttrs[ColBeg].BC := LineInformations.DebugPointColor;
|
|
end;
|
|
lssErrorPoint:
|
|
begin
|
|
LineAttrs[ColBeg].FC := LineInformations.ErrorPointTextColor;
|
|
LineAttrs[ColBeg].BC := LineInformations.ErrorPointColor;
|
|
end;
|
|
end;
|
|
if LineStyle <> lssUnselected then
|
|
begin
|
|
TmpI := ColEnd;
|
|
if TmpI < Max_X then
|
|
Inc(TmpI);
|
|
for I := ColBeg + 1 to TmpI do
|
|
begin
|
|
LineAttrs[I].FC := LineAttrs[ColBeg].FC;
|
|
LineAttrs[I].BC := LineAttrs[ColBeg].BC;
|
|
LineAttrs[I].Border := LineAttrs[ColBeg].Border;
|
|
end;
|
|
end;
|
|
|
|
GetBracketHighlightAttr(Line, LineAttrs);
|
|
|
|
if (Line = CaretY) and (CurrentLineHighlight <> clNone) and (CurrentLineHighlight <> clDefault) then
|
|
for I := ColBeg to ColEnd do
|
|
if LineAttrs[I].BC = Color then
|
|
LineAttrs[I].BC := CurrentLineHighlight;
|
|
|
|
if FSelection.IsSelected then
|
|
ChangeSelectedAttr(LineStyle); { we change the attributes of the chosen block [translated] }
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.GutterPaint(Canvas: TCanvas);
|
|
begin
|
|
if Assigned(FOnPaintGutter) then
|
|
FOnPaintGutter(Self, Canvas);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.GutterClick(Line: Integer);
|
|
begin
|
|
if Assigned(FOnGutterClick) then
|
|
FOnGutterClick(Self, Line);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.GutterDblClick(Line: Integer);
|
|
begin
|
|
if Assigned(FOnGutterDblClick) then
|
|
FOnGutterDblClick(Self, Line);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.BookmarkChanged(Bookmark: Integer);
|
|
begin
|
|
Gutter.Invalidate;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.CompletionIdentifier(var Cancel: Boolean);
|
|
begin
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.CompletionTemplate(var Cancel: Boolean);
|
|
begin
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.DoCompletionIdentifier(var Cancel: Boolean);
|
|
begin
|
|
if not Focused then
|
|
Cancel := True
|
|
else
|
|
begin
|
|
CompletionIdentifier(Cancel);
|
|
if Assigned(FOnCompletionIdentifier) then
|
|
FOnCompletionIdentifier(Self, Cancel);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.DoCompletionTemplate(var Cancel: Boolean);
|
|
begin
|
|
if not Focused then
|
|
Cancel := True
|
|
else
|
|
begin
|
|
CompletionTemplate(Cancel);
|
|
if Assigned(FOnCompletionTemplate) then
|
|
FOnCompletionTemplate(Self, Cancel);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.Resize;
|
|
begin
|
|
UpdateEditorSize;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.CreateWnd;
|
|
begin
|
|
inherited CreateWnd;
|
|
if FScrollBars in [ssHorizontal, ssBoth] then
|
|
FScrollBarHorz.Handle := Handle;
|
|
if FScrollBars in [ssVertical, ssBoth] then
|
|
FScrollBarVert.Handle := Handle;
|
|
FAllRepaint := True;
|
|
UpdateEditorSize;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.CreateParams(var Params: TCreateParams);
|
|
const
|
|
BorderStyles: array [TBorderStyle] of Cardinal =
|
|
(0, WS_BORDER);
|
|
ScrollStyles: array [TScrollStyle] of Cardinal =
|
|
(0, WS_HSCROLL, WS_VSCROLL, WS_HSCROLL or WS_VSCROLL);
|
|
begin
|
|
inherited CreateParams(Params);
|
|
with Params do
|
|
begin
|
|
Style := Style or BorderStyles[FBorderStyle] or ScrollStyles[FScrollBars];
|
|
if Ctl3D and (FBorderStyle = bsSingle) then
|
|
begin
|
|
Style := Style and not WS_BORDER;
|
|
ExStyle := ExStyle or WS_EX_CLIENTEDGE;
|
|
end;
|
|
WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW);
|
|
|
|
if ReadOnly then
|
|
Style := Style or ES_READONLY
|
|
else
|
|
Style := Style and not ES_READONLY;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.Loaded;
|
|
begin
|
|
inherited Loaded;
|
|
UpdateEditorSize;
|
|
end;
|
|
|
|
|
|
|
|
procedure TJvCustomEditorBase.ScrollBarScroll(Sender: TObject; ScrollCode:
|
|
TScrollCode; var ScrollPos: Integer);
|
|
begin
|
|
case ScrollCode of
|
|
scLineUp..scPageDown, {scPosition,} scTrack {, scEndScroll}:
|
|
if Sender = FScrollBarVert then
|
|
Scroll(True, ScrollPos)
|
|
else
|
|
if Sender = FScrollBarHorz then
|
|
Scroll(False, ScrollPos);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.Scroll(Vert: Boolean; ScrollPos: Integer);
|
|
var
|
|
R, RClip, RUpdate: TRect;
|
|
OldFTopRow: Integer;
|
|
OldFLeftCol: Integer;
|
|
begin
|
|
if UpdateLock = 0 then
|
|
begin
|
|
PaintCaret(False);
|
|
if Vert then
|
|
begin {Vertical Scroll}
|
|
{ optimized scrolling }
|
|
OldFTopRow := FTopRow;
|
|
FTopRow := ScrollPos;
|
|
if Abs((OldFTopRow - ScrollPos) * FCellRect.Height) < FEditorClient.Height then
|
|
begin
|
|
R := FEditorClient.ClientRect;
|
|
R.Bottom := R.Top + CellRect.Height * FVisibleRowCount;
|
|
R.Left := 0; // update gutter
|
|
RClip := R;
|
|
Inc(RClip.Bottom, CellRect.Height);
|
|
ScrollDC(
|
|
FEditorClient.Canvas.Handle, // handle of device context
|
|
0, // horizontal scroll units
|
|
(OldFTopRow - ScrollPos) * CellRect.Height, // vertical scroll units
|
|
R, // address of structure for scrolling rectangle
|
|
RClip, // address of structure for clipping rectangle
|
|
0, // handle of scrolling region
|
|
@RUpdate // address of structure for update rectangle
|
|
);
|
|
// (ahuser) WinNT seams to have problems with ScrollDC in vertical direction. (Mantis #2528)
|
|
if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion < 5) then
|
|
Dec(RUpdate.Top, CellRect.Height);
|
|
Inc(RUpdate.Bottom, CellRect.Height);
|
|
Windows.InvalidateRect(Handle, @RUpdate, False);
|
|
end
|
|
else
|
|
Invalidate;
|
|
Update;
|
|
end
|
|
else {Horizontal Scroll}
|
|
begin
|
|
{ optimized scrolling }
|
|
OldFLeftCol := FLeftCol;
|
|
FLeftCol := ScrollPos;
|
|
if FLeftCol >= Max_X then
|
|
FLeftCol := Max_X - 1;
|
|
if Abs((OldFLeftCol - ScrollPos) * CellRect.Width) < FEditorClient.Width then
|
|
begin
|
|
R := FEditorClient.ClientRect;
|
|
R.Right := R.Left + CellRect.Width * FVisibleColCount;
|
|
RClip := R;
|
|
Inc(RClip.Right, CellRect.Width);
|
|
ScrollDC(
|
|
FEditorClient.Canvas.Handle, // handle of device context
|
|
(OldFLeftCol - ScrollPos) * CellRect.Width, // horizontal scroll units
|
|
0, // vertical scroll units
|
|
R, // address of structure for scrolling rectangle
|
|
RClip, // address of structure for clipping rectangle
|
|
0, // handle of scrolling region
|
|
@RUpdate // address of structure for update rectangle
|
|
);
|
|
Inc(RUpdate.Right, CellRect.Width); // draw italic chars correctly
|
|
Windows.InvalidateRect(Handle, @RUpdate, False);
|
|
end
|
|
else
|
|
Invalidate;
|
|
Update;
|
|
end;
|
|
end
|
|
else { UpdateLock > 0 }
|
|
begin
|
|
if Vert then
|
|
FTopRow := ScrollPos
|
|
else
|
|
FLeftCol := ScrollPos;
|
|
|
|
if FLeftCol >= Max_X then
|
|
FLeftCol := Max_X - 1;
|
|
end;
|
|
FLastVisibleRow := FTopRow + FVisibleRowCount - 1;
|
|
FLastVisibleCol := FLeftCol + FVisibleColCount - 1;
|
|
if UpdateLock = 0 then
|
|
begin
|
|
DrawRightMargin;
|
|
PaintCaret(True);
|
|
end;
|
|
if Assigned(FOnScroll) then
|
|
FOnScroll(Self);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.KeyDown(var Key: Word; Shift: TShiftState);
|
|
var
|
|
Com: TEditCommand;
|
|
begin
|
|
PaintCaret(False);
|
|
try
|
|
if Completion.Visible then
|
|
begin
|
|
if Completion.DoKeyDown(Key, Shift) then
|
|
begin
|
|
IgnoreKeyPress := True;
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
Completion.FTimer.Enabled := False;
|
|
|
|
if not (ssShift in Shift) and not FMouseDown then
|
|
FSelection.Selecting := False;
|
|
|
|
if WaitSecondKey then
|
|
begin
|
|
IgnoreKeyPress := True; { Set this before calling FKeyboard.Command2()
|
|
because in FKeyboard.OnCommand2 the
|
|
Editor-window can loose focus and so the
|
|
second char will be printed. }
|
|
Com := FKeyboard.Command2(Key1, Shift1, Key, Shift);
|
|
WaitSecondKey := False;
|
|
IgnoreKeyPress := True;
|
|
end
|
|
else
|
|
begin
|
|
inherited KeyDown(Key, Shift);
|
|
Key1 := Key;
|
|
Shift1 := Shift;
|
|
Com := FKeyboard.Command(Key, Shift);
|
|
if Com = twoKeyCommand then
|
|
begin
|
|
IgnoreKeyPress := True;
|
|
WaitSecondKey := True;
|
|
end
|
|
else
|
|
IgnoreKeyPress := Com > 0;
|
|
end;
|
|
|
|
if (Com > 0) and (Com <> twoKeyCommand) then
|
|
begin
|
|
Command(Com);
|
|
if ssAlt in Shift then
|
|
begin
|
|
{ Setting the capture control to the editor prevents the VM_MENU key to
|
|
activate the mainmenu. }
|
|
PostMessage(Handle, CM_RESETCAPTURECONTROL, 0, LPARAM(GetCaptureControl));
|
|
SetCaptureControl(Self);
|
|
end;
|
|
Key := 0;
|
|
end;
|
|
|
|
if Com = ecBackspace then
|
|
Completion.DoKeyPress(Backspace);
|
|
finally
|
|
PaintCaret(True);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.KeyPress(var Key: Char);
|
|
var
|
|
Ch: Char;
|
|
begin
|
|
if IgnoreKeyPress or FReadOnly then
|
|
begin
|
|
IgnoreKeyPress := False;
|
|
Exit;
|
|
end;
|
|
|
|
PaintCaret(False);
|
|
try
|
|
if Assigned(OnKeyPress) then // do the inherited action
|
|
begin
|
|
Ch := Char(Key);
|
|
OnKeyPress(Self, Ch);
|
|
Key := Char(Ch);
|
|
end;
|
|
Command(Ord(Key));
|
|
finally
|
|
PaintCaret(True);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
var
|
|
XX, YY, SX, SY: Integer;
|
|
begin
|
|
if FDoubleClick then
|
|
begin
|
|
FDoubleClick := False;
|
|
Exit;
|
|
end;
|
|
FSelection.Selecting := False;
|
|
Completion.CloseUp(False);
|
|
Mouse2Caret(X, Y, XX, YY);
|
|
|
|
PaintCaret(False);
|
|
if (Button = mbLeft) and not (ssShift in Shift) then
|
|
begin
|
|
if ssAlt in Shift then
|
|
FSelection.SelBlockFormat := bfColumn
|
|
else
|
|
FSelection.SelBlockFormat := bfNonInclusive; // reset BlockFormat
|
|
SetUnSelected;
|
|
end;
|
|
SetFocus;
|
|
{$IFDEF MSWINDOWS}
|
|
// in MDIChilds the focus meight not be set correctly ("ActiveControl <> Control" in TCustomForm.SetActiveControl)
|
|
Windows.SetFocus(Handle);
|
|
{$ENDIF MSWINDOWS}
|
|
|
|
{--- UNDO ---}
|
|
if Button = mbLeft then
|
|
TJvBeginCompoundUndo.Create(Self);
|
|
{--- /UNDO ---}
|
|
if Button = mbLeft then
|
|
begin
|
|
if ssShift in Shift then
|
|
begin
|
|
if not FSelection.IsSelected then
|
|
begin
|
|
SetSel(FCaretX, FCaretY);
|
|
end
|
|
else
|
|
begin
|
|
SX := FSelection.SelStartX;
|
|
SY := FSelection.SelStartY;
|
|
SetUnSelected;
|
|
SetSel(SX, SY);
|
|
end;
|
|
SetSel(XX, YY);
|
|
end;
|
|
SetCaret(XX, YY);
|
|
end
|
|
else
|
|
if Button = mbRight then
|
|
SetCaret(XX, YY);
|
|
PaintCaret(True);
|
|
FMouseDown := True;
|
|
|
|
inherited MouseDown(Button, Shift, X, Y);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if FMouseDown and (ssLeft in (Shift * [ssShift, ssLeft]) ) then
|
|
begin
|
|
PaintCaret(False);
|
|
MouseMoveY := Y;
|
|
Mouse2Caret(X, Y, MouseMoveXX, MouseMoveYY);
|
|
|
|
if MouseMoveYY <= FLastVisibleRow then
|
|
begin
|
|
SetSel(MouseMoveXX, MouseMoveYY);
|
|
SetCaret(MouseMoveXX, MouseMoveYY);
|
|
end;
|
|
TimerScroll.Enabled := (Y < 0) or (Y > ClientHeight);
|
|
PaintCaret(True);
|
|
end;
|
|
inherited MouseMove(Shift, X, Y);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.MouseUp(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
var
|
|
XX, YY: Integer;
|
|
begin
|
|
if FMouseDown then
|
|
TJvEndCompoundUndo.Create(Self);
|
|
TimerScroll.Enabled := False;
|
|
FMouseDown := False;
|
|
inherited MouseUp(Button, Shift, X, Y);
|
|
|
|
// Gutter click
|
|
if (X >= 0) and (X < FGutterWidth) then
|
|
begin
|
|
Mouse2Caret(X, Y, XX, YY);
|
|
GutterClick(YY);
|
|
end;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean;
|
|
var
|
|
WheelDirection: Integer;
|
|
begin
|
|
Result := True;
|
|
if ssShift in Shift then
|
|
begin
|
|
// Shift+Wheel: move caret up and down
|
|
if WheelDelta > 0 then
|
|
Command(ecUp)
|
|
else
|
|
Command(ecDown);
|
|
end
|
|
else
|
|
if ssCtrl in Shift then
|
|
begin
|
|
if WheelDelta < 0 then
|
|
WheelDirection := -1
|
|
else
|
|
WheelDirection := 1;
|
|
// Ctrl+Wheel: scrollbar large change
|
|
FScrollBarVert.Position := FScrollBarVert.Position - WheelDirection * FScrollBarVert.LargeChange;
|
|
Scroll(True, FScrollBarVert.Position);
|
|
end
|
|
else
|
|
if Shift = [] then
|
|
begin
|
|
FScrollBarVert.Position := FScrollBarVert.Position - WheelDelta div 40;
|
|
Scroll(True, FScrollBarVert.Position);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.DblClick;
|
|
var
|
|
pt: TPoint;
|
|
XX, YY: Integer;
|
|
begin
|
|
FDoubleClick := True;
|
|
if Assigned(FOnDblClick) then
|
|
FOnDblClick(Self);
|
|
|
|
pt := ScreenToClient(Mouse.CursorPos);
|
|
if (pt.X >= 0) and (pt.X < FGutterWidth) then
|
|
begin
|
|
Mouse2Caret(pt.X, pt.Y, XX, YY);
|
|
GutterDblClick(YY);
|
|
end
|
|
else
|
|
if FDoubleClickLine then
|
|
begin
|
|
PaintCaret(False);
|
|
SetSel(0, FCaretY);
|
|
if FCaretY = LineCount - 1 then
|
|
begin
|
|
SetSel(LineLength[FCaretY], FCaretY);
|
|
SetCaret(LineLength[FCaretY], FCaretY);
|
|
end
|
|
else
|
|
begin
|
|
SetSel(0, FCaretY + 1);
|
|
SetCaret(0, FCaretY + 1);
|
|
end;
|
|
PaintCaret(True);
|
|
end
|
|
else
|
|
if LineCount > 0 then
|
|
SelectWordOnCaret;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.GetDlgCode(var Code: TDlgCodes);
|
|
begin
|
|
Code := [dcWantArrows, dcWantTab, dcWantChars, dcWantMessage];
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.FocusSet(PrevWnd: THandle);
|
|
begin
|
|
inherited FocusSet(PrevWnd);
|
|
CreateCaret(Handle, 0, 2, CellRect.Height - 2);
|
|
PaintCaret(True);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.FocusKilled(NextWnd: THandle);
|
|
begin
|
|
inherited FocusKilled(NextWnd);
|
|
Completion.CloseUp(False);
|
|
DestroyCaret;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.DoPaste;
|
|
begin
|
|
if not FReadOnly then
|
|
PostCommand(ecClipboardPaste);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.DoCopy;
|
|
begin
|
|
PostCommand(ecClipboardCopy);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.DoCut;
|
|
begin
|
|
if not FReadOnly then
|
|
PostCommand(ecClipboardCut);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.CursorChanged;
|
|
var
|
|
P: TPoint;
|
|
begin
|
|
inherited CursorChanged;
|
|
if HandleAllocated then
|
|
begin
|
|
GetCursorPos(P);
|
|
P := ScreenToClient(P);
|
|
if (P.X < GutterWidth) and (Cursor = crIBeam) then
|
|
SetCursor(Screen.Cursors[crArrow]);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.FontChanged;
|
|
begin
|
|
inherited FontChanged;
|
|
if HandleAllocated then
|
|
UpdateEditorSize;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.DoEraseBackground(Canvas: TCanvas; Param: Integer): Boolean;
|
|
begin
|
|
Result := False; // no background erase
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetGutterWidth(AWidth: Integer);
|
|
begin
|
|
if FGutterWidth <> AWidth then
|
|
begin
|
|
FGutterWidth := AWidth;
|
|
UpdateEditorSize;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetGutterColor(AColor: TColor);
|
|
begin
|
|
if FGutterColor <> AColor then
|
|
begin
|
|
FGutterColor := AColor;
|
|
Gutter.Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetBorderStyle(Value: TBorderStyle);
|
|
begin
|
|
if FBorderStyle <> Value then
|
|
begin
|
|
FBorderStyle := Value;
|
|
RecreateWnd;
|
|
end;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.GetKeepTrailingBlanks: Boolean;
|
|
begin
|
|
Result := FKeepTrailingBlanks or not FCursorBeyondEOL;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.GetSelStart: Integer;
|
|
begin
|
|
if FSelection.IsSelected then
|
|
Result := PosFromCaret(FSelection.SelBegX, FSelection.SelBegY)
|
|
else
|
|
Result := PosFromCaret(FCaretX, FCaretY);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetSelStart(ASelStart: Integer);
|
|
begin
|
|
with FSelection do
|
|
begin
|
|
IsSelected := False;
|
|
Selecting := False;
|
|
CaretFromPos(ASelStart, SelBegX, SelBegY);
|
|
SetCaretInternal(SelBegX, SelBegY);
|
|
SetSelLength(0);
|
|
MakeRowVisible(SelBegY);
|
|
// PaintSelection;
|
|
// EditorPaint;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetSelLength(ASelLength: Integer);
|
|
begin
|
|
with FSelection do
|
|
begin
|
|
IsSelected := ASelLength > 0;
|
|
Selecting := False;
|
|
CaretFromPos(SelStart + ASelLength, SelEndX, SelEndY);
|
|
SetSelUpdateRegion(SelBegY, SelEndY);
|
|
SetCaretInternal(SelEndX, SelEndY);
|
|
//PaintSelection;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.GetSelLength: Integer;
|
|
var
|
|
I: Integer;
|
|
Len, CLen: Integer;
|
|
begin
|
|
Result := 0;
|
|
with FSelection do
|
|
begin
|
|
if not IsSelected then
|
|
Exit;
|
|
|
|
if (SelBegY < 0) or (SelBegY > LineCount - 1) or (SelEndY < 0) or
|
|
(SelEndY > LineCount - 1) then
|
|
begin
|
|
if BeepOnError then
|
|
Beep;
|
|
Exit;
|
|
end;
|
|
|
|
if SelBlockFormat = bfColumn then
|
|
begin
|
|
for I := SelBegY to SelEndY do
|
|
begin
|
|
CLen := LineLength[I] - SelBegX;
|
|
if CLen < 0 then
|
|
CLen := 0;
|
|
if CLen > SelEndX - SelBegX + 1 then
|
|
CLen := SelEndX - SelBegX + 1;
|
|
|
|
Inc(Result, CLen + sLineBreakLen);
|
|
end;
|
|
if Result > 0 then
|
|
Dec(Result, sLineBreakLen);
|
|
end
|
|
else
|
|
begin
|
|
if SelBegY = SelEndY then
|
|
begin
|
|
Result := SelEndX - SelBegX + Ord(SelBlockFormat = bfInclusive);
|
|
if SelBegX + Result > LineLength[SelEndY] then
|
|
Result := LineLength[SelEndY] - SelBegX;
|
|
if Result < 0 then
|
|
Result := 0;
|
|
end
|
|
else
|
|
begin
|
|
Result := LineLength[SelBegY] - SelBegX;
|
|
if Result < 0 then
|
|
Result := 0;
|
|
for I := SelBegY + 1 to SelEndY - 1 do
|
|
Inc(Result, sLineBreakLen + LineLength[I]);
|
|
|
|
Len := SelEndX + Ord(SelBlockFormat = bfInclusive);
|
|
if Len > LineLength[SelEndY] then
|
|
Len := LineLength[SelEndY];
|
|
Result := Result + sLineBreakLen + Len;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetSelBlockFormat(Value: TJvSelBlockFormat);
|
|
begin
|
|
Command(ecInclusiveBlock + Ord(Value));
|
|
end;
|
|
|
|
function TJvCustomEditorBase.GetSelBlockFormat: TJvSelBlockFormat;
|
|
begin
|
|
Result := FSelection.SelBlockFormat;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetMode(Index: Integer; Value: Boolean);
|
|
begin
|
|
if Index = 0 then
|
|
begin
|
|
if FInsertMode <> Value then
|
|
begin
|
|
FInsertMode := Value;
|
|
StatusChanged;
|
|
end;
|
|
end
|
|
else {1 :}
|
|
begin
|
|
if HandleAllocated then
|
|
begin
|
|
if Value then
|
|
SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) or ES_READONLY)
|
|
else
|
|
SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) and not ES_READONLY);
|
|
end;
|
|
if FReadOnly <> Value then
|
|
begin
|
|
FReadOnly := Value;
|
|
StatusChanged;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetCaretPosition(Index, Pos: Integer);
|
|
begin
|
|
if Index = 0 then
|
|
SetCaret(Pos, FCaretY)
|
|
else
|
|
SetCaret(FCaretX, Pos);
|
|
|
|
// persistent blocks:
|
|
if FSelection.IsSelected then
|
|
begin
|
|
with FSelection do
|
|
if ((FCaretX < SelBegX) and (CaretY <= SelBegY)) or
|
|
((FCaretX >= SelEndX) and (CaretY >= SelEndY)) then
|
|
FPersistentBlocksCaretChanged := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetCols(ACols: Integer);
|
|
begin
|
|
if FCols <> ACols then
|
|
begin
|
|
FCols := Max(ACols, 1);
|
|
FScrollBarHorz.Max := FCols - 1;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetRows(ARows: Integer);
|
|
begin
|
|
if FRows <> ARows then
|
|
begin
|
|
FRows := Max(ARows, 1);
|
|
FScrollBarVert.Max := Max(1, FRows - 1 + FVisibleRowCount - 1);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetScrollBars(Value: TScrollStyle);
|
|
begin
|
|
if FScrollBars <> Value then
|
|
begin
|
|
FScrollBars := Value;
|
|
RecreateWnd;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetRightMarginVisible(Value: Boolean);
|
|
begin
|
|
if FRightMarginVisible <> Value then
|
|
begin
|
|
FRightMarginVisible := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetRightMargin(Value: Integer);
|
|
begin
|
|
if FRightMargin <> Value then
|
|
begin
|
|
FRightMargin := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetRightMarginColor(Value: TColor);
|
|
begin
|
|
if FRightMarginColor <> Value then
|
|
begin
|
|
FRightMarginColor := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetSelBackColor(const Value: TColor);
|
|
begin
|
|
if Value <> FSelBackColor then
|
|
begin
|
|
FSelBackColor := Value;
|
|
if FSelection.IsSelected then
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetSelForeColor(const Value: TColor);
|
|
begin
|
|
if Value <> FSelForeColor then
|
|
begin
|
|
FSelForeColor := Value;
|
|
if FSelection.IsSelected then
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.GetPopupMenu: TPopupMenu;
|
|
begin
|
|
Result := inherited GetPopupMenu;
|
|
if (Result = nil) and UseFixedPopup then
|
|
Result := FixedDefaultEditPopup(Self);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.LockUpdate;
|
|
begin
|
|
Inc(FUpdateLock);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.UnlockUpdate;
|
|
begin
|
|
Dec(FUpdateLock);
|
|
end;
|
|
|
|
function TJvCustomEditorBase.GetClipboardBlockFormat: TJvSelBlockFormat;
|
|
var
|
|
Data: THandle;
|
|
begin
|
|
Result := bfNonInclusive;
|
|
if Clipboard.HasFormat(BlockTypeFormat) then
|
|
begin
|
|
Clipboard.Open;
|
|
Data := GetClipboardData(BlockTypeFormat);
|
|
try
|
|
if Data <> 0 then
|
|
Result := TJvSelBlockFormat(PInteger(GlobalLock(Data))^);
|
|
finally
|
|
if Data <> 0 then
|
|
GlobalUnlock(Data);
|
|
Clipboard.Close;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetClipboardBlockFormat(const Value: TJvSelBlockFormat);
|
|
var
|
|
Data: THandle;
|
|
DataPtr: Pointer;
|
|
begin
|
|
Clipboard.Open;
|
|
try
|
|
Data := GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, 1);
|
|
try
|
|
DataPtr := GlobalLock(Data);
|
|
try
|
|
Move(Value, DataPtr^, 1);
|
|
SetClipboardData(BlockTypeFormat, Data);
|
|
finally
|
|
GlobalUnlock(Data);
|
|
end;
|
|
except
|
|
GlobalFree(Data);
|
|
raise;
|
|
end;
|
|
finally
|
|
Clipboard.Close;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetSel(SelX, SelY: Integer);
|
|
var
|
|
LineLen: Integer;
|
|
|
|
procedure UpdateSelected;
|
|
var
|
|
iR: Integer;
|
|
begin
|
|
with FSelection do
|
|
begin
|
|
if SelBlockFormat = bfColumn then
|
|
begin
|
|
if FUpdateSelBegY < SelBegY then
|
|
for iR := FUpdateSelBegY to SelBegY do
|
|
PaintLine(iR, -1, -1);
|
|
for iR := SelBegY to SelEndY do
|
|
PaintLine(iR, -1, -1);
|
|
if FUpdateSelEndY > SelEndY then
|
|
for iR := SelEndY to FUpdateSelEndY do
|
|
PaintLine(iR, -1, -1);
|
|
end
|
|
else
|
|
begin
|
|
if FUpdateSelBegY < SelBegY then
|
|
for iR := FUpdateSelBegY to SelBegY do
|
|
PaintLine(iR, -1, -1)
|
|
else
|
|
for iR := SelBegY to FUpdateSelBegY do
|
|
PaintLine(iR, -1, -1);
|
|
if FUpdateSelEndY < SelEndY then
|
|
for iR := FUpdateSelEndY to SelEndY do
|
|
PaintLine(iR, -1, -1)
|
|
else
|
|
for iR := SelEndY to FUpdateSelEndY do
|
|
PaintLine(iR, -1, -1);
|
|
end;
|
|
|
|
SelectionChanged;
|
|
if Assigned(FOnSelectionChange) then
|
|
FOnSelectionChange(Self);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
with FSelection do
|
|
begin
|
|
{--- UNDO ---}
|
|
TJvSelectUndo.Create(Self, FCaretX, FCaretY);
|
|
{--- /UNDO ---}
|
|
if SelX < 0 then
|
|
SelX := 0;
|
|
if SelY < 0 then
|
|
SelY := 0;
|
|
if SelY >= LineCount then
|
|
begin
|
|
if LineCount = 0 then
|
|
SelY := 0 // select none
|
|
else
|
|
begin
|
|
SelY := LineCount - 1; // select last line
|
|
if not (FSelection.SelBlockFormat in [bfLine, bfColumn]) then
|
|
SelX := LineLength[SelY]; // with all text
|
|
end;
|
|
end;
|
|
if not (SelBlockFormat in [bfLine, bfColumn]) then
|
|
begin
|
|
if (LineCount > 0) and (SelY < LineCount) then
|
|
begin
|
|
LineLen := LineLength[SelY];
|
|
if SelX > LineLen then
|
|
SelX := LineLen; // only text not the whole line
|
|
end;
|
|
end;
|
|
|
|
if FPersistentBlocks then
|
|
begin
|
|
if FPersistentBlocksCaretChanged then
|
|
begin
|
|
IsSelected := False;
|
|
Selecting := False;
|
|
end;
|
|
FPersistentBlocksCaretChanged := False;
|
|
end;
|
|
|
|
if not Selecting then
|
|
begin
|
|
SelStartX := SelX;
|
|
SelStartY := SelY;
|
|
SelEndX := SelX;
|
|
SelEndY := SelY;
|
|
SelBegX := SelX;
|
|
SelBegY := SelY;
|
|
IsSelected := False;
|
|
Selecting := True;
|
|
if SelBlockFormat = bfLine then
|
|
AdjustSelLineMode(False); // Restore
|
|
end
|
|
else
|
|
begin
|
|
if SelBlockFormat = bfLine then
|
|
AdjustSelLineMode(True); // Restore
|
|
|
|
FUpdateSelBegY := SelBegY;
|
|
FUpdateSelEndY := SelEndY;
|
|
|
|
if SelY <= SelStartY then
|
|
begin
|
|
SelBegY := SelY;
|
|
SelEndY := SelStartY;
|
|
end;
|
|
if SelY >= SelStartY then
|
|
begin
|
|
SelBegY := SelStartY;
|
|
SelEndY := SelY;
|
|
end;
|
|
|
|
if (SelY < SelStartY) or ((SelY = SelStartY) and (SelX <= SelStartX)) then
|
|
if (SelBlockFormat = bfColumn) and (SelX > SelStartX) then
|
|
begin
|
|
SelBegX := SelStartX;
|
|
SelEndX := SelX;
|
|
end
|
|
else
|
|
begin
|
|
SelBegX := SelX;
|
|
SelEndX := SelStartX;
|
|
end;
|
|
if (SelY > SelStartY) or ((SelY = SelStartY) and (SelX >= SelStartX)) then
|
|
if (SelBlockFormat = bfColumn) and (SelX < SelStartX) then
|
|
begin
|
|
SelBegX := SelX;
|
|
SelEndX := SelStartX;
|
|
end
|
|
else
|
|
begin
|
|
SelBegX := SelStartX;
|
|
SelEndX := SelX;
|
|
end;
|
|
|
|
if SelBlockFormat = bfLine then
|
|
begin
|
|
// save line mode X values
|
|
SelLineOrgBegX := SelBegX;
|
|
SelLineOrgEndX := SelEndX;
|
|
SelBegX := 0;
|
|
SelEndX := Max_X;
|
|
end;
|
|
|
|
if (SelBegY < SelEndY) or ((SelBegY = SelEndY) and (SelBegX < SelEndX)) then
|
|
IsSelected := True
|
|
else
|
|
IsSelected := False;
|
|
end;
|
|
|
|
if FCompound = 0 then
|
|
UpdateSelected;
|
|
SetSelUpdateRegion(SelBegY, SelEndY);
|
|
end;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.IsNewSelection: Boolean;
|
|
begin
|
|
if FPersistentBlocks then
|
|
Result := (not FSelection.IsSelected) or FPersistentBlocksCaretChanged
|
|
else
|
|
Result := (not FSelection.IsSelected);
|
|
end;
|
|
|
|
function TJvCustomEditorBase.IsEmptySelection: Boolean;
|
|
begin
|
|
with FSelection do
|
|
Result := IsSelected and (SelBegX = SelEndX) and (SelBegY = SelEndY);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.PaintSelection;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := FUpdateSelBegY to FUpdateSelEndY do
|
|
PaintLine(I, -1, -1);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetUnSelected;
|
|
begin
|
|
if FSelection.IsSelected then
|
|
begin
|
|
FSelection.IsSelected := False;
|
|
FSelection.Selecting := False;
|
|
{--- UNDO ---}
|
|
TJvUnselectUndo.Create(Self, FCaretX, FCaretY);
|
|
{--- /UNDO ---}
|
|
PaintSelection;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.RemoveSelectedBlock;
|
|
begin
|
|
if FSelection.IsSelected then
|
|
begin
|
|
if FBlockOverwrite and not FPersistentBlocks then
|
|
DeleteSelected
|
|
else
|
|
if not FPersistentBlocks then
|
|
SetUnSelected;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.PersistentBlocksSetUnSelected;
|
|
begin
|
|
FPersistentBlocksCaretChanged := True;
|
|
if not FPersistentBlocks then
|
|
SetUnSelected;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetSelUpdateRegion(BegY, EndY: Integer);
|
|
begin
|
|
if FUpdateSelBegY > BegY then
|
|
FUpdateSelBegY := BegY;
|
|
if FUpdateSelEndY < EndY then
|
|
FUpdateSelEndY := EndY;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.AdjustSelLineMode(Restore: Boolean);
|
|
begin
|
|
with FSelection do
|
|
begin
|
|
if not Restore then
|
|
begin
|
|
SelLineOrgBegX := SelBegX;
|
|
SelLineOrgEndX := SelEndX;
|
|
SelBegX := 0;
|
|
SelEndX := Max_X;
|
|
end
|
|
else
|
|
begin
|
|
SelBegX := SelLineOrgBegX;
|
|
SelEndX := SelLineOrgEndX;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.AdjustPersistentBlockSelection(X, Y: Integer;
|
|
Mode: TAdjustPersistentBlockMode; Args: array of Integer);
|
|
begin
|
|
// persistent blocks: adjust selection
|
|
if (not FPersistentBlocks) or (not FSelection.IsSelected) then
|
|
Exit;
|
|
|
|
if (FSelection.SelBlockFormat = bfColumn) and
|
|
not (Mode in [amDeleteLine, amLineConcat, amLineBreak]) then
|
|
Exit;
|
|
|
|
with FSelection do
|
|
begin
|
|
case Mode of
|
|
amInsert: // X=InsertCaretX, Y=InsertCaretY, Args[0]=char count
|
|
begin
|
|
if (Y = SelBegY) and (X <= SelBegX) then
|
|
Inc(SelBegX, Args[0]);
|
|
if (Y = SelEndY) and (X < SelEndX) then
|
|
Inc(SelEndX, Args[0]);
|
|
end;
|
|
amDelete: // X=InsertCaretX, Y=InsertCaretY, Args[0]=char count
|
|
begin
|
|
if (Y = SelBegY) and (X <= SelBegX) then
|
|
Dec(SelBegX, Args[0]);
|
|
if (Y = SelEndY) and (X <= SelEndX) then
|
|
Dec(SelEndX, Args[0]);
|
|
end;
|
|
amDeleteLine: // Y=line to delete
|
|
begin
|
|
// one line selection
|
|
if (Y = SelBegY) and (SelEndY = SelBegY) then
|
|
begin
|
|
IsSelected := False;
|
|
Selecting := False;
|
|
end
|
|
else
|
|
begin
|
|
if Y < SelBegY then
|
|
Dec(SelBegY);
|
|
if Y < SelEndY then
|
|
Dec(SelEndY);
|
|
end;
|
|
end;
|
|
amLineBreak: // X=BreakCaretX, Y=BreakCaretY
|
|
begin
|
|
if Y < SelBegY then
|
|
begin
|
|
// move down
|
|
Inc(SelBegY);
|
|
Inc(SelEndY);
|
|
end
|
|
else
|
|
if Y <= SelEndY then
|
|
begin
|
|
if (Y = SelBegY) and (X <= SelBegX) then
|
|
begin
|
|
// LineBreak in the first line
|
|
Dec(SelBegX, X);
|
|
if (SelBegY = SelEndY) and (SelBlockFormat <> bfColumn) then // one line selection
|
|
Dec(SelEndX, X);
|
|
Inc(SelBegY);
|
|
Inc(SelEndY);
|
|
end
|
|
else
|
|
if Y < SelEndY then
|
|
begin
|
|
// LineBreak in selection
|
|
Inc(SelEndY);
|
|
end
|
|
else
|
|
if {(Y = SelEndY) and} (X < SelEndX) and (SelBlockFormat <> bfColumn) then
|
|
begin
|
|
// LineBreak in the last line
|
|
SelEndX := SelEndX - X;
|
|
Inc(SelEndY);
|
|
end;
|
|
end;
|
|
end;
|
|
amLineConcat: // X=CaretX, Y=CaretY, Args[0]=ConcatCaretX, Args[1]=ConcatCaretY
|
|
begin
|
|
if Y < SelBegY then
|
|
begin
|
|
// move up
|
|
Dec(SelBegY);
|
|
Dec(SelEndY);
|
|
end
|
|
else
|
|
if Y <= SelEndY then
|
|
begin
|
|
if (Y = SelBegY) and (X <= SelBegX) then
|
|
begin
|
|
// LineConcat in the first line
|
|
Dec(SelBegX, X - Args[X]);
|
|
if (SelBegY = SelEndY) and (SelBlockFormat <> bfColumn) then // one line selection
|
|
Inc(SelEndX, X - Args[X]);
|
|
Dec(SelBegY);
|
|
Dec(SelEndY);
|
|
end
|
|
else
|
|
if Y < SelEndY then
|
|
// LineConcat in selection
|
|
Dec(SelEndY)
|
|
else
|
|
if {(Y = SelEndY) and} (X <= SelEndX) and (SelBlockFormat <> bfColumn) then
|
|
begin
|
|
// LineConcat in the last line
|
|
Inc(SelEndX, LineLength[Args[1]]);
|
|
Dec(SelEndY);
|
|
end;
|
|
end;
|
|
end;
|
|
end; // case
|
|
|
|
if SelBegY < 0 then
|
|
SelBegY := 0;
|
|
if (SelEndY < SelBegY) or (SelBegY >= LineCount) then
|
|
SetUnSelected;
|
|
if SelBegX < 0 then
|
|
SelBegX := 0;
|
|
if SelEndX > Max_X then
|
|
SelEndX := Max_X;
|
|
if (SelEndX < SelBegX) and (SelBegY = SelEndY) then
|
|
SetUnSelected;
|
|
|
|
// set update region
|
|
SetSelUpdateRegion(SelBegY, SelEndY);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.Paint;
|
|
var
|
|
I: Integer;
|
|
ECR: TRect;
|
|
BX, EX, BY, EY: Integer;
|
|
begin
|
|
if (UpdateLock > 0) or (CellRect.Width <= 1) or (CellRect.Height <= 1) then
|
|
Exit;
|
|
PaintCaret(False);
|
|
|
|
ECR := FEditorClient.Canvas.ClipRect;
|
|
OffsetRect(ECR, -FGutterWidth, 0);
|
|
if FAllRepaint then
|
|
ECR := FEditorClient.BoundsRect;
|
|
BX := ECR.Left div CellRect.Width - 1;
|
|
EX := ECR.Right div CellRect.Width + 1;
|
|
BY := ECR.Top div CellRect.Height;
|
|
EY := ECR.Bottom div CellRect.Height + 1;
|
|
for I := BY to EY do
|
|
PaintLine(FTopRow + I, FLeftCol + BX, FLeftCol + EX + 1);
|
|
|
|
PaintCaret(True);
|
|
FGutter.Paint;
|
|
FAllRepaint := False;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.PaintLine(Line: Integer; ColBeg, ColEnd: Integer);
|
|
var
|
|
R: TRect;
|
|
ColPainted: Integer;
|
|
begin
|
|
if (Line < FTopRow) or (Line > FTopRow + FVisibleRowCount) then
|
|
Exit;
|
|
if ColBeg < FLeftCol then
|
|
ColBeg := FLeftCol;
|
|
if (ColEnd < 0) or (ColEnd > FLeftCol + FVisibleColCount) then
|
|
ColEnd := FLeftCol + FVisibleColCount;
|
|
ColEnd := Min(ColEnd, Max_X - 1);
|
|
|
|
ColPainted := ColBeg;
|
|
if (Line >= 0) and (Line < LineCount) then
|
|
PaintLineText(Line, ColBeg, ColEnd, ColPainted)
|
|
else
|
|
begin
|
|
if (Line = CaretY) and (CurrentLineHighlight <> clNone) and (CurrentLineHighlight <> clDefault) then
|
|
FEditorClient.Canvas.Brush.Color := CurrentLineHighlight
|
|
else
|
|
FEditorClient.Canvas.Brush.Color := Color;
|
|
FEditorClient.Canvas.FillRect(Bounds(FEditorClient.Left, (Line - FTopRow) *
|
|
CellRect.Height, 1, CellRect.Height));
|
|
end;
|
|
{right part}
|
|
R := Bounds(CalcCellRect(ColPainted - FLeftCol, Line - FTopRow).Left,
|
|
(Line - FTopRow) * CellRect.Height,
|
|
(FLeftCol + FVisibleColCount - ColPainted + 2) * CellRect.Width,
|
|
CellRect.Height);
|
|
{if the line is selected, paint right empty space with selected background}
|
|
if FSelection.IsSelected and (FSelection.SelBlockFormat in [bfInclusive, bfLine, bfNonInclusive]) and
|
|
(Line >= FSelection.SelBegY) and (Line < FSelection.SelEndY) then
|
|
FEditorClient.Canvas.Brush.Color := FSelBackColor
|
|
else
|
|
if (Line = CaretY) and (CurrentLineHighlight <> clNone) and (CurrentLineHighlight <> clDefault) then
|
|
FEditorClient.Canvas.Brush.Color := CurrentLineHighlight
|
|
else
|
|
FEditorClient.Canvas.Brush.Color := Color;
|
|
FEditorClient.Canvas.FillRect(R);
|
|
DrawRightMargin;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.PaintLine(Line: Integer);
|
|
begin
|
|
PaintLine(Line, -1, -1);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.GetBracketHighlightAttr(Line: Integer; var Attrs: TLineAttrs);
|
|
|
|
procedure GetHighlightBeginEnd(const R: TRect);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (R.Left >= 0) and // R valid
|
|
(Line >= R.Top) and (Line <= R.Bottom) and (R.Left >= 0) and (R.Right <= Max_X) then
|
|
for I := R.Left to R.Right do
|
|
begin
|
|
if BracketHighlighting.FontColor <> clNone then
|
|
Attrs[I].FC := BracketHighlighting.FontColor;
|
|
if BracketHighlighting.Color <> clNone then
|
|
Attrs[I].BC := BracketHighlighting.Color;
|
|
Attrs[I].Border := BracketHighlighting.BorderColor;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if BracketHighlighting.Active then
|
|
begin
|
|
GetHighlightBeginEnd(FBracketHighlighting.FStart);
|
|
GetHighlightBeginEnd(FBracketHighlighting.FStop);
|
|
end;
|
|
end;
|
|
|
|
{ *****************************************************************************}
|
|
{ CompareInStrInternal and CompareInTextInternal are only used by
|
|
HighlightBrackets(). They are too special in their parameters and should not
|
|
be moved to JvJCLUtils.pas. }
|
|
|
|
function CompareInStrInternal(const S: string; Index: Integer; const SubStr: string; LenSubStr: Integer): Boolean;
|
|
{ Index is zero based for speed optimization }
|
|
var
|
|
J, I, EndIndex: Integer;
|
|
begin
|
|
Result := False;
|
|
EndIndex := Index + LenSubStr - 1;
|
|
if EndIndex < Length(S) then
|
|
begin
|
|
J := 0;
|
|
for I := Index to EndIndex do
|
|
begin
|
|
if S[I + 1] <> SubStr[J + 1] then
|
|
Exit;
|
|
Inc(J);
|
|
end;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
function CompareInTextInternal(const S: string; Index: Integer; const SubStr: string; LenSubStr: Integer): Boolean;
|
|
{ Index is zero based for speed optimization }
|
|
{ SubStr is always in lowercase }
|
|
var
|
|
I, J, EndIndex: Integer;
|
|
Ch: Char;
|
|
begin
|
|
Result := False;
|
|
EndIndex := Index + LenSubStr - 1;
|
|
if EndIndex < Length(S) then
|
|
begin
|
|
J := 0;
|
|
for I := Index to EndIndex do
|
|
begin
|
|
Ch := S[I + 1];
|
|
if not CharInSet(Ch, ['A'..'Z']) then
|
|
begin
|
|
if Ch <> SubStr[J + 1] then
|
|
Exit
|
|
end
|
|
else
|
|
begin
|
|
if Char(Byte(Ch) - Ord('A') + Ord('a')) <> SubStr[J + 1] then
|
|
Exit;
|
|
end;
|
|
Inc(J);
|
|
end;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.HighlightBrackets(X, Y: Integer; BetweenSearch: Boolean = False);
|
|
const
|
|
Separators: TSysCharSet = [#0, ' ', '-', #13, #10, '.', ',', '/', '\', '#', '"', '''',
|
|
':', '+', '%', '*', '(', ')', ';', '=', '{', '}', '[', ']', '{', '}', '<', '>'];
|
|
var
|
|
Text: string;
|
|
SearchDir: Integer;
|
|
SearchStart: string;
|
|
SearchEnd: string;
|
|
SearchOpen: Integer;
|
|
CaseSensitive: Boolean;
|
|
IsBracketCompare: Boolean;
|
|
LenSearchEnd, LenSearchStart, LenText: Integer;
|
|
CmpProc: function(const S: string; Index: Integer; const SubStr: string; LenSubStr: Integer): Boolean;
|
|
StringMap: TDynBoolArray;
|
|
R: TRect;
|
|
begin
|
|
StringMap := nil;
|
|
{ remove last highlighting }
|
|
if BracketHighlighting.FStart.Left > -1 then
|
|
begin
|
|
BracketHighlighting.FStart.Left := -1; // invalidate
|
|
PaintLine(BracketHighlighting.FStart.Top);
|
|
end;
|
|
if FBracketHighlighting.FStop.Left > -1 then
|
|
begin
|
|
BracketHighlighting.FStop.Left := -1; // invalidate
|
|
PaintLine(BracketHighlighting.FStop.Top);
|
|
end;
|
|
|
|
if not BracketHighlighting.Active or not Visible or not Enabled then
|
|
Exit;
|
|
|
|
if (Y >= 0) and {$IFDEF SUPPORTS_UNICODE}GetUnicodeTextLine{$ELSE}GetAnsiTextLine{$ENDIF SUPPORTS_UNICODE}(Y, Text) and (X >= 0) and (X < Length(Text)) then
|
|
begin
|
|
LenText := Length(Text);
|
|
|
|
// Create string map
|
|
StringMap := BracketHighlighting.CreateStringMap(Text);
|
|
if StringMap[X] then
|
|
Exit; // we are in a string => nothing to do
|
|
|
|
SearchDir := 0; // nothing to search
|
|
CaseSensitive := False;
|
|
IsBracketCompare := True;
|
|
|
|
// obtain search direction and end-char
|
|
if CharInSet(Text[X + 1], ['(', '{', '[']) then
|
|
begin
|
|
SearchDir := +1;
|
|
SearchStart := Text[X + 1];
|
|
case Text[X + 1] of
|
|
'(': SearchEnd := ')';
|
|
'{': SearchEnd := '}';
|
|
'[': SearchEnd := ']';
|
|
end;
|
|
end
|
|
else
|
|
if CharInSet(Text[X + 1], [')', '}', ']']) then
|
|
begin
|
|
SearchDir := -1;
|
|
SearchStart := Text[X + 1];
|
|
case Text[X + 1] of
|
|
')': SearchEnd := '(';
|
|
'}': SearchEnd := '{';
|
|
']': SearchEnd := '[';
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
IsBracketCompare := False;
|
|
// Text search
|
|
SearchStart := {$IFDEF SUPPORTS_UNICODE}GetUnicodeWordOnCaret{$ELSE}GetAnsiWordOnCaret{$ENDIF SUPPORTS_UNICODE};
|
|
while (X >= 0) and not CharInSet(Text[X + 1], Separators) do
|
|
Dec(X);
|
|
Inc(X);
|
|
|
|
GetBracketHighlightingWords(SearchDir, SearchStart, SearchEnd, CaseSensitive);
|
|
|
|
{ if (SearchDir = 0) or (SearchStart = '') or (SearchEnd = '') then
|
|
begin
|
|
GetBracketHighlightingComments(SearchDir, SearchStart, SearchEnd);
|
|
end;}
|
|
end;
|
|
|
|
if (SearchDir <> 0) and (SearchStart <> '') and (SearchEnd <> '') then
|
|
begin
|
|
BracketHighlighting.FStart.TopLeft := Point(X + 1, Y);
|
|
BracketHighlighting.FStart.BottomRight := Point(X + 1 + Length(SearchStart) - 1, Y);
|
|
|
|
SearchOpen := 1;
|
|
LenSearchStart := Length(SearchStart);
|
|
LenSearchEnd := Length(SearchEnd);
|
|
|
|
if (not CaseSensitive) and not IsBracketCompare then
|
|
begin
|
|
SearchStart := LowerCase(SearchStart); // not AnsiLowerCase, because CompareInText uses LoCase
|
|
SearchEnd := LowerCase(SearchEnd); // not AnsiLowerCase, because CompareInText uses LoCase
|
|
CmpProc := CompareInTextInternal;
|
|
end
|
|
else
|
|
CmpProc := CompareInStrInternal;
|
|
|
|
repeat
|
|
Inc(X, SearchDir);
|
|
|
|
// -1 direction
|
|
if X < 0 then
|
|
begin
|
|
Dec(Y);
|
|
if (Y < 0) or not {$IFDEF SUPPORTS_UNICODE}GetUnicodeTextLine{$ELSE}GetAnsiTextLine{$ENDIF SUPPORTS_UNICODE}(Y, Text) then
|
|
Break;
|
|
StringMap := BracketHighlighting.CreateStringMap(Text);
|
|
X := Length(Text) - 1;
|
|
if X < 0 then
|
|
Continue;
|
|
if CaretY - Y > 800 then
|
|
Exit;
|
|
end
|
|
else // +1 direction
|
|
if X >= Length(Text) then
|
|
begin
|
|
Inc(Y);
|
|
if not {$IFDEF SUPPORTS_UNICODE}GetUnicodeTextLine{$ELSE}GetAnsiTextLine{$ENDIF SUPPORTS_UNICODE}(Y, Text) then
|
|
Break;
|
|
StringMap := BracketHighlighting.CreateStringMap(Text);
|
|
X := 0;
|
|
if X >= Length(Text) then
|
|
Continue;
|
|
if Y - CaretY > 800 then
|
|
Exit;
|
|
end;
|
|
|
|
if not StringMap[X] then
|
|
begin
|
|
if IsBracketCompare then // it is faster to compare one char
|
|
begin
|
|
if Text[X + 1] = SearchEnd[1] then
|
|
begin
|
|
Dec(SearchOpen);
|
|
if SearchOpen = 0 then
|
|
begin
|
|
BracketHighlighting.FStop.TopLeft := Point(X + 1, Y);
|
|
BracketHighlighting.FStop.BottomRight := Point(X + 1, Y);
|
|
Break;
|
|
end;
|
|
end
|
|
else
|
|
if Text[X + 1] = SearchStart[1] then
|
|
Inc(SearchOpen);
|
|
end
|
|
else
|
|
begin
|
|
// word pairs
|
|
if CmpProc(Text, X, SearchEnd, LenSearchEnd) then // case sensitive
|
|
begin
|
|
if ((X = 0) or CharInSet(Text[X + 1 - 1], Separators)) and
|
|
((X + 1 + LenSearchEnd < LenText) or CharInSet(Text[X + 1 + LenSearchEnd], Separators)) then
|
|
begin
|
|
Dec(SearchOpen);
|
|
if SearchOpen = 0 then
|
|
begin
|
|
// found
|
|
BracketHighlighting.FStop.TopLeft := Point(X + 1, Y);
|
|
BracketHighlighting.FStop.BottomRight := Point(X + 1 + Length(SearchEnd) - 1, Y);
|
|
Break;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
if CmpProc(Text, X, SearchStart, LenSearchStart) then // case sensitive
|
|
begin
|
|
if ((X = 0) or CharInSet(Text[X + 1 - 1], Separators)) and
|
|
((X + 1 + LenSearchStart < LenText) or CharInSet(Text[X + 1 + LenSearchStart], Separators)) then
|
|
Inc(SearchOpen);
|
|
end;
|
|
end;
|
|
end;
|
|
until False;
|
|
|
|
{ sort Start and Stop "char" }
|
|
if BracketHighlighting.FStart.Top > BracketHighlighting.FStop.Top then
|
|
begin
|
|
R := BracketHighlighting.FStart;
|
|
BracketHighlighting.FStart := BracketHighlighting.FStop;
|
|
BracketHighlighting.FStop := R;
|
|
end
|
|
else
|
|
if (BracketHighlighting.FStart.Top = BracketHighlighting.FStop.Top) and
|
|
(BracketHighlighting.FStart.Left > BracketHighlighting.FStop.Left) then
|
|
begin
|
|
R := BracketHighlighting.FStart;
|
|
BracketHighlighting.FStart := BracketHighlighting.FStop;
|
|
BracketHighlighting.FStop := R;
|
|
end;
|
|
|
|
{ The caret must be between the start and stop "char" }
|
|
if BracketHighlighting.FStart.Top = CaretY then
|
|
begin
|
|
if BracketHighlighting.FStart.Left > CaretX + 1 then
|
|
BracketHighlighting.FStop.Left := -1; // invalidate
|
|
end;
|
|
if BracketHighlighting.FStop.Top = CaretY then
|
|
begin
|
|
if BracketHighlighting.FStop.Right < CaretX then
|
|
BracketHighlighting.FStop.Left := -1; // invalidate
|
|
end;
|
|
if (BracketHighlighting.FStop.Top < CaretY) or (BracketHighlighting.FStart.Top > CaretY) then
|
|
BracketHighlighting.FStop.Left := -1; // invalidate
|
|
|
|
|
|
{ Do only highlight if start and stop are found }
|
|
if BracketHighlighting.FStop.Left = -1 then
|
|
BracketHighlighting.FStart.Left := -1 // invalidate
|
|
else
|
|
begin
|
|
PaintLine(BracketHighlighting.FStart.Top);
|
|
PaintLine(BracketHighlighting.FStop.Top);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if not BetweenSearch and BracketHighlighting.ShowBetweenHighlighting and
|
|
(BracketHighlighting.FStop.Left = -1) and
|
|
(Y >= 0) and (X >= 0) and {$IFDEF SUPPORTS_UNICODE}GetUnicodeTextLine{$ELSE}GetAnsiTextLine{$ENDIF SUPPORTS_UNICODE}(Y, Text) then
|
|
begin
|
|
// find ending bracket
|
|
StringMap := BracketHighlighting.CreateStringMap(Text);
|
|
SearchOpen := 1;
|
|
repeat
|
|
if X >= Length(Text) then
|
|
begin
|
|
Inc(Y);
|
|
if not {$IFDEF SUPPORTS_UNICODE}GetUnicodeTextLine{$ELSE}GetAnsiTextLine{$ENDIF SUPPORTS_UNICODE}(Y, Text) then
|
|
Break;
|
|
StringMap := BracketHighlighting.CreateStringMap(Text);
|
|
X := 0;
|
|
if X >= Length(Text) then
|
|
Continue;
|
|
if Y - CaretY > 800 then
|
|
Exit;
|
|
end;
|
|
|
|
if not StringMap[X] then
|
|
begin
|
|
case Text[X + 1] of
|
|
'(', '{', '[':
|
|
Inc(SearchOpen);
|
|
')', '}', ']':
|
|
begin
|
|
Dec(SearchOpen);
|
|
if SearchOpen = 0 then
|
|
begin
|
|
HighlightBrackets(X, Y, True);
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
Inc(X);
|
|
until False;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.GetBracketHighlightingWords(var Direction: Integer;
|
|
const Start: string; var Stop: string; var CaseSensitive: Boolean);
|
|
var
|
|
I, Ps: Integer;
|
|
S: string;
|
|
CmpProc: function(const S1, S2: string): Integer;
|
|
begin
|
|
CaseSensitive := BracketHighlighting.CaseSensitiveWordPairs;
|
|
if CaseSensitive then
|
|
CmpProc := AnsiCompareStr
|
|
else
|
|
CmpProc := AnsiCompareText;
|
|
|
|
for I := 0 to BracketHighlighting.WordPairs.Count - 1 do
|
|
begin
|
|
S := BracketHighlighting.WordPairs[I];
|
|
Ps := Pos('=', S);
|
|
if Ps > 0 then
|
|
begin
|
|
if CmpProc(Copy(S, 1, Ps - 1), Start) = 0 then
|
|
begin
|
|
Stop := Copy(S, Ps + 1, MaxInt);
|
|
Direction := +1;
|
|
Break;
|
|
end;
|
|
if CmpProc(Copy(S, Ps + 1, MaxInt), Start) = 0 then
|
|
begin
|
|
Stop := Copy(S, 1, Ps - 1);
|
|
Direction := -1;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ find the font resource for LA }
|
|
|
|
function TJvCustomEditorBase.FontCacheFind(LA: TLineAttr): TFont;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
// find the font instance
|
|
for I := 0 to FFontCache.Count - 1 do
|
|
begin
|
|
Result := TFont(FFontCache.Items[I]);
|
|
if (Result.Style = LA.Style) and (Result.Color = LA.FC) then
|
|
Exit;
|
|
end;
|
|
// create a new font instance
|
|
Result := TFont.Create;
|
|
Result.Assign(FEditorClient.Canvas.Font); // copy default font
|
|
Result.Style := LA.Style;
|
|
Result.Color := LA.FC;
|
|
FFontCache.Add(Result); { store in FontCache }
|
|
end;
|
|
|
|
{ clear the font resource cache }
|
|
|
|
procedure TJvCustomEditorBase.FontCacheClear;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FFontCache.Count - 1 do
|
|
TFont(FFontCache.Items[I]).Free;
|
|
FFontCache.Clear;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.DrawRightMargin;
|
|
var
|
|
F: Integer;
|
|
begin
|
|
if FRightMarginVisible and (FRightMargin > FLeftCol) and
|
|
(FRightMargin < FLastVisibleCol + 3) then
|
|
with FEditorClient.Canvas do
|
|
begin
|
|
{ we paint RightMargin Line [translated] }
|
|
Pen.Color := FRightMarginColor;
|
|
F := CalcCellRect(FRightMargin - FLeftCol, 0).Left;
|
|
MoveTo(F, FEditorClient.Top);
|
|
LineTo(F, FEditorClient.Top + FEditorClient.Height);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.CheckBeyondEOL(var CX: Integer; CY: Integer);
|
|
begin
|
|
if not CursorBeyondEOL then
|
|
begin
|
|
if (CY >= 0) and (CY < LineCount) then
|
|
begin
|
|
if CX >= GetLineLength(CY) then
|
|
CX := GetLineLength(CY);
|
|
end
|
|
else
|
|
CX := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.Mouse2Cell(X, Y: Integer; var CX, CY: Integer);
|
|
begin
|
|
CX := Round((X - FEditorClient.Left) / CellRect.Width);
|
|
CY := (Y - FEditorClient.Top) div CellRect.Height;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.Mouse2Caret(X, Y: Integer; var CX, CY: Integer);
|
|
begin
|
|
Mouse2Cell(X, Y, CX, CY);
|
|
if CX < 0 then
|
|
CX := 0;
|
|
if CY < 0 then
|
|
CY := 0;
|
|
CX := CX + FLeftCol;
|
|
CY := CY + FTopRow;
|
|
if CX > FLastVisibleCol then
|
|
CX := FLastVisibleCol;
|
|
if (CY > LineCount - 1) and not CursorBeyondEOF then
|
|
CY := LineCount - 1;
|
|
CheckBeyondEOL(CX, CY);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.MousePosToCell(X, Y: Integer; var CX, CY: Integer);
|
|
begin
|
|
CX := (X - FEditorClient.Left) div CellRect.Width; // difference to Mouse2Caret
|
|
CY := (Y - FEditorClient.Top) div CellRect.Height;
|
|
if CX < 0 then
|
|
CX := 0;
|
|
if CY < 0 then
|
|
CY := 0;
|
|
CX := CX + FLeftCol;
|
|
CY := CY + FTopRow;
|
|
if CX > FLastVisibleCol then
|
|
CX := FLastVisibleCol;
|
|
if CY > LineCount - 1 then // difference to Mouse2Caret
|
|
CY := LineCount - 1;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.CaretChanged(LastCaretX, LastCaretY: Integer);
|
|
begin
|
|
if Assigned(FOnCaretChanged) then
|
|
FOnCaretChanged(Self, LastCaretX, LastCaretY);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.CaretCoord(X, Y: Integer; var CX, CY: Integer);
|
|
begin
|
|
CX := X - FLeftCol;
|
|
CY := Y - FTopRow;
|
|
if CX < 0 then
|
|
CX := 0;
|
|
if CY < 0 then
|
|
CY := 0;
|
|
CX := CellRect.Width * CX;
|
|
CY := CellRect.Height * CY;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.PosFromMouse(X, Y: Integer): Integer;
|
|
var
|
|
X1, Y1: Integer;
|
|
begin
|
|
Mouse2Caret(X, Y, X1, Y1);
|
|
if (X1 < 0) or (Y1 < 0) then
|
|
Result := -1
|
|
else
|
|
Result := PosFromCaret(X1, Y1);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetCaretInternal(X, Y: Integer);
|
|
var
|
|
R: TRect;
|
|
LastCaretX, LastCaretY: Integer;
|
|
begin
|
|
if (X = FCaretX) and (Y = FCaretY) then
|
|
Exit;
|
|
// To scroll the image
|
|
if not FCursorBeyondEOF then
|
|
Y := Min(Y, LineCount - 1);
|
|
Y := Max(Y, 0);
|
|
X := Min(X, Max_X);
|
|
X := Max(X, 0);
|
|
CheckBeyondEOL(X, Y);
|
|
|
|
if Y < FTopRow then
|
|
SetLeftTop(FLeftCol, Y)
|
|
else
|
|
if Y > Max(FLastVisibleRow, 0) then
|
|
SetLeftTop(FLeftCol, Y - FVisibleRowCount + 1);
|
|
if X < 0 then
|
|
X := 0;
|
|
if X < FLeftCol then
|
|
SetLeftTop(X, FTopRow)
|
|
else
|
|
if X > FLastVisibleCol then
|
|
SetLeftTop(X - FVisibleColCount + 1, FTopRow);
|
|
|
|
if Focused then {mac: do not move Caret when not focused!}
|
|
begin
|
|
R := CalcCellRect(X - FLeftCol, Y - FTopRow);
|
|
SetCaretPos(R.Left - 1, R.Top + 1);
|
|
end;
|
|
|
|
if (FCaretX <> X) or (FCaretY <> Y) then
|
|
begin
|
|
LastCaretX := FCaretX;
|
|
LastCaretY := FCaretY;
|
|
FCaretX := X;
|
|
FCaretY := Y;
|
|
if (CurrentLineHighlight <> clNone) and (CurrentLineHighlight <> clDefault) then
|
|
begin
|
|
PaintLine(LastCaretY);
|
|
PaintLine(FCaretY);
|
|
end;
|
|
StatusChanged;
|
|
CaretChanged(LastCaretX, LastCaretY);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.NotUndoable;
|
|
begin
|
|
FUndoBuffer.Clear;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.NotRedoable;
|
|
begin
|
|
FUndoBuffer.ClearRedo;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.LineDeleted(Line: Integer);
|
|
begin
|
|
if Assigned(FOnLineDeleted) then
|
|
FOnLineDeleted(Self, Line);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.LineInserted(Line: Integer);
|
|
begin
|
|
if Assigned(FOnLineInserted) then
|
|
FOnLineInserted(Self, Line);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.ChangeBookmark(Bookmark: TBookmarkNum;
|
|
Valid: Boolean);
|
|
|
|
procedure SetXY(X, Y: Integer);
|
|
var
|
|
X1, Y1: Integer;
|
|
begin
|
|
X1 := FLeftCol;
|
|
Y1 := FTopRow;
|
|
if (Y < FTopRow) or (Y > FLastVisibleRow) then
|
|
Y1 := Y - (FVisibleRowCount div 2);
|
|
if (X < FLeftCol) or (X > FVisibleColCount) then
|
|
X1 := X - (FVisibleColCount div 2);
|
|
SetLeftTop(X1, Y1);
|
|
SetCaret(X, Y);
|
|
end;
|
|
|
|
begin
|
|
if Valid then
|
|
if Bookmarks[Bookmark].Valid and (Bookmarks[Bookmark].Y = FCaretY) then
|
|
Bookmarks[Bookmark].Valid := False
|
|
else
|
|
begin
|
|
Bookmarks[Bookmark].X := FCaretX;
|
|
Bookmarks[Bookmark].Y := FCaretY;
|
|
Bookmarks[Bookmark].Valid := True;
|
|
end
|
|
else
|
|
if Bookmarks[Bookmark].Valid then
|
|
SetXY(Bookmarks[Bookmark].X, Bookmarks[Bookmark].Y);
|
|
BookmarkChanged(Bookmark);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.BeginRecord;
|
|
begin
|
|
FMacro := '';
|
|
FRecording := True;
|
|
StatusChanged;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.EndRecord(var AMacro: TMacro);
|
|
begin
|
|
FRecording := False;
|
|
AMacro := FMacro;
|
|
StatusChanged;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.PlayMacro(const AMacro: TMacro);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
BeginCompound;
|
|
try
|
|
I := 1;
|
|
while I < Length(AMacro) do
|
|
begin
|
|
{$IFDEF UNICODE}
|
|
Command(Word(AMacro[I]) + Word(AMacro[I + 1]) shl 16);
|
|
{$ELSE}
|
|
Command(Byte(AMacro[I]) + Byte(AMacro[I + 1]) shl 8);
|
|
{$ENDIF UNICODE}
|
|
Inc(I, 2);
|
|
end;
|
|
finally
|
|
EndCompound;
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetLeftTop(ALeftCol, ATopRow: Integer);
|
|
begin
|
|
if ALeftCol < 0 then
|
|
ALeftCol := 0;
|
|
if FLeftCol <> ALeftCol then
|
|
begin
|
|
FScrollBarHorz.Position := ALeftCol;
|
|
Scroll(False, ALeftCol);
|
|
end;
|
|
if ATopRow < 0 then
|
|
ATopRow := 0;
|
|
if FTopRow <> ATopRow then
|
|
begin
|
|
FScrollBarVert.Position := ATopRow;
|
|
Scroll(True, ATopRow);
|
|
end;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.CanUndo: Boolean;
|
|
begin
|
|
Result := FUndoBuffer.CanUndo;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.CanRedo: Boolean;
|
|
begin
|
|
Result := FUndoBuffer.CanRedo;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.CanCopy: Boolean;
|
|
begin
|
|
Result := FSelection.IsSelected and not IsEmptySelection;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.CanPaste: Boolean;
|
|
var
|
|
H: THandle;
|
|
begin
|
|
Result := False;
|
|
if (FCaretY >= LineCount) and (LineCount > 0) then
|
|
Exit;
|
|
|
|
try
|
|
H := Clipboard.GetAsHandle(CF_TEXT);
|
|
if H <> 0 then
|
|
Result := (GlobalSize(H) > 0);
|
|
except
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.CanCut: Boolean;
|
|
begin
|
|
Result := CanCopy and not ReadOnly;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.CanSelectAll: Boolean;
|
|
var
|
|
MaxCol, MaxLine: Integer;
|
|
begin
|
|
MaxLine := LineCount - 1;
|
|
if MaxLine > 0 then
|
|
MaxCol := LineLength[MaxLine]
|
|
else
|
|
MaxCol := 0;
|
|
Result := (FSelection.SelBegX > 0) or (FSelection.SelBegY > 0) or
|
|
(FSelection.SelEndX < MaxCol) or (FSelection.SelEndY < MaxLine);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SelectAll;
|
|
begin
|
|
SelectRange(0, 0, Max_X, MaxInt);
|
|
end;
|
|
|
|
function TJvCustomEditorBase.HasSelection: Boolean;
|
|
begin
|
|
Result := FSelection.IsSelected and not IsEmptySelection;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.ClipboardCut;
|
|
begin
|
|
ClipboardCopy;
|
|
DeleteSelected;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.ClearSelection;
|
|
begin
|
|
SetUnSelected;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.Redo;
|
|
begin
|
|
FUndoBuffer.Redo;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.Undo;
|
|
begin
|
|
FUndoBuffer.Undo;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SelectRange(BegX, BegY, EndX, EndY: Integer);
|
|
begin
|
|
{ --- UNDO --- }
|
|
TJvSelectUndo.Create(Self, FCaretX, FCaretY);
|
|
{ --- /UNDO ---}
|
|
with FSelection do
|
|
begin
|
|
IsSelected := False;
|
|
Selecting := False;
|
|
|
|
if BegX < 0 then
|
|
BegX := 0;
|
|
if BegY < 0 then
|
|
BegY := 0;
|
|
if EndX > Max_X then
|
|
EndX := Max_X;
|
|
if (EndY < BegY) or (BegY >= LineCount) then
|
|
Exit;
|
|
if EndY >= LineCount then
|
|
EndY := LineCount - 1;
|
|
if EndY < 0 then
|
|
Exit;
|
|
|
|
SelBegX := BegX;
|
|
SelBegY := BegY;
|
|
SelEndX := EndX;
|
|
SelEndY := EndY;
|
|
SelLineOrgBegX := BegX;
|
|
SelLineOrgEndX := BegY;
|
|
IsSelected := not IsEmptySelection;
|
|
Selecting := False;
|
|
|
|
SetSelUpdateRegion(SelBegY, SelEndY);
|
|
end;
|
|
if FCompound = 0 then
|
|
PaintSelection;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.CalcCellRect(X, Y: Integer): TRect;
|
|
begin
|
|
Result := Bounds(
|
|
FEditorClient.Left + X * CellRect.Width + 1,
|
|
FEditorClient.Top + Y * CellRect.Height,
|
|
CellRect.Width,
|
|
CellRect.Height)
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetCaret(X, Y: Integer);
|
|
begin
|
|
if (X = FCaretX) and (Y = FCaretY) then
|
|
Exit;
|
|
{--- UNDO ---}
|
|
TJvCaretUndo.Create(Self, FCaretX, FCaretY);
|
|
{--- /UNDO ---}
|
|
SetCaretInternal(X, Y);
|
|
if UpdateLock = 0 then
|
|
StatusChanged;
|
|
end;
|
|
|
|
{ It returns on the index of pos - to the number of symbol - its coordinate.
|
|
Returns on index Pos - to number of the character - his(its) coordinates.
|
|
[translated]
|
|
}
|
|
procedure TJvCustomEditorBase.CaretFromPos(Pos: Integer; var X, Y: Integer);
|
|
var
|
|
I, Len, P: Integer;
|
|
begin
|
|
X := -1;
|
|
Y := -1;
|
|
if Pos < 0 then
|
|
Exit;
|
|
P := 0;
|
|
|
|
for I := 0 to LineCount - 1 do
|
|
begin
|
|
Len := LineLength[I];
|
|
Inc(P, Len);
|
|
if P >= Pos then
|
|
begin
|
|
Dec(P, Len);
|
|
Y := I;
|
|
X := Pos - P;
|
|
Break;
|
|
end;
|
|
Inc(P, sLineBreakLen);
|
|
end;
|
|
end;
|
|
|
|
function TJvCustomEditorBase.PosFromCaret(X, Y: Integer): Integer;
|
|
var
|
|
I: Integer;
|
|
Len: Integer;
|
|
begin
|
|
if Cardinal(Y) >= Cardinal(LineCount) then
|
|
Result := -1
|
|
else
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to Y - 1 do
|
|
Inc(Result, LineLength[I] + sLineBreakLen);
|
|
Len := LineLength[Y];
|
|
if X < Len then
|
|
Inc(Result, X)
|
|
else
|
|
Inc(Result, Len);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.PaintCaret(bShow: Boolean);
|
|
var
|
|
R: TRect;
|
|
begin
|
|
if FHideCaret then
|
|
Exit;
|
|
if not bShow then
|
|
Windows.HideCaret(Handle)
|
|
else
|
|
if Focused then
|
|
begin
|
|
R := CalcCellRect(FCaretX - FLeftCol, FCaretY - FTopRow);
|
|
if (R.Left >= 0) and (R.Left >= FGutterWidth) then
|
|
SetCaretPos(R.Left - 1, R.Top + 1)
|
|
else
|
|
SetCaretPos(-MAXSHORT, -MAXSHORT); // hide caret without Windows.HideCaret
|
|
ShowCaret(Handle);
|
|
end
|
|
end;
|
|
|
|
function TJvCustomEditorBase.GetTextLen: Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to LineCount - 1 do
|
|
Inc(Result, LineLength[I] + sLineBreakLen);
|
|
Dec(Result, sLineBreakLen);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.BeginUpdate;
|
|
begin
|
|
LockUpdate;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.EndUpdate;
|
|
begin
|
|
Assert(FUpdateLock > 0); { Error }
|
|
UnlockUpdate;
|
|
if UpdateLock = 0 then
|
|
begin
|
|
FAllRepaint := True;
|
|
UpdateEditorSize;
|
|
StatusChanged;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.MakeRowVisible(ARow: Integer);
|
|
begin
|
|
if (ARow < FTopRow) or (ARow > FLastVisibleRow) then
|
|
begin
|
|
ARow := ARow - Trunc(VisibleRowCount / 2); {mac: bugfix - FCaretY}
|
|
if ARow < 0 then
|
|
ARow := 0;
|
|
SetLeftTop(FLeftCol, ARow);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.Command(ACommand: TEditCommand);
|
|
var
|
|
X, Y: Integer;
|
|
CaretUndo: Boolean;
|
|
F: Integer;
|
|
iBeg: Integer;
|
|
BlockFormat: TJvSelBlockFormat;
|
|
type
|
|
TPr = procedure of object;
|
|
|
|
procedure DoAndCorrectXY(Pr: TPr);
|
|
begin
|
|
Pr;
|
|
X := CaretX;
|
|
Y := CaretY;
|
|
CaretUndo := False;
|
|
end;
|
|
|
|
function Com(const Args: array of TEditCommand): Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to High(Args) do
|
|
if Args[I] = ACommand then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
Result := False;
|
|
end;
|
|
|
|
procedure SetSel1(X, Y: Integer);
|
|
begin
|
|
SetSel(X, Y);
|
|
CaretUndo := False;
|
|
end;
|
|
|
|
procedure IncCaretX(var X, Y: Integer; XOffset: Integer);
|
|
begin
|
|
Inc(X, XOffset);
|
|
if not CursorBeyondEOL then
|
|
begin
|
|
if X < 0 then
|
|
begin
|
|
if (Y > 0) and (Y <= LineCount) then
|
|
begin
|
|
Dec(Y);
|
|
X := LineLength[Y];
|
|
end;
|
|
end
|
|
else if (Y >= 0) and (Y < LineCount) and (X > LineLength[Y]) then
|
|
begin
|
|
if not CursorBeyondEOF and (Y < LineCount - 1) then
|
|
begin
|
|
Inc(Y);
|
|
X := 0;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
X := CaretX;
|
|
Y := CaretY;
|
|
CaretUndo := True;
|
|
// LockUpdate;
|
|
{ macro recording }
|
|
if Recording and not Com([ecRecordMacro, ecBeginCompound]) and (Compound = 0) then
|
|
begin
|
|
{$IFDEF UNICODE}
|
|
FMacro := FMacro + Char(LoWord(ACommand)) + Char(HiWord(ACommand));
|
|
{$ELSE}
|
|
FMacro := FMacro + AnsiChar(Lo(ACommand)) + AnsiChar(Hi(ACommand));
|
|
{$ENDIF UNICODE}
|
|
end;
|
|
|
|
PaintCaret(False);
|
|
try
|
|
case ACommand of
|
|
{ caret movements }
|
|
ecLeft, ecRight, ecSelLeft, ecSelRight:
|
|
begin
|
|
if Com([ecSelLeft, ecSelRight]) and IsNewSelection then
|
|
SetSel1(X, Y);
|
|
if Com([ecLeft, ecSelLeft]) then
|
|
IncCaretX(X, Y, -1)
|
|
else
|
|
IncCaretX(X, Y, +1);
|
|
if Com([ecSelLeft, ecSelRight]) then
|
|
SetSel1(X, Y)
|
|
else
|
|
PersistentBlocksSetUnSelected;
|
|
end;
|
|
ecUp, ecDown, ecSelUp, ecSelDown:
|
|
if Com([ecUp, ecSelUp]) or (Y < Rows - 1) or CursorBeyondEOF then
|
|
begin
|
|
if Com([ecSelUp, ecSelDown]) and IsNewSelection then
|
|
SetSel1(X, Y);
|
|
if Com([ecUp, ecSelUp]) then
|
|
Dec(Y)
|
|
else
|
|
Inc(Y);
|
|
if Com([ecSelUp, ecSelDown]) then
|
|
SetSel1(X, Y)
|
|
else
|
|
PersistentBlocksSetUnSelected;
|
|
end;
|
|
ecSelColumnLeft, ecSelColumnRight, ecSelColumnUp, ecSelColumnDown:
|
|
begin
|
|
FSelection.SelBlockFormat := bfColumn;
|
|
case ACommand of
|
|
ecSelColumnLeft: Command(ecSelLeft);
|
|
ecSelColumnRight: Command(ecSelRight);
|
|
ecSelColumnUp: Command(ecSelUp);
|
|
ecSelColumnDown: Command(ecSelDown);
|
|
end;
|
|
Exit;
|
|
end;
|
|
ecScrollLineUp, ecScrollLineDown:
|
|
begin
|
|
if not ((ACommand = ecScrollLineDown) and
|
|
(Y >= LineCount - 1) and (Y = TopRow)) then
|
|
begin
|
|
if ACommand = ecScrollLineUp then
|
|
F := -1
|
|
else
|
|
F := 1;
|
|
FScrollBarVert.Position := FScrollBarVert.Position + F;
|
|
Scroll(True, FScrollBarVert.Position);
|
|
end;
|
|
if Y < FTopRow then
|
|
Y := FTopRow
|
|
else
|
|
if Y > FLastVisibleRow then
|
|
Y := FLastVisibleRow;
|
|
end;
|
|
ecBeginLine, ecSelBeginLine, ecBeginDoc, ecSelBeginDoc,
|
|
ecEndLine, ecSelEndLine, ecEndDoc, ecSelEndDoc:
|
|
begin
|
|
if Com([ecSelBeginLine, ecSelBeginDoc, ecSelEndLine, ecSelEndDoc]) and
|
|
IsNewSelection then
|
|
SetSel1(CaretX, Y);
|
|
if Com([ecBeginLine, ecSelBeginLine]) then
|
|
X := 0
|
|
else
|
|
if Com([ecBeginDoc, ecSelBeginDoc]) then
|
|
begin
|
|
X := 0;
|
|
Y := 0;
|
|
SetLeftTop(0, 0);
|
|
end
|
|
else
|
|
if Com([ecEndLine, ecSelEndLine]) then
|
|
if Cardinal(Y) < Cardinal(LineCount) then
|
|
X := LineLength[Y]
|
|
else
|
|
X := 0
|
|
else
|
|
if Com([ecEndDoc, ecSelEndDoc]) then
|
|
begin
|
|
Y := LineCount - 1;
|
|
if Y >= 0 then
|
|
begin
|
|
X := LineLength[Y];
|
|
SetLeftTop(X - FVisibleColCount, Y - FVisibleRowCount div 2);
|
|
end;
|
|
end;
|
|
if Com([ecSelBeginLine, ecSelBeginDoc, ecSelEndLine, ecSelEndDoc]) then
|
|
SetSel1(X, Y)
|
|
else
|
|
PersistentBlocksSetUnSelected;
|
|
end;
|
|
ecPrevPage:
|
|
begin
|
|
FScrollBarVert.Position := FScrollBarVert.Position - FScrollBarVert.LargeChange;
|
|
Scroll(True, FScrollBarVert.Position);
|
|
Y := Y - FVisibleRowCount;
|
|
PersistentBlocksSetUnSelected;
|
|
end;
|
|
ecNextPage:
|
|
begin
|
|
FScrollBarVert.Position := FScrollBarVert.Position + FScrollBarVert.LargeChange;
|
|
Scroll(True, FScrollBarVert.Position);
|
|
Y := Y + FVisibleRowCount;
|
|
PersistentBlocksSetUnSelected;
|
|
end;
|
|
ecSelPrevPage:
|
|
begin
|
|
BeginUpdate;
|
|
SetSel1(X, Y);
|
|
FScrollBarVert.Position := FScrollBarVert.Position - FScrollBarVert.LargeChange;
|
|
Scroll(True, FScrollBarVert.Position);
|
|
Y := Y - FVisibleRowCount;
|
|
SetSel1(X, Y);
|
|
EndUpdate;
|
|
end;
|
|
ecSelNextPage:
|
|
begin
|
|
BeginUpdate;
|
|
SetSel1(X, Y);
|
|
FScrollBarVert.Position := FScrollBarVert.Position + FScrollBarVert.LargeChange;
|
|
Scroll(True, FScrollBarVert.Position);
|
|
Y := Y + FVisibleRowCount;
|
|
if Y <= LineCount - 1 then
|
|
SetSel1(X, Y)
|
|
else
|
|
SetSel1(X, LineCount - 1);
|
|
EndUpdate;
|
|
end;
|
|
ecWindowTop:
|
|
Y := FTopRow;
|
|
ecWindowBottom:
|
|
Y := FTopRow + FVisibleRowCount - 1;
|
|
{ editing }
|
|
ecCharFirst..ecCharLast:
|
|
if not FReadOnly then
|
|
begin
|
|
InsertChar(Word(ACommand - ecCharFirst));
|
|
Exit;
|
|
end;
|
|
ecInsertPara:
|
|
if not FReadOnly then
|
|
begin
|
|
InsertChar(13);
|
|
Exit;
|
|
end
|
|
else
|
|
if Y < LineCount - 1 then
|
|
begin
|
|
Inc(Y);
|
|
if LineLength[Y] > 0 then
|
|
begin
|
|
iBeg := FindNotBlankCharPosInLine(Y) - 1;
|
|
if iBeg < X then
|
|
X := iBeg;
|
|
end;
|
|
end;
|
|
ecIndent:
|
|
if not FReadOnly and FSelection.IsSelected then
|
|
begin
|
|
if FSelection.SelBlockFormat = bfColumn then
|
|
IndentColumns(FSelection.SelBegX, FSelection.SelBegY, FSelection.SelEndY)
|
|
else
|
|
IndentSelLines(False);
|
|
Exit;
|
|
end;
|
|
ecUnindent:
|
|
if not FReadOnly and FSelection.IsSelected then
|
|
begin
|
|
if FSelection.SelBlockFormat = bfColumn then
|
|
UnIndentColumns(FSelection.SelBegX, FSelection.SelBegY, FSelection.SelEndY)
|
|
else
|
|
IndentSelLines(True);
|
|
Exit;
|
|
end;
|
|
ecChangeInsertMode:
|
|
begin
|
|
FInsertMode := not FInsertMode;
|
|
StatusChanged;
|
|
end;
|
|
ecInclusiveBlock..ecNonInclusiveBlock:
|
|
begin
|
|
if FSelection.SelBlockFormat = TJvSelBlockFormat(ACommand - ecInclusiveBlock) then
|
|
Exit;
|
|
|
|
if FSelection.IsSelected then
|
|
begin
|
|
// convert line block to others and visi versa
|
|
if ACommand <> ecLineBlock then
|
|
begin
|
|
if FSelection.SelBlockFormat = bfLine then
|
|
AdjustSelLineMode(True); // Restore :=
|
|
end
|
|
else
|
|
AdjustSelLineMode(False); // Restore :=
|
|
end;
|
|
|
|
FSelection.SelBlockFormat := TJvSelBlockFormat(ACommand - ecInclusiveBlock);
|
|
PaintSelection;
|
|
StatusChanged;
|
|
end;
|
|
ecClipboardCut:
|
|
if not FReadOnly then
|
|
DoAndCorrectXY(ClipboardCut);
|
|
ecClipboardCopy:
|
|
ClipboardCopy;
|
|
ecClipboardPaste:
|
|
if not FReadOnly then
|
|
DoAndCorrectXY(ClipboardPaste);
|
|
ecDeleteSelected:
|
|
if not FReadOnly and FSelection.IsSelected then
|
|
DoAndCorrectXY(DeleteSelected);
|
|
ecDeleteWord:
|
|
if not FReadOnly then
|
|
begin
|
|
Command(ecBeginCompound);
|
|
Command(ecBeginUpdate);
|
|
try
|
|
BlockFormat := FSelection.SelBlockFormat;
|
|
FSelection.SelBlockFormat := bfNonInclusive; // no bfLine, bfColumn, bfInclusive
|
|
Command(ecSelNextWord);
|
|
FSelection.SelBlockFormat := BlockFormat;
|
|
|
|
Command(ecDeleteSelected);
|
|
finally
|
|
Command(ecEndUpdate);
|
|
Command(ecEndCompound);
|
|
end;
|
|
Exit;
|
|
end;
|
|
ecSelAll:
|
|
begin
|
|
SelectAll;
|
|
Exit;
|
|
end;
|
|
ecUndo:
|
|
if not FReadOnly then
|
|
begin
|
|
FUndoBuffer.Undo;
|
|
PaintCaret(True);
|
|
Exit;
|
|
end;
|
|
ecRedo:
|
|
if not FReadOnly then
|
|
begin
|
|
FUndoBuffer.Redo;
|
|
PaintCaret(True);
|
|
Exit;
|
|
end;
|
|
ecBeginCompound:
|
|
BeginCompound;
|
|
ecEndCompound:
|
|
EndCompound;
|
|
ecSetBookmark0..ecSetBookmark9:
|
|
ChangeBookmark(ACommand - ecSetBookmark0, True);
|
|
ecGotoBookmark0..ecGotoBookmark9:
|
|
begin
|
|
ChangeBookmark(ACommand - ecGotoBookmark0, False);
|
|
X := CaretX;
|
|
Y := CaretY;
|
|
end;
|
|
ecCompletionIdentifiers:
|
|
if not FReadOnly then
|
|
begin
|
|
Completion.DoCompletion(cmIdentifiers);
|
|
PaintCaret(True);
|
|
Exit;
|
|
end;
|
|
ecCompletionTemplates:
|
|
if not FReadOnly then
|
|
begin
|
|
Completion.DoCompletion(cmTemplates);
|
|
PaintCaret(True);
|
|
Exit;
|
|
end;
|
|
ecBeginUpdate:
|
|
BeginUpdate;
|
|
ecEndUpdate:
|
|
EndUpdate;
|
|
ecRecordMacro:
|
|
if FRecording then
|
|
EndRecord(FDefMacro)
|
|
else
|
|
BeginRecord;
|
|
ecPlayMacro:
|
|
begin
|
|
PlayMacro(FDefMacro);
|
|
Exit;
|
|
end;
|
|
else
|
|
if DoCommand(ACommand, X, Y, CaretUndo) then
|
|
Exit;
|
|
end;
|
|
|
|
if CaretUndo then
|
|
SetCaret(X, Y)
|
|
else
|
|
SetCaretInternal(X, Y);
|
|
finally
|
|
// UnlockUpdate;
|
|
PaintCaret(True);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.PostCommand(ACommand: TEditCommand);
|
|
begin
|
|
PostMessage(Handle, WM_EDITCOMMAND, ACommand, 0);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.IndentLines(UnIndent: Boolean; BegY, EndY: Integer);
|
|
begin
|
|
if UnIndent then
|
|
UnIndentColumns(0, BegY, EndY)
|
|
else
|
|
IndentColumns(0, BegY, EndY);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.IndentSelLines(UnIndent: Boolean);
|
|
var
|
|
BegNotBlank, EndNotBlank: Integer;
|
|
BegY, EndY: Integer;
|
|
begin
|
|
with FSelection do
|
|
begin
|
|
if (not IsSelected) or (SelBlockFormat = bfColumn) then
|
|
Exit;
|
|
|
|
BegY := SelBegY;
|
|
EndY := SelEndY;
|
|
if SelEndX = 0 then
|
|
Dec(EndY);
|
|
if BegY > EndY then
|
|
Exit;
|
|
|
|
BegNotBlank := FindNotBlankCharPosInLine(BegY) - 1;
|
|
EndNotBlank := FindNotBlankCharPosInLine(EndY) - 1;
|
|
|
|
IndentLines(UnIndent, BegY, EndY);
|
|
|
|
// to relative values
|
|
BegNotBlank := (FindNotBlankCharPosInLine(BegY) - 1) - BegNotBlank;
|
|
EndNotBlank := (FindNotBlankCharPosInLine(EndY) - 1) - EndNotBlank;
|
|
|
|
if UnIndent then
|
|
begin
|
|
// adjust selection
|
|
Inc(SelBegX, BegNotBlank);
|
|
if SelBegX < 0 then
|
|
SelBegX := 0;
|
|
|
|
if SelEndX > 0 then
|
|
Inc(SelEndX, EndNotBlank);
|
|
if SelEndX < 0 then
|
|
SelEndX := 0;
|
|
end
|
|
else
|
|
begin
|
|
// adjust selection
|
|
Inc(SelBegX, BegNotBlank);
|
|
if SelBegX > Max_X then
|
|
SelBegX := Max_X;
|
|
|
|
if SelEndX > 0 then
|
|
Inc(SelEndX, EndNotBlank);
|
|
if SelEndX > Max_X then
|
|
SelEndX := Max_X;
|
|
end;
|
|
|
|
// adjust caret
|
|
if (CaretY = SelEndY) and (SelEndX > 0) then
|
|
SetCaretInternal(CaretX + EndNotBlank, CaretY)
|
|
else
|
|
if CaretY = SelBegY then
|
|
SetCaretInternal(CaretX + BegNotBlank, CaretY);
|
|
|
|
SetSelUpdateRegion(BegY, EndY);
|
|
PaintSelection;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.BeginCompound;
|
|
begin
|
|
Inc(FCompound);
|
|
{--- UNDO ---}
|
|
TJvBeginCompoundUndo.Create(Self);
|
|
{--- /UNDO ---}
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.EndCompound;
|
|
begin
|
|
{--- UNDO ---}
|
|
TJvEndCompoundUndo.Create(Self);
|
|
{--- /UNDO ---}
|
|
Dec(FCompound);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.PostBeginCompound;
|
|
begin
|
|
PostMessage(Handle, WM_COMPOUND, 0, 0);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.PostEndCompound;
|
|
begin
|
|
PostMessage(Handle, WM_COMPOUND, 1, 0);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetBracketHighlighting(Value: TJvBracketHighlighting);
|
|
begin
|
|
if Value <> BracketHighlighting then
|
|
BracketHighlighting.Assign(Value);
|
|
end;
|
|
|
|
procedure TJvCustomEditorBase.SetCurrentLineHighlight(const Value: TColor);
|
|
begin
|
|
if Value <> FCurrentLineHighlight then
|
|
begin
|
|
FCurrentLineHighlight := Value;
|
|
if not (csLoading in ComponentState) and (CaretY >= 0) and (CaretY < LineCount) then
|
|
PaintLine(CaretY);
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvErrorHighlightingItem } ===========================================
|
|
|
|
constructor TJvErrorHighlightingItem.Create(AOwner: TJvErrorHighlighting;
|
|
ACol, ALine, ALen: Integer; const AErrorText: string);
|
|
begin
|
|
inherited Create;
|
|
FOwner := AOwner;
|
|
FCol := ACol;
|
|
FLine := ALine;
|
|
FLen := ALen;
|
|
FErrorText := AErrorText;
|
|
end;
|
|
|
|
destructor TJvErrorHighlightingItem.Destroy;
|
|
begin
|
|
if not (csDestroying in FOwner.Editor.ComponentState) then
|
|
FOwner.FItems.Extract(Self);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvErrorHighlightingItem.SetCol(const Value: Integer);
|
|
begin
|
|
if Value <> FCol then
|
|
begin
|
|
FCol := Value;
|
|
FOwner.RepaintLine(Line);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvErrorHighlightingItem.SetLine(const Value: Integer);
|
|
begin
|
|
if Value <> FLine then
|
|
begin
|
|
FLine := -1;
|
|
FOwner.RepaintLine(Line);
|
|
FLine := Value;
|
|
FOwner.RepaintLine(Line);
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvErrorHighlighting } ===============================================
|
|
|
|
constructor TJvErrorHighlighting.Create(AEditor: TJvCustomEditorBase);
|
|
begin
|
|
inherited Create;
|
|
FEditor := AEditor;
|
|
FItems := TObjectList.Create;
|
|
end;
|
|
|
|
destructor TJvErrorHighlighting.Destroy;
|
|
begin
|
|
FItems.Free;
|
|
FEditor := nil;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJvErrorHighlighting.GetCount: Integer;
|
|
begin
|
|
Result := FItems.Count;
|
|
end;
|
|
|
|
function TJvErrorHighlighting.Add(ACol, ALine, ALen: Integer; const AErrorText: string): Integer;
|
|
begin
|
|
Result := FItems.Add(TJvErrorHighlightingItem.Create(Self, ACol, ALine, ALen, AErrorText));
|
|
RepaintLine(ALine);
|
|
end;
|
|
|
|
function TJvErrorHighlighting.GetItem(Index: Integer): TJvErrorHighlightingItem;
|
|
begin
|
|
Result := TJvErrorHighlightingItem(FItems[Index]);
|
|
end;
|
|
|
|
procedure TJvErrorHighlighting.Remove(Item: TJvErrorHighlightingItem);
|
|
var
|
|
Line: Integer;
|
|
begin
|
|
if Assigned(Item) then
|
|
begin
|
|
Line := Item.Line;
|
|
FItems.Remove(Item);
|
|
RepaintLine(Line);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvErrorHighlighting.Delete(Index: Integer);
|
|
var
|
|
Line: Integer;
|
|
begin
|
|
if (Index >= 0) and (Index < Count) then
|
|
begin
|
|
Line := Items[Index].Line;
|
|
FItems.Delete(Index);
|
|
RepaintLine(Line);
|
|
end
|
|
else
|
|
FItems.Delete(Index);
|
|
end;
|
|
|
|
procedure TJvErrorHighlighting.Clear;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
FNeedsRepaint := FItems.Count > 0;
|
|
FItems.Clear;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvErrorHighlighting.RepaintLine(Line: Integer);
|
|
begin
|
|
if FPaintLock > 0 then
|
|
FNeedsRepaint := True
|
|
else
|
|
begin
|
|
if Assigned(FEditor) then
|
|
FEditor.PaintLine(Line);
|
|
FNeedsRepaint := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvErrorHighlighting.EndUpdate;
|
|
begin
|
|
Assert(FPaintLock > 0, 'Unpaired call to EndUpdate');
|
|
Dec(FPaintLock);
|
|
if FNeedsRepaint then
|
|
begin
|
|
if Assigned(FEditor) then
|
|
FEditor.Paint;
|
|
FNeedsRepaint := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvErrorHighlighting.BeginUpdate;
|
|
begin
|
|
Inc(FPaintLock);
|
|
end;
|
|
|
|
procedure TJvErrorHighlighting.DeleteLine(Line: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Dec(Line);
|
|
BeginUpdate;
|
|
try
|
|
for I := Count - 1 downto 0 do
|
|
if Items[I].Line = Line then
|
|
Delete(I)
|
|
else
|
|
if Items[I].Line > Line then
|
|
Items[I].Line := Items[I].Line - 1;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvErrorHighlighting.InsertLine(Line: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Dec(Line);
|
|
BeginUpdate;
|
|
try
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].Line >= Line then
|
|
Items[I].Line := Items[I].Line + 1;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TJvErrorHighlighting.GetLineErrorMap(Y: Integer): TDynBoolArray;
|
|
var
|
|
I, X: Integer;
|
|
Item: TJvErrorHighlightingItem;
|
|
MaxX: Integer;
|
|
begin
|
|
MaxX := 0;
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
Item := Items[I];
|
|
if Item.Line = Y then
|
|
if Item.Col + Item.Len > MaxX then
|
|
MaxX := Item.Col + Item.Len;
|
|
end;
|
|
SetLength(Result, MaxX);
|
|
|
|
if MaxX > 0 then
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
Item := Items[I];
|
|
if Item.Line = Y then
|
|
for X := Item.Col to Item.Col + Item.Len - 1 do
|
|
Result[X] := True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJvErrorHighlighting.ErrorAt(X, Y: Integer): TJvErrorHighlightingItem;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
Result := Items[I];
|
|
if (Result.Line = Y) and (X >= Result.Col) and (X < Result.Col + Result.Len) then
|
|
Exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TJvErrorHighlighting.PaintError(Canvas: TCanvas; Col, Line: Integer;
|
|
const R: TRect; Len: Integer; const MyDi: TDynIntArray);
|
|
var
|
|
I, Width, X: Integer;
|
|
Errors: TDynBoolArray;
|
|
begin
|
|
Errors := GetLineErrorMap(Line);
|
|
X := R.Left;
|
|
for I := Col to Col + Len - 1 do
|
|
begin
|
|
Width := MyDi[I];
|
|
if (I <= High(Errors)) and Errors[I] then
|
|
begin
|
|
with Canvas do
|
|
begin
|
|
Pen.Color := clRed;
|
|
MoveTo(X, R.Bottom - 1);
|
|
LineTo(X + Width div 4, R.Bottom - 4);
|
|
LineTo(X + Width div 4 * 2, R.Bottom - 1);
|
|
LineTo(X + Width div 4 * 3, R.Bottom - 4);
|
|
LineTo(X + Width, R.Bottom - 1);
|
|
end;
|
|
end;
|
|
Inc(X, Width);
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvEditorCompletionList } ============================================
|
|
|
|
constructor TJvEditorCompletionList.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
Left := -1000;
|
|
Visible := False;
|
|
TabStop := False;
|
|
ParentFont := False;
|
|
Parent := Owner as TJvCustomEditorBase;
|
|
Ctl3D := False;
|
|
FTimer := TTimer.Create(nil);
|
|
FTimer.Enabled := False;
|
|
FTimer.Interval := 200;
|
|
FTimer.OnTimer := OnTimer;
|
|
Style := lbOwnerDrawFixed;
|
|
ItemHeight := 13;
|
|
|
|
// HintWindow := THintWindow.Create(Self);
|
|
end;
|
|
|
|
destructor TJvEditorCompletionList.Destroy;
|
|
begin
|
|
FTimer.Free;
|
|
// HintWindow.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvEditorCompletionList.CreateParams(var Params: TCreateParams);
|
|
begin
|
|
inherited CreateParams(Params);
|
|
with Params do
|
|
begin
|
|
Style := Style {or WS_POPUP} or WS_BORDER;
|
|
ExStyle := ExStyle or WS_EX_TOOLWINDOW;
|
|
WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvEditorCompletionList.CreateWnd;
|
|
begin
|
|
inherited CreateWnd;
|
|
if not (csDesigning in ComponentState) then
|
|
Windows.SetParent(Handle, 0);
|
|
// CallWindowProc(DefWndProc, Handle, WM_SETFOCUS, 0, 0); {??}
|
|
end;
|
|
|
|
procedure TJvEditorCompletionList.DestroyWnd;
|
|
begin
|
|
inherited DestroyWnd;
|
|
// HintWindow.ReleaseHandle;
|
|
end;
|
|
|
|
procedure TJvEditorCompletionList.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
F: Integer;
|
|
begin
|
|
YY := Y;
|
|
F := ItemAtPos(Point(X, Y), True);
|
|
if KeyPressed(VK_LBUTTON) then
|
|
begin
|
|
F := ItemAtPos(Point(X, Y), True);
|
|
if F > -1 then
|
|
ItemIndex := F;
|
|
FTimer.Enabled := (Y < 0) or (Y > ClientHeight);
|
|
if (Y < -ItemHeight) or (Y > ClientHeight + ItemHeight) then
|
|
FTimer.Interval := 50
|
|
else
|
|
FTimer.Interval := 200;
|
|
end;
|
|
if (F > -1) and not FTimer.Enabled then
|
|
begin
|
|
//Application.CancelHint;
|
|
// Hint := Items[F];
|
|
// HintWindow.ActivateHint(Bounds(ClientOrigin.X + X, ClientOrigin.Y + Y, 300, ItemHeight), Items[F]);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvEditorCompletionList.MouseDown(Button: TMouseButton; Shift:
|
|
TShiftState; X, Y: Integer);
|
|
var
|
|
F: Integer;
|
|
begin
|
|
MouseCapture := True;
|
|
F := ItemAtPos(Point(X, Y), True);
|
|
if F > -1 then
|
|
ItemIndex := F;
|
|
end;
|
|
|
|
procedure TJvEditorCompletionList.MouseUp(Button: TMouseButton; Shift:
|
|
TShiftState; X, Y: Integer);
|
|
begin
|
|
MouseCapture := False;
|
|
(Owner as TJvCustomEditorBase).Completion.CloseUp(
|
|
(Button = mbLeft) and PtInRect(ClientRect, Point(X, Y)));
|
|
end;
|
|
|
|
procedure TJvEditorCompletionList.OnTimer(Sender: TObject);
|
|
begin
|
|
if YY < 0 then
|
|
Perform(WM_VSCROLL, SB_LINEUP, 0)
|
|
else
|
|
if YY > ClientHeight then
|
|
Perform(WM_VSCROLL, SB_LINEDOWN, 0);
|
|
end;
|
|
|
|
procedure TJvEditorCompletionList.WMCancelMode(var Msg: TMessage);
|
|
begin
|
|
(Owner as TJvCustomEditorBase).Completion.CloseUp(False);
|
|
end;
|
|
|
|
procedure TJvEditorCompletionList.CMHintShow(var Msg: TMessage);
|
|
begin
|
|
Msg.Result := 1;
|
|
end;
|
|
|
|
procedure TJvEditorCompletionList.DrawItem(Index: Integer; Rect: TRect;
|
|
State: TOwnerDrawState);
|
|
var
|
|
Offset, W: Integer;
|
|
S: string;
|
|
begin
|
|
// this is a ANSI component
|
|
if Assigned(OnDrawItem) then
|
|
OnDrawItem(Self, Index, Rect, State)
|
|
else
|
|
begin
|
|
Canvas.FillRect(Rect);
|
|
Offset := 3;
|
|
with (Owner as TJvCustomEditorBase).Completion do
|
|
case Mode of
|
|
cmIdentifiers:
|
|
TJvUnicodeCanvas(Canvas).TextOut(Rect.Left + Offset, Rect.Top, SubStrBySeparator(Items[Index], 1,
|
|
{$IFDEF SUPPORTS_UNICODE}GetUnicodeSeparator{$ELSE}GetAnsiSeparator{$ENDIF SUPPORTS_UNICODE}));
|
|
cmTemplates:
|
|
begin
|
|
TJvUnicodeCanvas(Canvas).TextOut(Rect.Left + Offset, Rect.Top, SubStrBySeparator(Items[Index], 1,
|
|
{$IFDEF SUPPORTS_UNICODE}GetUnicodeSeparator{$ELSE}GetAnsiSeparator{$ENDIF SUPPORTS_UNICODE}));
|
|
Canvas.Font.Style := [fsBold];
|
|
S := SubStrBySeparator(Items[Index], 0, {$IFDEF SUPPORTS_UNICODE}GetUnicodeSeparator{$ELSE}GetAnsiSeparator{$ENDIF SUPPORTS_UNICODE});
|
|
W := Canvas.TextWidth(S);
|
|
TJvUnicodeCanvas(Canvas).TextOut(Rect.Right - 2 * Offset - W, Rect.Top, S);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvEditorCompletion } ================================================
|
|
|
|
constructor TJvCompletionBase.Create(AJvEditor: TJvCustomEditorBase);
|
|
begin
|
|
inherited Create;
|
|
FJvEditor := AJvEditor;
|
|
FPopupList := TJvEditorCompletionList.Create(FJvEditor);
|
|
FItemHeight := FPopupList.ItemHeight;
|
|
FDropDownCount := 6;
|
|
FDropDownWidth := 300;
|
|
FTimer := TTimer.Create(nil);
|
|
FTimer.Enabled := False;
|
|
FTimer.Interval := 800;
|
|
FTimer.OnTimer := OnTimer;
|
|
FDefMode := cmIdentifiers;
|
|
end;
|
|
|
|
destructor TJvCompletionBase.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
// (ahuser) is this necessary ?
|
|
FPopupList.Free;
|
|
FTimer.Free;
|
|
end;
|
|
|
|
procedure TJvCompletionBase.DoKeyPress(Key: Char);
|
|
begin
|
|
if FVisible then
|
|
if HasChar(Key, JvEditorCompletionChars) then
|
|
SelectItem
|
|
else
|
|
CloseUp(True)
|
|
else
|
|
if FEnabled then
|
|
FTimer.Enabled := True;
|
|
end;
|
|
|
|
function TJvCompletionBase.DoKeyDown(Key: Word; Shift: TShiftState): Boolean;
|
|
begin
|
|
Result := True;
|
|
case Key of
|
|
VK_ESCAPE:
|
|
CloseUp(False);
|
|
VK_RETURN:
|
|
CloseUp(True);
|
|
VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_HOME, VK_END:
|
|
FPopupList.Perform(WM_KEYDOWN, Key, 0);
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCompletionBase.DoCompletion(const AMode: TCompletionList);
|
|
var
|
|
Eq: Boolean;
|
|
Cancel: Boolean;
|
|
begin
|
|
if FJvEditor.ReadOnly then
|
|
Exit;
|
|
if FPopupList.Visible then
|
|
CloseUp(False);
|
|
FMode := AMode;
|
|
case FMode of
|
|
cmIdentifiers:
|
|
DropDown(AMode, True);
|
|
cmTemplates:
|
|
begin
|
|
Cancel := False;
|
|
// JvEditor.DoCompletionIdentifier(Cancel);
|
|
FJvEditor.DoCompletionTemplate(Cancel);
|
|
if Cancel or (GetTemplateCount = 0) then
|
|
Exit;
|
|
MakeItems;
|
|
FindSelItem(Eq);
|
|
if Eq then
|
|
ReplaceWordItemIndex(2)
|
|
else
|
|
DropDown(AMode, True);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCompletionBase.DropDown(const AMode: TCompletionList; const ShowAlways:
|
|
Boolean);
|
|
var
|
|
ItemCount: Integer;
|
|
P: TPoint;
|
|
Y: Integer;
|
|
PopupWidth, PopupHeight: Integer;
|
|
SysBorderWidth, SysBorderHeight: Integer;
|
|
R: TRect;
|
|
Cancel: Boolean;
|
|
Eq: Boolean;
|
|
begin
|
|
CloseUp(False);
|
|
FMode := AMode;
|
|
with FJvEditor do
|
|
begin
|
|
Cancel := False;
|
|
case FMode of
|
|
cmIdentifiers:
|
|
DoCompletionIdentifier(Cancel);
|
|
cmTemplates:
|
|
DoCompletionTemplate(Cancel)
|
|
end;
|
|
MakeItems;
|
|
FindSelItem(Eq);
|
|
// Cancel := not Visible and (ItemIndex = -1);
|
|
if Cancel or (Items.Count = 0) or (((ItemIndex = -1) or Eq) and not ShowAlways) then
|
|
Exit;
|
|
FPopupList.ItemHeight := FItemHeight;
|
|
FVisible := True;
|
|
SetItemIndex(FItemIndex);
|
|
if FListBoxStyle in [lbStandard] then
|
|
FPopupList.Style := lbOwnerDrawFixed
|
|
else
|
|
FPopupList.Style := FListBoxStyle;
|
|
FPopupList.OnMeasureItem := FJvEditor.OnCompletionMeasureItem;
|
|
FPopupList.OnDrawItem := FJvEditor.OnCompletionDrawItem;
|
|
|
|
ItemCount := Items.Count;
|
|
SysBorderWidth := GetSystemMetrics(SM_CXBORDER);
|
|
SysBorderHeight := GetSystemMetrics(SM_CYBORDER);
|
|
R := CalcCellRect(CaretX - LeftCol, CaretY - TopRow + 1);
|
|
P := R.TopLeft;
|
|
P.X := ClientOrigin.X + P.X;
|
|
P.Y := ClientOrigin.Y + P.Y;
|
|
Dec(P.X, 2 * SysBorderWidth);
|
|
Dec(P.Y, SysBorderHeight);
|
|
if ItemCount > FDropDownCount then
|
|
ItemCount := FDropDownCount;
|
|
PopupHeight := ItemHeight * ItemCount + 2;
|
|
Y := P.Y;
|
|
if (Y + PopupHeight) > Screen.Height then
|
|
begin
|
|
Y := P.Y - PopupHeight - CellRect.Height + 1;
|
|
if Y < 0 then
|
|
Y := P.Y;
|
|
end;
|
|
PopupWidth := FDropDownWidth;
|
|
if PopupWidth = 0 then
|
|
PopupWidth := Width + 2 * SysBorderWidth;
|
|
end;
|
|
FPopupList.Left := P.X;
|
|
FPopupList.Top := Y;
|
|
FPopupList.Width := PopupWidth;
|
|
FPopupList.Height := PopupHeight;
|
|
SetWindowPos(FPopupList.Handle, HWND_TOP, P.X, Y, 0, 0,
|
|
SWP_NOSIZE or SWP_NOACTIVATE or SWP_SHOWWINDOW);
|
|
FPopupList.Visible := True;
|
|
end;
|
|
|
|
procedure TJvCompletionBase.SelectItem;
|
|
var
|
|
Cancel: Boolean;
|
|
Param: Boolean;
|
|
begin
|
|
FindSelItem(Param);
|
|
Cancel := not Visible and (ItemIndex = -1);
|
|
case FMode of
|
|
cmIdentifiers:
|
|
FJvEditor.DoCompletionIdentifier(Cancel);
|
|
cmTemplates:
|
|
FJvEditor.DoCompletionTemplate(Cancel);
|
|
end;
|
|
if Cancel or (GetItemCount = 0) then
|
|
CloseUp(False);
|
|
end;
|
|
|
|
procedure TJvCompletionBase.CloseUp(const Apply: Boolean);
|
|
begin
|
|
if not Visible then
|
|
Exit;
|
|
|
|
FItemIndex := ItemIndex;
|
|
FPopupList.Visible := False;
|
|
// (FPopupList as TJvEditorCompletionList).HintWindow.ReleaseHandle;
|
|
FVisible := False;
|
|
FTimer.Enabled := False;
|
|
if Apply and (ItemIndex > -1) then
|
|
case FMode of
|
|
cmIdentifiers:
|
|
ReplaceWordItemIndex(0);
|
|
cmTemplates:
|
|
ReplaceWordItemIndex(2);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCompletionBase.OnTimer(Sender: TObject);
|
|
begin
|
|
DropDown(FDefMode, False);
|
|
end;
|
|
|
|
function TJvCompletionBase.GetItemIndex: Integer;
|
|
begin
|
|
Result := FItemIndex;
|
|
if FVisible then
|
|
Result := FPopupList.ItemIndex;
|
|
end;
|
|
|
|
procedure TJvCompletionBase.SetItemIndex(AValue: Integer);
|
|
begin
|
|
FItemIndex := AValue;
|
|
if FVisible then
|
|
FPopupList.ItemIndex := FItemIndex;
|
|
end;
|
|
|
|
function TJvCompletionBase.GetInterval: Cardinal;
|
|
begin
|
|
Result := FTimer.Interval;
|
|
end;
|
|
|
|
procedure TJvCompletionBase.SetInterval(AValue: Cardinal);
|
|
begin
|
|
FTimer.Interval := AValue;
|
|
end;
|
|
|
|
function TJvCompletionBase.GetItemCount: Integer;
|
|
begin
|
|
case FMode of
|
|
cmIdentifiers:
|
|
Result := GetIdentifierCount;
|
|
cmTemplates:
|
|
Result := GetTemplateCount;
|
|
else
|
|
Result := 0;
|
|
end;
|
|
end;
|
|
|
|
function TJvCompletionBase.GetItems: TStrings;
|
|
begin
|
|
Result := FPopupList.Items;
|
|
end;
|
|
|
|
//=== { TJvSymbolColor } =====================================================
|
|
|
|
constructor TJvSymbolColor.Create;
|
|
begin
|
|
inherited Create;
|
|
FStyle := [];
|
|
FForeColor := clWindowText;
|
|
FBackColor := clWindow;
|
|
end;
|
|
|
|
procedure TJvSymbolColor.SetColor(const ForeColor, BackColor: TColor; const Style: TFontStyles);
|
|
begin
|
|
FForeColor := ForeColor;
|
|
FBackColor := BackColor;
|
|
FStyle := Style;
|
|
end;
|
|
|
|
procedure TJvSymbolColor.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TJvSymbolColor then
|
|
begin
|
|
FForeColor := TJvSymbolColor(Source).FForeColor;
|
|
FBackColor := TJvSymbolColor(Source).FBackColor;
|
|
FStyle := TJvSymbolColor(Source).FStyle;
|
|
end
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
//=== { TJvColors } ==========================================================
|
|
|
|
constructor TJvColors.Create;
|
|
begin
|
|
inherited Create;
|
|
FComment := TJvSymbolColor.Create;
|
|
FNumber := TJvSymbolColor.Create;
|
|
FString := TJvSymbolColor.Create;
|
|
FSymbol := TJvSymbolColor.Create;
|
|
FReserved := TJvSymbolColor.Create;
|
|
FStatement := TJvSymbolColor.Create;
|
|
FIdentifier := TJvSymbolColor.Create;
|
|
FPreproc := TJvSymbolColor.Create;
|
|
FFunctionCall := TJvSymbolColor.Create;
|
|
FDeclaration := TJvSymbolColor.Create;
|
|
FPlainText := TJvSymbolColor.Create;
|
|
Preproc.SetColor(clGreen, clWindow, []);
|
|
Comment.SetColor(clOlive, clWindow, [fsItalic]);
|
|
Number.SetColor(clNavy, clWindow, []);
|
|
Strings.SetColor(clPurple, clWindow, []);
|
|
Symbol.SetColor(clBlue, clWindow, []);
|
|
Reserved.SetColor(clWindowText, clWindow, [fsBold]);
|
|
Statement.SetColor(clWindowText, clWindow, [fsBold]);
|
|
Identifier.SetColor(clWindowText, clWindow, []);
|
|
FunctionCall.SetColor(clWindowText, clWindow, []);
|
|
Declaration.SetColor(clWindowText, clWindow, []);
|
|
PlainText.SetColor(clWindowText, clWindow, []);
|
|
end;
|
|
|
|
destructor TJvColors.Destroy;
|
|
begin
|
|
FComment.Free;
|
|
FNumber.Free;
|
|
FString.Free;
|
|
FSymbol.Free;
|
|
FReserved.Free;
|
|
FStatement.Free;
|
|
FIdentifier.Free;
|
|
FPreproc.Free;
|
|
FFunctionCall.Free;
|
|
FDeclaration.Free;
|
|
FPlainText.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvColors.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TJvColors then
|
|
begin
|
|
Comment.Assign(TJvColors(Source).Comment);
|
|
Number.Assign(TJvColors(Source).Number);
|
|
Strings.Assign(TJvColors(Source).Strings);
|
|
Symbol.Assign(TJvColors(Source).Symbol);
|
|
Reserved.Assign(TJvColors(Source).Reserved);
|
|
Statement.Assign(TJvColors(Source).Statement);
|
|
Identifier.Assign(TJvColors(Source).Identifier);
|
|
Preproc.Assign(TJvColors(Source).Preproc);
|
|
FunctionCall.Assign(TJvColors(Source).FunctionCall);
|
|
Declaration.Assign(TJvColors(Source).Declaration);
|
|
PlainText.Assign(TJvColors(Source).PlainText);
|
|
end
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
initialization
|
|
RegisterUnitVersion(HInstance, UnitVersioning);
|
|
|
|
finalization
|
|
UnregisterUnitVersion(HInstance);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
end.
|