shedit.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. {
  2. $Id$
  3. "shedit" - Text editor with syntax highlighting
  4. Copyright (C) 1999 Sebastian Guenther ([email protected])
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. }
  17. // ===================================================================
  18. // Generic text editor widget with syntax highlighting capabilities
  19. // ===================================================================
  20. {$MODE objfpc}
  21. {$H+}
  22. unit shedit;
  23. interface
  24. uses
  25. Classes, doc_text;
  26. type
  27. TSHTextEdit = class;
  28. // -------------------------------------------------------------------
  29. // Keyboard/action assignment handling
  30. // -------------------------------------------------------------------
  31. TKeyboardActionProc = procedure of object;
  32. TSelectionAction = (selNothing,selExtend,selClear);
  33. TKeyboardActionDescr = class(TCollectionItem)
  34. public
  35. Descr: String; // Human readable description
  36. Method: TKeyboardActionProc;
  37. SelectionAction : TSelectionAction;
  38. end;
  39. TShortcut = class(TCollectionItem)
  40. public
  41. KeyCode: Integer;
  42. ShiftState: TShiftState;
  43. Action: TKeyboardActionDescr;
  44. end;
  45. // -------------------------------------------------------------------
  46. // Undo/redo buffer stuff
  47. // -------------------------------------------------------------------
  48. TUndoInfo = class;
  49. TUndoInfo = class
  50. Prev, Next: TUndoInfo;
  51. CursorX, CursorY: Integer;
  52. function Merge(AEdit: TSHTextEdit; AInfo: TUndoInfo): Boolean; virtual;
  53. procedure DoUndo(AEdit: TSHTextEdit); virtual; abstract;
  54. end;
  55. TUndoEdit = class(TUndoInfo)
  56. NumOfChars: Integer;
  57. constructor Create;
  58. constructor Create(ANumOfChars: Integer);
  59. function Merge(AEdit: TSHTextEdit; AInfo: TUndoInfo): Boolean; override;
  60. procedure DoUndo(AEdit: TSHTextEdit); override;
  61. end;
  62. TUndoDelLeft = class(TUndoInfo)
  63. DeletedString: String;
  64. constructor Create(const ADeletedString: String);
  65. function Merge(AEdit: TSHTextEdit; AInfo: TUndoInfo): Boolean; override;
  66. procedure DoUndo(AEdit: TSHTextEdit); override;
  67. end;
  68. TUndoDelRight = class(TUndoDelLeft)
  69. procedure DoUndo(AEdit: TSHTextEdit); override;
  70. end;
  71. // -------------------------------------------------------------------
  72. // Selection support
  73. // -------------------------------------------------------------------
  74. TSelection = class
  75. public
  76. constructor Create;
  77. procedure Clear;
  78. StartX, StartY, EndX, EndY: Integer;
  79. function IsValid: Boolean;
  80. // Ordered coordinates: swaps start and end if necessary
  81. function OStartX: Integer;
  82. function OStartY: Integer;
  83. function OEndX: Integer;
  84. function OEndY: Integer;
  85. end;
  86. // -------------------------------------------------------------------
  87. // SHRenderer interface
  88. // -------------------------------------------------------------------
  89. ISHRenderer = class
  90. procedure InvalidateRect(x1, y1, x2, y2: Integer); virtual; abstract;
  91. procedure InvalidateLines(y1, y2: Integer); virtual; abstract;
  92. // Drawing
  93. procedure ClearRect(x1, y1, x2, y2: Integer); virtual; abstract;
  94. procedure DrawTextLine(x1, x2, y: Integer; s: PChar); virtual; abstract;
  95. // Cursor
  96. procedure ShowCursor(x, y: Integer); virtual; abstract;
  97. procedure HideCursor(x, y: Integer); virtual; abstract;
  98. // Scrolling support
  99. function GetHorzPos: Integer; virtual; abstract;
  100. procedure SetHorzPos(x: Integer); virtual; abstract;
  101. function GetVertPos: Integer; virtual; abstract;
  102. procedure SetVertPos(y: Integer); virtual; abstract;
  103. function GetPageWidth: Integer; virtual; abstract;
  104. function GetPageHeight: Integer; virtual; abstract;
  105. function GetLineWidth: Integer; virtual; abstract;
  106. procedure SetLineWidth(count: Integer); virtual; abstract;
  107. function GetLineCount: Integer; virtual; abstract;
  108. procedure SetLineCount(count: Integer); virtual; abstract;
  109. property HorzPos: Integer read GetHorzPos write SetHorzPos;
  110. property VertPos: Integer read GetVertPos write SetVertPos;
  111. property PageWidth: Integer read GetPageWidth;
  112. property PageHeight: Integer read GetPageHeight;
  113. property LineWidth: Integer read GetLineWidth write SetLineWidth;
  114. property LineCount: Integer read GetLineCount write SetLineCount;
  115. // Clipboard support
  116. function GetClipboard: String; virtual; abstract;
  117. procedure SetClipboard(Content: String); virtual; abstract;
  118. end;
  119. // -------------------------------------------------------------------
  120. // SHTextEdit: The main editor class
  121. // -------------------------------------------------------------------
  122. TShortcutEvent = procedure of object;
  123. TSHTextEdit = class
  124. protected
  125. // ===== Internally used stuff
  126. ViewInfo: TViewInfo; // Connection to document
  127. CursorVisible: Integer;
  128. OverwriteMode: Boolean;
  129. LastUndoInfo, LastRedoInfo: TUndoInfo; // tails of double linked lists
  130. FSel: TSelection;
  131. // OnKeyPressed saves the cursor position before calling key handlers
  132. LastCursorX, LastCursorY: Integer;
  133. function CalcSHFlags(FlagsIn: Byte; source: String): Byte;
  134. procedure HideCursor;
  135. procedure ShowCursor;
  136. procedure ChangeInLine(line: Integer); // Redraws screen where necessary
  137. procedure AddUndoInfo(AInfo: TUndoInfo; CanMerge: Boolean);
  138. // The default implementation does not perform any syntax highlighting:
  139. procedure DoHighlighting(var flags: Byte; source, dest: PChar); virtual;
  140. // ===== Properties
  141. FDoc: TTextDoc; // Document object for text
  142. FCursorX, FCursorY: Integer; // 0/0 = upper left corner
  143. FOnModifiedChange: TNotifyEvent;
  144. FRenderer: ISHRenderer;
  145. procedure SetCursorX(NewCursorX: Integer);
  146. procedure SetCursorY(NewCursorY: Integer);
  147. procedure ModifiedChanged(Sender: TObject);
  148. procedure LineInserted(Sender: TTextDoc; Line: Integer); virtual;
  149. procedure LineRemoved(Sender: TTextDoc; Line: Integer); virtual;
  150. function ExecKey(Key: Char; BlockMode: Boolean): Boolean;
  151. procedure ExecKeys(Keys: String; BlockMode: Boolean);
  152. procedure MultiDelLeft(Count: Integer);
  153. public
  154. // Keyboard command handlers
  155. // Cursor movement
  156. procedure AdjustCursorToRange;
  157. procedure AdjustRangeToCursor;
  158. procedure CursorUp;
  159. procedure CursorDown;
  160. procedure CursorLeft;
  161. procedure CursorRight;
  162. procedure CursorHome;
  163. procedure CursorEnd;
  164. procedure CursorDocBegin;
  165. procedure CursorDocEnd;
  166. procedure CursorPageUp;
  167. procedure CursorPageDown;
  168. // Misc
  169. procedure ToggleOverwriteMode;
  170. procedure EditDelLeft;
  171. procedure EditDelRight;
  172. procedure EditDelLine;
  173. procedure EditUndo;
  174. procedure EditRedo;
  175. procedure ClipboardCut;
  176. procedure ClipboardCopy;
  177. procedure ClipboardPaste;
  178. // Customizable keyboard handlers
  179. procedure KeyReturn; virtual;
  180. public
  181. constructor Create(ADoc: TTextDoc; ARenderer: ISHRenderer); virtual;
  182. function AddKeyboardAction(AMethod: TKeyboardActionProc;ASelectionAction:TSelectionAction;ADescr: String): TKeyboardActionDescr;
  183. function AddKeyboardAssignment(AKeyCode: Integer; AShiftState: TShiftState;
  184. AAction: TKeyboardActionDescr): TShortcut;
  185. procedure AddKeyDef(AMethod: TKeyboardActionProc; ASelectionAction:TSelectionAction; ADescr: String; AKeyCode: Integer; AShiftState: TShiftState);
  186. procedure FocusIn;
  187. procedure FocusOut;
  188. procedure DrawContent(x1, y1, x2, y2: Integer);
  189. procedure KeyPressed(KeyCode: LongWord; ShiftState: TShiftState); virtual;
  190. KeyboardActions: TCollection;
  191. Shortcuts: TCollection;
  192. shDefault, shSelected: Integer;
  193. property Doc: TTextDoc read FDoc;
  194. property CursorX: Integer read FCursorX write SetCursorX;
  195. property CursorY: Integer read FCursorY write SetCursorY;
  196. property Selection: TSelection read FSel write FSel;
  197. property OnModifiedChange: TNotifyEvent
  198. read FOnModifiedChange write FOnModifiedChange;
  199. property Renderer: ISHRenderer read FRenderer;
  200. end;
  201. implementation
  202. uses
  203. Sysutils;
  204. {$INCLUDE undo.inc}
  205. {$INCLUDE keys.inc}
  206. {$INCLUDE drawing.inc}
  207. constructor TSelection.Create;
  208. begin
  209. inherited Create;
  210. Clear;
  211. end;
  212. function TSelection.IsValid: Boolean;
  213. begin
  214. Result := StartX <> -1;
  215. end;
  216. function TSelection.OStartX: Integer;
  217. begin
  218. if (StartY > EndY) or ((StartY = EndY) and (StartX > EndX)) then
  219. Result := EndX
  220. else
  221. Result := StartX;
  222. end;
  223. function TSelection.OStartY: Integer;
  224. begin
  225. if (StartY > EndY) or ((StartY = EndY) and (StartX > EndX)) then
  226. Result := EndY
  227. else
  228. Result := StartY;
  229. end;
  230. function TSelection.OEndX: Integer;
  231. begin
  232. if (StartY > EndY) or ((StartY = EndY) and (StartX > EndX)) then
  233. Result := StartX
  234. else
  235. Result := EndX;
  236. end;
  237. function TSelection.OEndY: Integer;
  238. begin
  239. if (StartY > EndY) or ((StartY = EndY) and (StartX > EndX)) then
  240. Result := StartY
  241. else
  242. Result := EndY;
  243. end;
  244. procedure TSelection.Clear;
  245. begin
  246. StartX := -1;
  247. StartY := -1;
  248. EndX := -1;
  249. EndY := -1;
  250. end;
  251. constructor TSHTextEdit.Create(ADoc: TTextDoc; ARenderer: ISHRenderer);
  252. var
  253. i: Integer;
  254. begin
  255. FDoc := ADoc;
  256. // The document must not be empty
  257. if FDoc.LineCount = 0 then
  258. FDoc.AddLine('');
  259. ViewInfo := TViewInfo(FDoc.ViewInfos.Add);
  260. ViewInfo.OnLineInsert := @LineInserted;
  261. ViewInfo.OnLineRemove := @LineRemoved;
  262. ViewInfo.OnModifiedChange := @ModifiedChanged;
  263. FRenderer := ARenderer;
  264. FSel := TSelection.Create;
  265. KeyboardActions := TCollection.Create(TKeyboardActionDescr);
  266. Shortcuts := TCollection.Create(TShortcut);
  267. Renderer.LineCount := FDoc.LineCount;
  268. Renderer.LineWidth := FDoc.LineWidth;
  269. CursorX:=0;
  270. CursorY:=0;
  271. end;
  272. procedure TSHTextEdit.ModifiedChanged(Sender: TObject);
  273. begin
  274. if Assigned(OnModifiedChange) then
  275. OnModifiedChange(Self);
  276. end;
  277. procedure TSHTextEdit.FocusIn;
  278. begin
  279. CursorVisible := 0;
  280. ShowCursor;
  281. end;
  282. procedure TSHTextEdit.FocusOut;
  283. begin
  284. HideCursor;
  285. end;
  286. procedure TSHTextEdit.SetCursorX(NewCursorX: Integer);
  287. begin
  288. FCursorX := NewCursorX;
  289. HideCursor;
  290. ShowCursor;
  291. end;
  292. procedure TSHTextEdit.SetCursorY(NewCursorY: Integer);
  293. begin
  294. FCursorY := NewCursorY;
  295. HideCursor;
  296. ShowCursor;
  297. end;
  298. procedure TSHTextEdit.LineInserted(Sender: TTextDoc; Line: Integer);
  299. begin
  300. Renderer.LineCount := FDoc.LineCount;
  301. Renderer.LineWidth := FDoc.LineWidth;
  302. ChangeInLine(Line);
  303. end;
  304. procedure TSHTextEdit.LineRemoved(Sender: TTextDoc; Line: Integer);
  305. begin
  306. LineInserted(Sender, Line);
  307. end;
  308. end.
  309. {
  310. $Log$
  311. Revision 1.5 1999-12-10 15:01:03 peter
  312. * first things for selection
  313. * Better Adjusting of range/cursor
  314. Revision 1.4 1999/12/09 23:16:41 peter
  315. * cursor walking is now possible, both horz and vert ranges are now
  316. adapted
  317. * filter key modifiers
  318. * selection move routines added, but still no correct output to the
  319. screen
  320. Revision 1.3 1999/12/06 21:27:27 peter
  321. * gtk updates, redrawing works now much better and clears only between
  322. x1 and x2
  323. Revision 1.2 1999/11/15 21:47:36 peter
  324. * first working keypress things
  325. Revision 1.1 1999/10/29 15:59:04 peter
  326. * inserted in fcl
  327. }