keys.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. {
  2. "SHEdit" - Text editor with syntax highlighting
  3. Copyright (C) 1999-2000 by Sebastian Guenther ([email protected])
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. }
  10. // TSHTextEdit: Implementation of keyboard handling methods
  11. function TSHTextEdit.AddKeyboardAction(AMethod: TKeyboardActionProc;ASelectionAction:TSelectionAction;ADescr: String): TKeyboardActionDescr;
  12. begin
  13. Result := TKeyboardActionDescr(KeyboardActions.Add);
  14. Result.Descr := ADescr;
  15. Result.Method := AMethod;
  16. Result.SelectionAction := ASelectionAction;
  17. end;
  18. function TSHTextEdit.AddKeyboardAssignment(AKeyCode: Integer; AShiftState: TShiftState; AAction: TKeyboardActionDescr): TShortcut;
  19. begin
  20. Result := TShortcut(Shortcuts.Add);
  21. Result.KeyCode := AKeyCode;
  22. Result.ShiftState := AShiftState;
  23. Result.Action := AAction;
  24. end;
  25. procedure TSHTextEdit.AddKeyDef(AMethod: TKeyboardActionProc; ASelectionAction:TSelectionAction; ADescr: String; AKeyCode: Integer; AShiftState: TShiftState);
  26. begin
  27. AddKeyboardAssignment(AKeyCode, AShiftState,AddKeyboardAction(AMethod, ASelectionAction, ADescr));
  28. end;
  29. procedure TSHTextEdit.ToggleOverwriteMode;
  30. begin
  31. OverwriteMode := not OverwriteMode; // *** specify signal for change
  32. end;
  33. procedure TSHTextEdit.AdjustCursorToRange;
  34. begin
  35. if FCursorY < FWidget.VertPos then begin
  36. HideCursor;
  37. FCursorY := FWidget.VertPos;
  38. ShowCursor;
  39. end else if FCursorY > FWidget.VertPos + FWidget.PageHeight then begin
  40. HideCursor;
  41. FCursorY := FWidget.VertPos + FWidget.PageHeight - 1;
  42. ShowCursor;
  43. end;
  44. if FCursorX < FWidget.HorzPos then begin
  45. HideCursor;
  46. FCursorX := FWidget.HorzPos;
  47. ShowCursor;
  48. end else if FCursorX > FWidget.HorzPos + FWidget.PageWidth then begin
  49. HideCursor;
  50. FCursorX := FWidget.HorzPos + FWidget.PageWidth - 1;
  51. ShowCursor;
  52. end;
  53. end;
  54. procedure TSHTextEdit.AdjustRangeToCursor;
  55. var
  56. py : integer;
  57. begin
  58. if FCursorY < FWidget.VertPos then
  59. FWidget.VertPos := FCursorY
  60. else if FCursorY >= FWidget.VertPos + FWidget.PageHeight then begin
  61. py := FCursorY - FWidget.PageHeight + 1;
  62. if py < 0 then
  63. FWidget.VertPos:=0
  64. else
  65. FWidget.VertPos:=py;
  66. end;
  67. if FCursorX < FWidget.HorzPos then
  68. FWidget.HorzPos := FCursorX
  69. else if FCursorX >= FWidget.HorzPos + FWidget.PageWidth then begin
  70. py := FCursorX - FWidget.PageWidth + 1;
  71. if py < 0 then
  72. FWidget.HorzPos := 0
  73. else
  74. FWidget.HorzPos := py;
  75. end;
  76. end;
  77. procedure TSHTextEdit.CursorUp;
  78. begin
  79. if FCursorY > 0 then
  80. Dec(FCursorY);
  81. end;
  82. procedure TSHTextEdit.CursorDown;
  83. begin
  84. if FCursorY < FDoc.LineCount - 1 then
  85. Inc(FCursorY);
  86. end;
  87. procedure TSHTextEdit.CursorLeft;
  88. begin
  89. Dec(FCursorX);
  90. if FCursorX < 0 then
  91. if FCursorY>0 then begin
  92. Dec(FCursorY);
  93. FCursorX := FDoc.LineLen[FCursorY];
  94. end else
  95. FCursorX := 0;
  96. end;
  97. procedure TSHTextEdit.CursorRight;
  98. begin
  99. Inc(FCursorX);
  100. end;
  101. procedure TSHTextEdit.CursorDocBegin;
  102. begin
  103. FCursorX := 0;
  104. FCursorY := 0;
  105. end;
  106. procedure TSHTextEdit.CursorDocEnd;
  107. begin
  108. FCursorY := FDoc.LineCount-1;
  109. FCursorX := FDoc.LineLen[FCursorY];
  110. end;
  111. procedure TSHTextEdit.CursorHome;
  112. begin
  113. FCursorX := 0;
  114. AdjustRangeToCursor;
  115. end;
  116. procedure TSHTextEdit.CursorEnd;
  117. begin
  118. FCursorX := FDoc.LineLen[FCursorY];
  119. AdjustRangeToCursor;
  120. end;
  121. procedure TSHTextEdit.CursorPageUp;
  122. begin
  123. Dec(FCursorY, FWidget.PageHeight);
  124. if FCursorY < 0 then
  125. FCursorY := 0;
  126. end;
  127. procedure TSHTextEdit.CursorPageDown;
  128. begin
  129. Inc(FCursorY, FWidget.PageHeight);
  130. if FCursorY > FDoc.LineCount - 1 then
  131. FCursorY := FDoc.LineCount - 1;
  132. end;
  133. procedure TSHTextEdit.EditDelLeft;
  134. var
  135. s: String;
  136. begin
  137. if FCursorX > 0 then begin
  138. s := FDoc.LineText[FCursorY];
  139. Dec(FCursorX);
  140. AddUndoInfo(TUndoDelLeft.Create(s[FCursorX + 1]), True);
  141. s := Copy(s, 1, FCursorX) + Copy(s, FCursorX + 2, Length(s));
  142. FDoc.LineText[FCursorY] := s;
  143. ChangeInLine(FCursorY);
  144. end else if FCursorY > 0 then begin
  145. FCursorX := FDoc.LineLen[FCursorY - 1];
  146. FDoc.LineText[FCursorY - 1] := FDoc.LineText[FCursorY - 1] +
  147. FDoc.LineText[FCursorY];
  148. Dec(FCursorY);
  149. FDoc.RemoveLine(FCursorY + 1);
  150. AddUndoInfo(TUndoDelLeft.Create(#13), True);
  151. end;
  152. end;
  153. procedure TSHTextEdit.EditDelRight;
  154. var
  155. s: String;
  156. begin
  157. if FCursorX < FDoc.LineLen[FCursorY] then begin
  158. s := FDoc.LineText[FCursorY];
  159. AddUndoInfo(TUndoDelRight.Create(s[FCursorX + 1]), True);
  160. s := Copy(s, 1, FCursorX) + Copy(s, FCursorX + 2, Length(s));
  161. FDoc.LineText[FCursorY] := s;
  162. ChangeInLine(FCursorY);
  163. end else if FCursorY < FDoc.LineCount - 1 then begin
  164. FDoc.LineText[FCursorY] := FDoc.LineText[FCursorY] +
  165. FDoc.LineText[FCursorY + 1];
  166. FDoc.RemoveLine(FCursorY + 1);
  167. AddUndoInfo(TUndoDelRight.Create(#13), True);
  168. end;
  169. end;
  170. procedure TSHTextEdit.EditDelLine;
  171. var
  172. DeletedText: String;
  173. begin
  174. DeletedText := FDoc.LineText[FCursorY];
  175. if FDoc.LineCount = 1 then
  176. FDoc.LineText[FCursorY] := ''
  177. else
  178. FDoc.RemoveLine(FCursorY);
  179. if FCursorY >= FDoc.LineCount then
  180. FCursorY := FDoc.LineCount - 1;
  181. FCursorX := 0;
  182. AddUndoInfo(TUndoDelRight.Create(DeletedText + #13), True);
  183. ChangeInLine(FCursorY);
  184. end;
  185. procedure TSHTextEdit.EditUndo;
  186. var
  187. info: TUndoInfo;
  188. begin
  189. if LastUndoInfo = nil then exit;
  190. info := LastUndoInfo;
  191. LastUndoInfo := LastRedoInfo;
  192. info.DoUndo(Self);
  193. LastRedoInfo := LastUndoInfo;
  194. LastUndoInfo := info;
  195. // Free undo info
  196. if info.Prev <> nil then
  197. info.Prev.Next := info.Next
  198. else
  199. FDoc.Modified := False;
  200. LastUndoInfo := info.Prev;
  201. info.Free;
  202. end;
  203. procedure TSHTextEdit.EditRedo;
  204. var
  205. info: TUndoInfo;
  206. begin
  207. if LastRedoInfo = nil then exit;
  208. info := LastRedoInfo;
  209. info.DoUndo(Self);
  210. // Free redo info
  211. if info.Prev <> nil then
  212. info.Prev.Next := info.Next;
  213. LastRedoInfo := info.Prev;
  214. info.Free;
  215. end;
  216. procedure TSHTextEdit.ClipboardCut;
  217. begin
  218. WriteLn('ClipboardCut: Not implemented yet');
  219. ClipboardCopy;
  220. end;
  221. procedure TSHTextEdit.ClipboardCopy;
  222. var
  223. cbtext: String;
  224. y: Integer;
  225. begin
  226. if FSel.OStartY = FSel.OEndY then
  227. cbtext := Copy(FDoc.LineText[FSel.OStartY],
  228. FSel.OStartX + 1, FSel.OEndX - FSel.OStartX)
  229. else begin
  230. cbtext := Copy(FDoc.LineText[FSel.OStartY],
  231. FSel.OStartX + 1, FDoc.LineLen[FSel.OStartY]) + #10;
  232. for y := FSel.OStartY + 1 to FSel.OEndY - 1 do
  233. cbtext := cbtext + FDoc.LineText[y] + #10;
  234. cbtext := cbtext + Copy(FDoc.LineText[FSel.OEndY], 1, FSel.OEndX);
  235. end;
  236. FWidget.SetClipboard(cbtext);
  237. end;
  238. procedure TSHTextEdit.ClipboardPaste;
  239. var
  240. cbtext: String;
  241. begin
  242. cbtext := FWidget.GetClipboard;
  243. ExecKeys(cbtext, True);
  244. end;
  245. procedure TSHTextEdit.KeyReturn; begin end;
  246. function TSHTextEdit.ExecKey(Key: Char; BlockMode: Boolean): Boolean;
  247. var
  248. s, s2: String;
  249. i: Integer;
  250. begin
  251. Result := True;
  252. case Key of
  253. #9: begin
  254. s := FDoc.LineText[FCursorY];
  255. s2 := ' ';
  256. i := 1;
  257. while ((FCursorX + i) mod 4) <> 0 do begin
  258. s2 := s2 + ' ';
  259. Inc(i);
  260. end;
  261. s := Copy(s, 1, FCursorX) + s2 + Copy(s, FCursorX + 1, Length(s));
  262. FDoc.LineText[FCursorY] := s;
  263. Inc(FCursorX, i);
  264. AddUndoInfo(TUndoEdit.Create(i), True);
  265. ChangeInLine(FCursorY);
  266. end;
  267. #13: begin
  268. s := FDoc.LineText[FCursorY];
  269. FDoc.LineText[FCursorY] := Copy(s, 1, FCursorX);
  270. FDoc.InsertLine(FCursorY + 1, Copy(s, FCursorX + 1, Length(s)));
  271. CursorX := 0;
  272. Inc(FCursorY);
  273. AddUndoInfo(TUndoEdit.Create, True);
  274. if not BlockMode then KeyReturn;
  275. end;
  276. #32..#255:
  277. begin
  278. s := FDoc.LineText[FCursorY];
  279. if FCursorX>=Length(s) then
  280. s := s + Space(FCursorX-length(s)) + Key
  281. else
  282. if OverwriteMode then
  283. s := Copy(s, 1, FCursorX) + Key + Copy(s, FCursorX + 2, Length(s))
  284. else
  285. s := Copy(s, 1, FCursorX) + Key + Copy(s, FCursorX + 1, Length(s));
  286. FDoc.LineText[FCursorY] := s;
  287. Inc(FCursorX);
  288. AddUndoInfo(TUndoEdit.Create, True);
  289. ChangeInLine(FCursorY);
  290. end;
  291. else Result := False;
  292. end;
  293. end;
  294. procedure TSHTextEdit.ExecKeys(Keys: String; BlockMode: Boolean);
  295. var
  296. s, s2: String;
  297. KeysPos, i: Integer;
  298. Key: Char;
  299. begin
  300. if BlockMode then
  301. AddUndoInfo(TUndoEdit.Create(0), False); // Initialize new undo block
  302. KeysPos := 1;
  303. while KeysPos <= Length(Keys) do begin
  304. case Keys[KeysPos] of
  305. #9: begin
  306. s := FDoc.LineText[FCursorY];
  307. s2 := ' ';
  308. i := 1;
  309. while ((FCursorX + i) mod 4) <> 0 do begin
  310. s2 := s2 + ' ';
  311. Inc(i);
  312. end;
  313. s := Copy(s, 1, FCursorX) + s2 + Copy(s, FCursorX + 1, Length(s));
  314. FDoc.LineText[FCursorY] := s;
  315. Inc(FCursorX, i);
  316. AddUndoInfo(TUndoEdit.Create(i), True);
  317. ChangeInLine(FCursorY);
  318. Inc(KeysPos);
  319. end;
  320. #13, #10: begin
  321. s := FDoc.LineText[FCursorY];
  322. FDoc.LineText[FCursorY] := Copy(s, 1, FCursorX);
  323. FDoc.InsertLine(FCursorY + 1, Copy(s, FCursorX + 1, Length(s)));
  324. CursorX := 0;
  325. Inc(FCursorY);
  326. AddUndoInfo(TUndoEdit.Create, True);
  327. if not BlockMode then KeyReturn;
  328. Inc(KeysPos);
  329. end;
  330. #32..#255: begin
  331. i := 0;
  332. while (KeysPos <= Length(Keys)) and (Keys[KeysPos] >= #32) do begin
  333. Key := Keys[KeysPos];
  334. s := FDoc.LineText[FCursorY];
  335. if FCursorX>=Length(s) then
  336. s := s + Space(FCursorX-length(s)) + Key
  337. else
  338. s := Copy(s, 1, FCursorX) + Key + Copy(s, FCursorX + 1 + Ord(OverwriteMode), Length(s));
  339. FDoc.LineText[FCursorY] := s;
  340. Inc(FCursorX);
  341. Inc(i);
  342. Inc(KeysPos);
  343. end;
  344. AddUndoInfo(TUndoEdit.Create(i), True);
  345. ChangeInLine(FCursorY);
  346. end;
  347. else Inc(KeysPos);
  348. end;
  349. end;
  350. end;
  351. procedure TSHTextEdit.MultiDelLeft(count: Integer);
  352. var
  353. s: String;
  354. begin
  355. while count > 0 do begin
  356. if FCursorX > 0 then begin
  357. while (FCursorX > 0) and (count > 0) do begin
  358. s := FDoc.LineText[FCursorY];
  359. Dec(FCursorX);
  360. AddUndoInfo(TUndoDelLeft.Create(s[FCursorX + 1]), True);
  361. s := Copy(s, 1, FCursorX) + Copy(s, FCursorX + 2, Length(s));
  362. FDoc.LineText[FCursorY] := s;
  363. Dec(count);
  364. end;
  365. ChangeInLine(FCursorY);
  366. end else if FCursorY > 0 then begin
  367. FCursorX := FDoc.LineLen[FCursorY - 1];
  368. FDoc.LineText[FCursorY - 1] := FDoc.LineText[FCursorY - 1] +
  369. FDoc.LineText[FCursorY];
  370. Dec(FCursorY);
  371. FDoc.RemoveLine(FCursorY + 1);
  372. AddUndoInfo(TUndoDelLeft.Create(#13), True);
  373. Dec(count);
  374. end else break;
  375. end;
  376. end;
  377. function TSHTextEdit.KeyPressed(KeyCode: LongWord; ShiftState: TShiftState): Boolean;
  378. var
  379. i: Integer;
  380. shortcut: TShortcut;
  381. ShortcutFound: Boolean;
  382. begin
  383. // WriteLn('TSHTextEdit: Key pressed: ', KeyCode);
  384. LastCursorX := FCursorX;
  385. LastCursorY := FCursorY;
  386. StartSelectionChange;
  387. // Check for keyboard shortcuts
  388. ShortcutFound := False;
  389. for i := 0 to Shortcuts.Count - 1 do begin
  390. shortcut := TShortcut(Shortcuts.Items[i]);
  391. if (KeyCode = shortcut.KeyCode) and
  392. (ShiftState * [ssShift, ssCtrl, ssAlt] = shortcut.ShiftState) then begin
  393. ShortcutFound := True;
  394. break;
  395. end;
  396. end;
  397. Result := True;
  398. if ShortcutFound then begin
  399. // WriteLn(shortcut.Action.Descr);
  400. shortcut.Action.Method; // Execute associated action
  401. // Handle the selection extending
  402. case shortcut.Action.SelectionAction of
  403. selNothing: ;
  404. selExtend: begin
  405. if not FSel.IsValid then begin
  406. FSel.StartX:=LastCursorX;
  407. FSel.StartY:=LastCursorY;
  408. end;
  409. FSel.EndX:=FCursorX;
  410. FSel.EndY:=FCursorY;
  411. end;
  412. selClear:
  413. FSel.Clear;
  414. end;
  415. end else
  416. if (KeyCode <= 255) and (ShiftState * [ssCtrl, ssAlt] = []) then
  417. ExecKey(Chr(KeyCode), False)
  418. else
  419. Result := False; // Key has not been processed
  420. EndSelectionChange;
  421. AdjustRangeToCursor;
  422. end;