lazarus/components/synedit/syneditkeycmds.pp
2005-06-25 15:34:03 +00:00

924 lines
31 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/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: SynEditKeyCmds.pas, released 2000-04-07.
The Original Code is based on the mwKeyCmds.pas file from the
mwEdit component suite by Martin Waldenburg and other developers, the Initial
Author of this file is Brad Stowers.
All Rights Reserved.
Contributors to the SynEdit and mwEdit projects are listed in the
Contributors.txt file.
Alternatively, the contents of this file may be used under the terms of the
GNU General Public License Version 2 or later (the "GPL"), in which case
the provisions of the GPL are applicable instead of those above.
If you wish to allow use of your version of this file only under the terms
of the GPL and not to allow others to use your version of this file
under the MPL, indicate your decision by deleting the provisions above and
replace them with the notice and other provisions required by the GPL.
If you do not delete the provisions above, a recipient may use your version
of this file under either the MPL or the GPL.
$Id$
You may retrieve the latest version of this file at the SynEdit home page,
located at http://SynEdit.SourceForge.net
Known Issues:
-------------------------------------------------------------------------------}
unit SynEditKeyCmds;
{$I synedit.inc}
interface
uses
{$IFDEF SYN_LAZARUS}
LCLIntf, LCLType,
{$ELSE}
Windows,
{$ENDIF}
Classes, Menus, SysUtils;
const
//****************************************************************************
// NOTE! If you add an editor command, you must also update the
// EditorCommandStrs constant array in implementation section below, or the
// command will not show up in the IDE.
//****************************************************************************
// "Editor Commands". Key strokes are translated from a table into these
// I used constants instead of a set so that additional commands could be
// added in descendants (you can't extend a set)
// There are two ranges of editor commands: the ecViewXXX commands are always
// valid, while the ecEditXXX commands are ignored when the editor is in
// read-only mode
ecNone = 0; // Nothing. Useful for user event to handle command
ecViewCommandFirst = 0;
ecViewCommandLast = 500;
ecEditCommandFirst = 501;
ecEditCommandLast = 1000;
ecLeft = 1; // Move cursor left one char
ecRight = 2; // Move cursor right one char
ecUp = 3; // Move cursor up one line
ecDown = 4; // Move cursor down one line
ecWordLeft = 5; // Move cursor left one word
ecWordRight = 6; // Move cursor right one word
ecLineStart = 7; // Move cursor to beginning of line
ecLineEnd = 8; // Move cursor to end of line
ecPageUp = 9; // Move cursor up one page
ecPageDown = 10; // Move cursor down one page
ecPageLeft = 11; // Move cursor right one page
ecPageRight = 12; // Move cursor left one page
ecPageTop = 13; // Move cursor to top of page
ecPageBottom = 14; // Move cursor to bottom of page
ecEditorTop = 15; // Move cursor to absolute beginning
ecEditorBottom = 16; // Move cursor to absolute end
ecGotoXY = 17; // Move cursor to specific coordinates, Data = PPoint
//******************************************************************************
// Maybe the command processor should just take a boolean that signifies if
// selection is affected or not?
//******************************************************************************
ecSelection = 100; // Add this to ecXXX command to get equivalent
// command, but with selection enabled. This is not
// a command itself.
// Same as commands above, except they affect selection, too
ecSelLeft = ecLeft + ecSelection;
ecSelRight = ecRight + ecSelection;
ecSelUp = ecUp + ecSelection;
ecSelDown = ecDown + ecSelection;
ecSelWordLeft = ecWordLeft + ecSelection;
ecSelWordRight = ecWordRight + ecSelection;
ecSelLineStart = ecLineStart + ecSelection;
ecSelLineEnd = ecLineEnd + ecSelection;
ecSelPageUp = ecPageUp + ecSelection;
ecSelPageDown = ecPageDown + ecSelection;
ecSelPageLeft = ecPageLeft + ecSelection;
ecSelPageRight = ecPageRight + ecSelection;
ecSelPageTop = ecPageTop + ecSelection;
ecSelPageBottom = ecPageBottom + ecSelection;
ecSelEditorTop = ecEditorTop + ecSelection;
ecSelEditorBottom = ecEditorBottom + ecSelection;
ecSelGotoXY = ecGotoXY + ecSelection; // Data = PPoint
ecSelectAll = 199; // Select entire contents of editor, cursor to end
ecCopy = 201; // Copy selection to clipboard
ecScrollUp = 211; // Scroll up one line leaving cursor position unchanged.
ecScrollDown = 212; // Scroll down one line leaving cursor position unchanged.
ecScrollLeft = 213; // Scroll left one char leaving cursor position unchanged.
ecScrollRight = 214; // Scroll right one char leaving cursor position unchanged.
ecInsertMode = 221; // Set insert mode
ecOverwriteMode = 222; // Set overwrite mode
ecToggleMode = 223; // Toggle ins/ovr mode
ecNormalSelect = 231; // Normal selection mode
ecColumnSelect = 232; // Column selection mode
ecLineSelect = 233; // Line selection mode
ecMatchBracket = 250; // Go to matching bracket
ecGotoMarker0 = 301; // Goto marker
ecGotoMarker1 = 302; // Goto marker
ecGotoMarker2 = 303; // Goto marker
ecGotoMarker3 = 304; // Goto marker
ecGotoMarker4 = 305; // Goto marker
ecGotoMarker5 = 306; // Goto marker
ecGotoMarker6 = 307; // Goto marker
ecGotoMarker7 = 308; // Goto marker
ecGotoMarker8 = 309; // Goto marker
ecGotoMarker9 = 310; // Goto marker
ecSetMarker0 = 351; // Set marker, Data = PPoint - X, Y Pos
ecSetMarker1 = 352; // Set marker, Data = PPoint - X, Y Pos
ecSetMarker2 = 353; // Set marker, Data = PPoint - X, Y Pos
ecSetMarker3 = 354; // Set marker, Data = PPoint - X, Y Pos
ecSetMarker4 = 355; // Set marker, Data = PPoint - X, Y Pos
ecSetMarker5 = 356; // Set marker, Data = PPoint - X, Y Pos
ecSetMarker6 = 357; // Set marker, Data = PPoint - X, Y Pos
ecSetMarker7 = 358; // Set marker, Data = PPoint - X, Y Pos
ecSetMarker8 = 359; // Set marker, Data = PPoint - X, Y Pos
ecSetMarker9 = 360; // Set marker, Data = PPoint - X, Y Pos
ecDeleteLastChar = 501; // Delete last char (i.e. backspace key)
ecDeleteChar = 502; // Delete char at cursor (i.e. delete key)
ecDeleteWord = 503; // Delete from cursor to end of word
ecDeleteLastWord = 504; // Delete from cursor to start of word
ecDeleteBOL = 505; // Delete from cursor to beginning of line
ecDeleteEOL = 506; // Delete from cursor to end of line
ecDeleteLine = 507; // Delete current line
ecClearAll = 508; // Delete everything
ecLineBreak = 509; // Break line at current position, move caret to new line
ecInsertLine = 510; // Break line at current position, leave caret
ecChar = 511; // Insert a character at current position
ecImeStr = 550; // Insert character(s) from IME
ecUndo = 601; // Perform undo if available
ecRedo = 602; // Perform redo if available
ecCut = 603; // Cut selection to clipboard
ecPaste = 604; // Paste clipboard to current position
ecBlockIndent = 610; // Indent selection
ecBlockUnindent = 611; // Unindent selection
ecTab = 612; // Tab key
ecShiftTab = 613; // Shift+Tab key
ecUpperCase = 620; // apply to the current or previous word
ecLowerCase = 621;
ecToggleCase = 622;
ecTitleCase = 623;
ecUpperCaseBlock = 625; // apply to current selection, or current char if no selection
ecLowerCaseBlock = 626;
ecToggleCaseBlock = 627;
ecString = 630; //Insert a whole string
ecAutoCompletion = 650;
ecGotFocus = 700;
ecLostFocus = 701;
ecUserFirst = 1001; // Start of user-defined commands
type
ESynKeyError = class(Exception);
TSynEditorCommand = type word;
TSynEditKeyStroke = class(TCollectionItem)
private
FKey: word; // Virtual keycode, i.e. VK_xxx
FShift: TShiftState;
FKey2: word;
FShift2: TShiftState;
FCommand: TSynEditorCommand;
function GetShortCut: TShortCut;
function GetShortCut2: TShortCut;
procedure SetCommand(const Value: TSynEditorCommand);
procedure SetKey(const Value: word);
procedure SetKey2(const Value: word);
procedure SetShift(const Value: TShiftState);
procedure SetShift2(const Value: TShiftState);
procedure SetShortCut(const Value: TShortCut);
procedure SetShortCut2(const Value: TShortCut);
protected
{$IFDEF SYN_COMPILER_3_UP}
function GetDisplayName: string; override;
{$ENDIF}
public
procedure Assign(Source: TPersistent); override;
{begin} //ac 2000-07-05
procedure LoadFromStream(AStream: TStream);
procedure SaveToStream(AStream: TStream);
{end} //ac 2000-07-05
// No duplicate checking is done if assignment made via these properties!
property Key: word read FKey write SetKey;
property Key2: word read FKey2 write SetKey2;
property Shift: TShiftState read FShift write SetShift;
property Shift2: TShiftState read FShift2 write SetShift2;
published
property Command: TSynEditorCommand read FCommand write SetCommand;
property ShortCut: TShortCut read GetShortCut write SetShortCut
default 0; //mh 2000-11-07
property ShortCut2: TShortCut read GetShortCut2 write SetShortCut2
default 0; //mh 2000-11-07
end;
TSynEditKeyStrokes = class(TCollection)
private
FOwner: TPersistent;
function GetItem(Index: Integer): TSynEditKeyStroke;
procedure SetItem(Index: Integer; Value: TSynEditKeyStroke);
protected
{$IFDEF SYN_COMPILER_3_UP}
function GetOwner: TPersistent; override;
{$ENDIF}
public
constructor Create(AOwner: TPersistent);
function Add: TSynEditKeyStroke;
procedure Assign(Source: TPersistent); override;
function FindCommand(Cmd: TSynEditorCommand): integer;
function FindKeycode(Code: word; SS: TShiftState): integer;
function FindKeycode2(Code1: word; SS1: TShiftState;
Code2: word; SS2: TShiftState): integer;
function FindShortcut(SC: TShortcut): integer;
function FindShortcut2(SC, SC2: TShortcut): integer;
procedure LoadFromStream(AStream: TStream); //ac 2000-07-05
procedure ResetDefaults;
procedure SaveToStream(AStream: TStream); //ac 2000-07-05
public
property Items[Index: Integer]: TSynEditKeyStroke read GetItem
write SetItem; default;
end;
// These are mainly for the TSynEditorCommand property editor, but could be
// useful elsewhere.
function EditorCommandToDescrString(Cmd: TSynEditorCommand): string;
function EditorCommandToCodeString(Cmd: TSynEditorCommand): string;
procedure GetEditorCommandValues(Proc: TGetStrProc);
function IdentToEditorCommand(const Ident: string; var Cmd: longint): boolean;
function EditorCommandToIdent(Cmd: longint; var Ident: string): boolean;
implementation
// FOR LAZARUS
uses
SynEditStrConst;
//=============================================================================
// This code should move to the menus.pas
type
TMenuKeyCap = (
mkcBkSp, mkcTab, mkcEsc, mkcEnter, mkcSpace, mkcPgUp,
mkcPgDn, mkcEnd, mkcHome, mkcLeft, mkcUp, mkcRight, mkcDown,
mkcIns, mkcDel, mkcShift, mkcCtrl, mkcAlt);
// this code should be moved to whereever mkcXXX are defined
const
SmkcBkSp = 'BkSp';
SmkcTab = 'Tab';
SmkcEsc = 'Esc';
SmkcEnter = 'Enter';
SmkcSpace = 'Space';
SmkcPgUp = 'PgUp';
SmkcPgDn = 'PgDn';
SmkcEnd = 'End';
SmkcHome = 'Home';
SmkcLeft = 'Left';
SmkcUp = 'Up';
SmkcRight = 'Right';
SmkcDown = 'Down';
SmkcIns = 'Ins';
SmkcDel = 'Del';
SmkcShift = 'Shift+';
SmkcCtrl = 'Ctrl+';
SmkcAlt = 'Alt+';
// this code should be moved to menus.pas
MenuKeyCaps: array[TMenuKeyCap] of ansistring = (
SmkcBkSp, SmkcTab, SmkcEsc, SmkcEnter, SmkcSpace, SmkcPgUp,
SmkcPgDn, SmkcEnd, SmkcHome, SmkcLeft, SmkcUp, SmkcRight, SmkcDown,
SmkcIns, SmkcDel, SmkcShift, SmkcCtrl, SmkcAlt);
function GetSpecialName(ShortCut: TShortCut): string;
// FOR LAZARUS: ToDo
{
var
ScanCode: Integer;
KeyName: array[0..255] of Char;
}
begin
Result := '';
// FOR LAZARUS: ToDo
{
ScanCode := MapVirtualKey(WordRec(ShortCut).Lo, 0) shl 16;
if ScanCode <> 0 then
begin
GetKeyNameText(ScanCode, KeyName, SizeOf(KeyName));
GetSpecialName := KeyName;
end; }
end;
function ShortCutToText(ShortCut: TShortCut): string;
var
Name: string;
begin
case WordRec(ShortCut).Lo of
$08, $09:
Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcBkSp) + WordRec(ShortCut).Lo - $08)];
$0D: Name := MenuKeyCaps[mkcEnter];
$1B: Name := MenuKeyCaps[mkcEsc];
$20..$28:
Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcSpace) + WordRec(ShortCut).Lo - $20)];
$2D..$2E:
Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcIns) + WordRec(ShortCut).Lo - $2D)];
$30..$39: Name := Chr(WordRec(ShortCut).Lo - $30 + Ord('0'));
$41..$5A: Name := Chr(WordRec(ShortCut).Lo - $41 + Ord('A'));
$60..$69: Name := Chr(WordRec(ShortCut).Lo - $60 + Ord('0'));
$70..$87: Name := 'F' + IntToStr(WordRec(ShortCut).Lo - $6F);
else
Name := GetSpecialName(ShortCut);
end;
if Name <> '' then
begin
Result := '';
if ShortCut and scShift <> 0 then Result := Result + MenuKeyCaps[mkcShift];
if ShortCut and scCtrl <> 0 then Result := Result + MenuKeyCaps[mkcCtrl];
if ShortCut and scAlt <> 0 then Result := Result + MenuKeyCaps[mkcAlt];
Result := Result + Name;
end
else Result := '';
end;
//=============================================================================
{ Command mapping routines }
{$IFDEF SYN_COMPILER_2}
// This is defined in D3/C3 and up.
type
TIdentMapEntry = record
Value: TSynEditorCommand;
Name: string;
end;
{$ENDIF}
const
EditorCommandStrs: array[0..89] of TIdentMapEntry = (
(Value: ecNone; Name: 'ecNone'),
(Value: ecLeft; Name: 'ecLeft'),
(Value: ecRight; Name: 'ecRight'),
(Value: ecUp; Name: 'ecUp'),
(Value: ecDown; Name: 'ecDown'),
(Value: ecWordLeft; Name: 'ecWordLeft'),
(Value: ecWordRight; Name: 'ecWordRight'),
(Value: ecLineStart; Name: 'ecLineStart'),
(Value: ecLineEnd; Name: 'ecLineEnd'),
(Value: ecPageUp; Name: 'ecPageUp'),
(Value: ecPageDown; Name: 'ecPageDown'),
(Value: ecPageLeft; Name: 'ecPageLeft'),
(Value: ecPageRight; Name: 'ecPageRight'),
(Value: ecPageTop; Name: 'ecPageTop'),
(Value: ecPageBottom; Name: 'ecPageBottom'),
(Value: ecEditorTop; Name: 'ecEditorTop'),
(Value: ecEditorBottom; Name: 'ecEditorBottom'),
(Value: ecGotoXY; Name: 'ecGotoXY'),
(Value: ecSelLeft; Name: 'ecSelLeft'),
(Value: ecSelRight; Name: 'ecSelRight'),
(Value: ecSelUp; Name: 'ecSelUp'),
(Value: ecSelDown; Name: 'ecSelDown'),
(Value: ecSelWordLeft; Name: 'ecSelWordLeft'),
(Value: ecSelWordRight; Name: 'ecSelWordRight'),
(Value: ecSelLineStart; Name: 'ecSelLineStart'),
(Value: ecSelLineEnd; Name: 'ecSelLineEnd'),
(Value: ecSelPageUp; Name: 'ecSelPageUp'),
(Value: ecSelPageDown; Name: 'ecSelPageDown'),
(Value: ecSelPageLeft; Name: 'ecSelPageLeft'),
(Value: ecSelPageRight; Name: 'ecSelPageRight'),
(Value: ecSelPageTop; Name: 'ecSelPageTop'),
(Value: ecSelPageBottom; Name: 'ecSelPageBottom'),
(Value: ecSelEditorTop; Name: 'ecSelEditorTop'),
(Value: ecSelEditorBottom; Name: 'ecSelEditorBottom'),
(Value: ecSelGotoXY; Name: 'ecSelGotoXY'),
(Value: ecSelectAll; Name: 'ecSelectAll'),
(Value: ecDeleteLastChar; Name: 'ecDeleteLastChar'),
(Value: ecDeleteChar; Name: 'ecDeleteChar'),
(Value: ecDeleteWord; Name: 'ecDeleteWord'),
(Value: ecDeleteLastWord; Name: 'ecDeleteLastWord'),
(Value: ecDeleteBOL; Name: 'ecDeleteBOL'),
(Value: ecDeleteEOL; Name: 'ecDeleteEOL'),
(Value: ecDeleteLine; Name: 'ecDeleteLine'),
(Value: ecClearAll; Name: 'ecClearAll'),
(Value: ecLineBreak; Name: 'ecLineBreak'),
(Value: ecInsertLine; Name: 'ecInsertLine'),
(Value: ecChar; Name: 'ecChar'),
(Value: ecImeStr; Name: 'ecImeStr'),
(Value: ecUndo; Name: 'ecUndo'),
(Value: ecRedo; Name: 'ecRedo'),
(Value: ecCut; Name: 'ecCut'),
(Value: ecCopy; Name: 'ecCopy'),
(Value: ecPaste; Name: 'ecPaste'),
(Value: ecScrollUp; Name: 'ecScrollUp'),
(Value: ecScrollDown; Name: 'ecScrollDown'),
(Value: ecScrollLeft; Name: 'ecScrollLeft'),
(Value: ecScrollRight; Name: 'ecScrollRight'),
(Value: ecInsertMode; Name: 'ecInsertMode'),
(Value: ecOverwriteMode; Name: 'ecOverwriteMode'),
(Value: ecToggleMode; Name: 'ecToggleMode'),
(Value: ecBlockIndent; Name: 'ecBlockIndent'),
(Value: ecBlockUnindent; Name: 'ecBlockUnindent'),
(Value: ecTab; Name: 'ecTab'),
(Value: ecShiftTab; Name: 'ecShiftTab'),
(Value: ecMatchBracket; Name: 'ecMatchBracket'),
(Value: ecNormalSelect; Name: 'ecNormalSelect'),
(Value: ecColumnSelect; Name: 'ecColumnSelect'),
(Value: ecLineSelect; Name: 'ecLineSelect'),
(Value: ecAutoCompletion; Name: 'ecAutoCompletion'),
(Value: ecUserFirst; Name: 'ecUserFirst'),
(Value: ecGotoMarker0; Name: 'ecGotoMarker0'),
(Value: ecGotoMarker1; Name: 'ecGotoMarker1'),
(Value: ecGotoMarker2; Name: 'ecGotoMarker2'),
(Value: ecGotoMarker3; Name: 'ecGotoMarker3'),
(Value: ecGotoMarker4; Name: 'ecGotoMarker4'),
(Value: ecGotoMarker5; Name: 'ecGotoMarker5'),
(Value: ecGotoMarker6; Name: 'ecGotoMarker6'),
(Value: ecGotoMarker7; Name: 'ecGotoMarker7'),
(Value: ecGotoMarker8; Name: 'ecGotoMarker8'),
(Value: ecGotoMarker9; Name: 'ecGotoMarker9'),
(Value: ecSetMarker0; Name: 'ecSetMarker0'),
(Value: ecSetMarker1; Name: 'ecSetMarker1'),
(Value: ecSetMarker2; Name: 'ecSetMarker2'),
(Value: ecSetMarker3; Name: 'ecSetMarker3'),
(Value: ecSetMarker4; Name: 'ecSetMarker4'),
(Value: ecSetMarker5; Name: 'ecSetMarker5'),
(Value: ecSetMarker6; Name: 'ecSetMarker6'),
(Value: ecSetMarker7; Name: 'ecSetMarker7'),
(Value: ecSetMarker8; Name: 'ecSetMarker8'),
(Value: ecSetMarker9; Name: 'ecSetMarker9'));
procedure GetEditorCommandValues(Proc: TGetStrProc);
var
i: integer;
begin
for i := Low(EditorCommandStrs) to High(EditorCommandStrs) do
Proc(EditorCommandStrs[I].Name);
end;
function IdentToEditorCommand(const Ident: string; var Cmd: longint): boolean;
{$IFDEF SYN_COMPILER_2}
var
I: Integer;
{$ENDIF}
begin
{$IFDEF SYN_COMPILER_2}
Result := FALSE;
for I := Low(EditorCommandStrs) to High(EditorCommandStrs) do
if CompareText(EditorCommandStrs[I].Name, Ident) = 0 then
begin
Result := TRUE;
Cmd := EditorCommandStrs[I].Value;
break;
end;
{$ELSE}
Result := IdentToInt(Ident, Cmd, EditorCommandStrs);
{$ENDIF}
end;
function EditorCommandToIdent(Cmd: longint; var Ident: string): boolean;
{$IFDEF SYN_COMPILER_2}
var
I: Integer;
{$ENDIF}
begin
{$IFDEF SYN_COMPILER_2}
Result := FALSE;
for I := Low(EditorCommandStrs) to High(EditorCommandStrs) do
if EditorCommandStrs[I].Value = Cmd then
begin
Result := TRUE;
Ident := EditorCommandStrs[I].Name;
break;
end;
{$ELSE}
Result := IntToIdent(Cmd, Ident, EditorCommandStrs);
{$ENDIF}
end;
function EditorCommandToDescrString(Cmd: TSynEditorCommand): string;
begin
// Doesn't do anything yet.
Result := '';
end;
function EditorCommandToCodeString(Cmd: TSynEditorCommand): string;
begin
Result := '';
if not EditorCommandToIdent(Cmd, Result) then
Result := IntToStr(Cmd);
end;
{ TSynEditKeyStroke }
procedure TSynEditKeyStroke.Assign(Source: TPersistent);
begin
if Source is TSynEditKeyStroke then
begin
Command := TSynEditKeyStroke(Source).Command;
Key := TSynEditKeyStroke(Source).Key;
Key2 := TSynEditKeyStroke(Source).Key2;
Shift := TSynEditKeyStroke(Source).Shift;
Shift2 := TSynEditKeyStroke(Source).Shift2;
end else
inherited Assign(Source);
end;
{$IFDEF SYN_COMPILER_3_UP}
function TSynEditKeyStroke.GetDisplayName: string;
begin
Result := EditorCommandToCodeString(Command) + ' - ' + ShortCutToText(ShortCut);
if ShortCut <> 0 then
Result := Result + ' ' + ShortCutToText(ShortCut2);
if Result = '' then
Result := inherited GetDisplayName;
end;
{$ENDIF}
function TSynEditKeyStroke.GetShortCut: TShortCut;
begin
Result := Menus.ShortCut(Key, Shift);
end;
procedure TSynEditKeyStroke.SetCommand(const Value: TSynEditorCommand);
begin
if Value <> FCommand then
FCommand := Value;
end;
procedure TSynEditKeyStroke.SetKey(const Value: word);
begin
if Value <> FKey then
FKey := Value;
end;
procedure TSynEditKeyStroke.SetShift(const Value: TShiftState);
begin
if Value <> FShift then
FShift := Value;
end;
procedure TSynEditKeyStroke.SetShortCut(const Value: TShortCut);
var
NewKey: Word;
NewShift: TShiftState;
Dup: integer;
begin
// Duplicate values of no shortcut are OK.
if Value <> 0 then
begin
// Check for duplicate shortcut in the collection and disallow if there is.
Dup := TSynEditKeyStrokes(Collection).FindShortcut2(Value, Key2);
if (Dup <> -1) and (Dup <> Self.Index) then
raise ESynKeyError.Create(SYNS_EDuplicateShortCut);
end;
Menus.ShortCutToKey(Value, NewKey, NewShift);
if (NewKey <> Key) or (NewShift <> Shift) then
begin
Key := NewKey;
Shift := NewShift;
end;
end;
procedure TSynEditKeyStroke.SetKey2(const Value: word);
begin
if Value <> FKey2 then
FKey2 := Value;
end;
procedure TSynEditKeyStroke.SetShift2(const Value: TShiftState);
begin
if Value <> FShift2 then
FShift2 := Value;
end;
procedure TSynEditKeyStroke.SetShortCut2(const Value: TShortCut);
var
NewKey: Word;
NewShift: TShiftState;
Dup: integer;
begin
// Duplicate values of no shortcut are OK.
if Value <> 0 then
begin
// Check for duplicate shortcut in the collection and disallow if there is.
Dup := TSynEditKeyStrokes(Collection).FindShortcut2(Key, Value);
if (Dup <> -1) and (Dup <> Self.Index) then
raise ESynKeyError.Create(SYNS_EDuplicateShortCut);
end;
Menus.ShortCutToKey(Value, NewKey, NewShift);
if (NewKey <> Key2) or (NewShift <> Shift2) then
begin
Key2 := NewKey;
Shift2 := NewShift;
end;
end;
function TSynEditKeyStroke.GetShortCut2: TShortCut;
begin
Result := Menus.ShortCut(Key2, Shift2);
end;
{begin} //ac 2000-07-05
procedure TSynEditKeyStroke.LoadFromStream(AStream: TStream);
begin
with AStream do begin
Read(fKey, SizeOf(fKey));
Read(fShift, SizeOf(fShift));
Read(fKey2, SizeOf(fKey2));
Read(fShift2, SizeOf(fShift2));
Read(fCommand, SizeOf(fCommand));
end;
end;
procedure TSynEditKeyStroke.SaveToStream(AStream: TStream);
begin
with AStream do begin
Write(fKey, SizeOf(fKey));
Write(fShift, SizeOf(fShift));
Write(fKey2, SizeOf(fKey2));
Write(fShift2, SizeOf(fShift2));
Write(fCommand, SizeOf(fCommand));
end;
end;
{end} //ac 2000-07-05
{ TSynEditKeyStrokes }
function TSynEditKeyStrokes.Add: TSynEditKeyStroke;
begin
Result := TSynEditKeyStroke(inherited Add);
end;
procedure TSynEditKeyStrokes.Assign(Source: TPersistent);
var
x: integer;
begin
if Source is TSynEditKeyStrokes then
begin
Clear;
for x := 0 to TSynEditKeyStrokes(Source).Count-1 do
begin
with Add do
Assign(TSynEditKeyStrokes(Source)[x]);
end;
end else
inherited Assign(Source);
end;
constructor TSynEditKeyStrokes.Create(AOwner: TPersistent);
begin
inherited Create(TSynEditKeyStroke);
FOwner := AOwner;
end;
function TSynEditKeyStrokes.FindCommand(Cmd: TSynEditorCommand): integer;
var
x: integer;
begin
Result := -1;
for x := 0 to Count-1 do
if Items[x].Command = Cmd then
begin
Result := x;
break;
end;
end;
function TSynEditKeyStrokes.FindKeycode(Code: word; SS: TShiftState): integer;
var
x: integer;
begin
Result := -1;
for x := 0 to Count-1 do
if (Items[x].Key = Code) and (Items[x].Shift = SS) and (Items[x].Key2 = 0)
then begin
{
writeln('TSynEditKeyStrokes.FindKeycode ',Items[x].Key,'=',Code
,' Shift ',ssShift in Items[x].Shift,'=',ssShift in SS
,' Ctrl ',ssCtrl in Items[x].Shift,'=',ssCtrl in SS
);
}
Result := x;
break;
end;
end;
function TSynEditKeyStrokes.FindKeycode2(Code1: word; SS1: TShiftState;
Code2: word; SS2: TShiftState): integer;
var
x: integer;
begin
Result := -1;
for x := 0 to Count-1 do
if (Items[x].Key = Code1) and (Items[x].Shift = SS1) and
(Items[x].Key2 = Code2) and (Items[x].Shift2 = SS2) then
begin
Result := x;
break;
end;
end;
function TSynEditKeyStrokes.FindShortcut(SC: TShortcut): integer;
var
x: integer;
begin
Result := -1;
for x := 0 to Count-1 do
if Items[x].Shortcut = SC then
begin
Result := x;
break;
end;
end;
function TSynEditKeyStrokes.FindShortcut2(SC, SC2: TShortcut): integer;
var
x: integer;
begin
Result := -1;
for x := 0 to Count-1 do
if (Items[x].Shortcut = SC) and (Items[x].Shortcut2 = SC2) then
begin
Result := x;
break;
end;
end;
function TSynEditKeyStrokes.GetItem(Index: Integer): TSynEditKeyStroke;
begin
Result := TSynEditKeyStroke(inherited GetItem(Index));
end;
{$IFDEF SYN_COMPILER_3_UP}
function TSynEditKeyStrokes.GetOwner: TPersistent;
begin
Result := FOwner;
end;
{$ENDIF}
{begin} //ac 2000-07-05
procedure TSynEditKeyStrokes.LoadFromStream(AStream: TStream);
var
Num: integer;
begin
AStream.Read(Num, SizeOf(Num));
while Num > 0 do begin
with Add do
LoadFromStream(AStream);
Dec(Num);
end;
end;
{end} //ac 2000-07-05
procedure TSynEditKeyStrokes.ResetDefaults;
procedure AddKey(const ACmd: TSynEditorCommand; const AKey: word;
const AShift: TShiftState);
begin
with Add do
begin
Key := AKey;
Shift := AShift;
Command := ACmd;
end;
end;
begin
Clear;
AddKey(ecUp, VK_UP, []);
AddKey(ecSelUp, VK_UP, [ssShift]);
AddKey(ecScrollUp, VK_UP, [ssCtrl]);
AddKey(ecDown, VK_DOWN, []);
AddKey(ecSelDown, VK_DOWN, [ssShift]);
AddKey(ecScrollDown, VK_DOWN, [ssCtrl]);
AddKey(ecLeft, VK_LEFT, []);
AddKey(ecSelLeft, VK_LEFT, [ssShift]);
AddKey(ecWordLeft, VK_LEFT, [ssCtrl]);
AddKey(ecSelWordLeft, VK_LEFT, [ssShift,ssCtrl]);
AddKey(ecRight, VK_RIGHT, []);
AddKey(ecSelRight, VK_RIGHT, [ssShift]);
AddKey(ecWordRight, VK_RIGHT, [ssCtrl]);
AddKey(ecSelWordRight, VK_RIGHT, [ssShift,ssCtrl]);
AddKey(ecPageDown, VK_NEXT, []);
AddKey(ecSelPageDown, VK_NEXT, [ssShift]);
AddKey(ecPageBottom, VK_NEXT, [ssCtrl]);
AddKey(ecSelPageBottom, VK_NEXT, [ssShift,ssCtrl]);
AddKey(ecPageUp, VK_PRIOR, []);
AddKey(ecSelPageUp, VK_PRIOR, [ssShift]);
AddKey(ecPageTop, VK_PRIOR, [ssCtrl]);
AddKey(ecSelPageTop, VK_PRIOR, [ssShift,ssCtrl]);
AddKey(ecLineStart, VK_HOME, []);
AddKey(ecSelLineStart, VK_HOME, [ssShift]);
AddKey(ecEditorTop, VK_HOME, [ssCtrl]);
AddKey(ecSelEditorTop, VK_HOME, [ssShift,ssCtrl]);
AddKey(ecLineEnd, VK_END, []);
AddKey(ecSelLineEnd, VK_END, [ssShift]);
AddKey(ecEditorBottom, VK_END, [ssCtrl]);
AddKey(ecSelEditorBottom, VK_END, [ssShift,ssCtrl]);
AddKey(ecToggleMode, VK_INSERT, []);
AddKey(ecCopy, VK_INSERT, [ssCtrl]);
AddKey(ecPaste, VK_INSERT, [ssShift]);
AddKey(ecDeleteChar, VK_DELETE, []);
AddKey(ecCut, VK_DELETE, [ssShift]);
AddKey(ecDeleteLastChar, VK_BACK, []);
AddKey(ecDeleteLastChar, VK_BACK, [ssShift]); //jr 2000-09-23
AddKey(ecDeleteLastWord, VK_BACK, [ssCtrl]);
AddKey(ecUndo, VK_BACK, [ssAlt]);
AddKey(ecRedo, VK_BACK, [ssAlt,ssShift]);
AddKey(ecLineBreak, VK_RETURN, []);
AddKey(ecSelectAll, ord('A'), [ssCtrl]);
AddKey(ecCopy, ord('C'), [ssCtrl]);
AddKey(ecBlockIndent, ord('I'), [ssCtrl,ssShift]);
AddKey(ecLineBreak, ord('M'), [ssCtrl]);
AddKey(ecInsertLine, ord('N'), [ssCtrl]);
AddKey(ecDeleteWord, ord('T'), [ssCtrl]);
AddKey(ecBlockUnindent, ord('U'), [ssCtrl,ssShift]);
AddKey(ecPaste, ord('V'), [ssCtrl]);
AddKey(ecCut, ord('X'), [ssCtrl]);
AddKey(ecDeleteLine, ord('Y'), [ssCtrl]);
AddKey(ecDeleteEOL, ord('Y'), [ssCtrl,ssShift]);
AddKey(ecUndo, ord('Z'), [ssCtrl]);
AddKey(ecRedo, ord('Z'), [ssCtrl,ssShift]);
AddKey(ecGotoMarker0, ord('0'), [ssCtrl]);
AddKey(ecGotoMarker1, ord('1'), [ssCtrl]);
AddKey(ecGotoMarker2, ord('2'), [ssCtrl]);
AddKey(ecGotoMarker3, ord('3'), [ssCtrl]);
AddKey(ecGotoMarker4, ord('4'), [ssCtrl]);
AddKey(ecGotoMarker5, ord('5'), [ssCtrl]);
AddKey(ecGotoMarker6, ord('6'), [ssCtrl]);
AddKey(ecGotoMarker7, ord('7'), [ssCtrl]);
AddKey(ecGotoMarker8, ord('8'), [ssCtrl]);
AddKey(ecGotoMarker9, ord('9'), [ssCtrl]);
AddKey(ecSetMarker0, ord('0'), [ssCtrl,ssShift]);
AddKey(ecSetMarker1, ord('1'), [ssCtrl,ssShift]);
AddKey(ecSetMarker2, ord('2'), [ssCtrl,ssShift]);
AddKey(ecSetMarker3, ord('3'), [ssCtrl,ssShift]);
AddKey(ecSetMarker4, ord('4'), [ssCtrl,ssShift]);
AddKey(ecSetMarker5, ord('5'), [ssCtrl,ssShift]);
AddKey(ecSetMarker6, ord('6'), [ssCtrl,ssShift]);
AddKey(ecSetMarker7, ord('7'), [ssCtrl,ssShift]);
AddKey(ecSetMarker8, ord('8'), [ssCtrl,ssShift]);
AddKey(ecSetMarker9, ord('9'), [ssCtrl,ssShift]);
AddKey(ecNormalSelect, ord('N'), [ssCtrl,ssShift]);
AddKey(ecColumnSelect, ord('C'), [ssCtrl,ssShift]);
AddKey(ecLineSelect, ord('L'), [ssCtrl,ssShift]);
AddKey(ecTab, VK_TAB, []);
AddKey(ecShiftTab, VK_TAB, [ssShift]);
AddKey(ecMatchBracket, ord('B'), [ssCtrl,ssShift]);
end;
procedure TSynEditKeyStrokes.SetItem(Index: Integer; Value: TSynEditKeyStroke);
begin
inherited SetItem(Index, Value);
end;
{begin} //ac 2000-07-05
procedure TSynEditKeyStrokes.SaveToStream(AStream: TStream);
var
i, Num: integer;
begin
Num := Count;
AStream.Write(Num, SizeOf(Num));
for i := 0 to Num - 1 do
Items[i].SaveToStream(AStream);
end;
{end} //ac 2000-07-05
initialization
{$IFNDEF FPC}
// FOR LAZARUS ToDo
RegisterIntegerConsts(TypeInfo(TSynEditorCommand), IdentToEditorCommand,
EditorCommandToIdent);
{$ENDIF}
end.