1 unit Editors;
2
3 {$i platform.inc}
4
5 {$ifdef PPC_FPC}
6 {$H-}
7 {$else}
8 {$F+,O+,E+,N+}
9 {$endif}
10 {$X+,R-,I-,Q-,V-}
11 {$ifndef OS_UNIX}
12 {$S-}
13 {$endif}
14
15
16 {$define UNIXLF}
17
18 {2.0 compatibility}
19 {$ifdef VER2_0}
20 {$macro on}
21 {$define resourcestring := const}
22 {$endif}
23
24 interface
25
26 uses
27 Objects, Drivers,Views,Dialogs,FVCommon,FVConsts;
28
29 const
30 { Length constants. }
31 Tab_Stop_Length = 74;
32
33 {$ifdef BIT_16}
34 MaxLineLength = 1024;
35 MinBufLength = $1000;
36 MaxBufLength = $ff00;
37 NotFoundValue = $ffff;
38 LineInfoGrow = 256;
39 MaxLines = 16000;
40 {$else}
41 MaxLineLength = 4096;
42 MinBufLength = $1000;
43 MaxBufLength = $7fffff00;
44 NotFoundValue = $ffffffff;
45 LineInfoGrow = 1024;
46 MaxLines = $7ffffff;
47 {$endif}
48
49
50 { Editor constants for dialog boxes. }
51 edOutOfMemory = 0;
52 edReadError = 1;
53 edWriteError = 2;
54 edCreateError = 3;
55 edSaveModify = 4;
56 edSaveUntitled = 5;
57 edSaveAs = 6;
58 edFind = 7;
59 edSearchFailed = 8;
60 edReplace = 9;
61 edReplacePrompt = 10;
62
63 edJumpToLine = 11;
64 edPasteNotPossible = 12;
65 edReformatDocument = 13;
66 edReformatNotAllowed = 14;
67 edReformNotPossible = 15;
68 edReplaceNotPossible = 16;
69 edRightMargin = 17;
70 edSetTabStops = 18;
71 edWrapNotPossible = 19;
72
73 { Editor flag constants for dialog options. }
74 efCaseSensitive = $0001;
75 efWholeWordsOnly = $0002;
76 efPromptOnReplace = $0004;
77 efReplaceAll = $0008;
78 efDoReplace = $0010;
79 efBackupFiles = $0100;
80
81 { Constants for object palettes. }
82 CIndicator = #2#3;
83 CEditor = #6#7;
84 CMemo = #26#27;
85
86 type
87 TEditorDialog = function (Dialog : Integer; Info : Pointer) : Word;
88
89 PIndicator = ^TIndicator;
90 TIndicator = object (TView)
91 Location : Objects.TPoint;
92 Modified : Boolean;
93 AutoIndent : Boolean; { Added boolean for AutoIndent mode. }
94 WordWrap : Boolean; { Added boolean for WordWrap mode. }
95 constructor Init (var Bounds : TRect);
96 procedure Draw; virtual;
GetPalettenull97 function GetPalette : PPalette; virtual;
98 procedure SetState (AState : Word; Enable : Boolean); virtual;
99 procedure SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean;
100 IsModified : Boolean;
101 IsWordWrap : Boolean);
102 end;
103
104 TLineInfoRec = record
105 Len,Attr : Sw_word;
106 end;
107 TLineInfoArr = array[0..MaxLines] of TLineInfoRec;
108 PLineInfoArr = ^TLineInfoArr;
109
110 PLineInfo = ^TLineInfo;
111 TLineInfo = object
112 Info : PLineInfoArr;
113 MaxPos : Sw_Word;
114 constructor Init;
115 destructor Done;
116 procedure Grow(pos:Sw_word);
117 procedure SetLen(pos,val:Sw_Word);
118 procedure SetAttr(pos,val:Sw_Word);
GetLennull119 function GetLen(pos:Sw_Word):Sw_Word;
GetAttrnull120 function GetAttr(pos:Sw_Word):Sw_Word;
121 end;
122
123
124 PEditBuffer = ^TEditBuffer;
125 TEditBuffer = array[0..MaxBufLength] of Char;
126
127 PEditor = ^TEditor;
128 TEditor = object (TView)
129 HScrollBar : PScrollBar;
130 VScrollBar : PScrollBar;
131 Indicator : PIndicator;
132 Buffer : PEditBuffer;
133 BufSize : Sw_Word;
134 BufLen : Sw_Word;
135 GapLen : Sw_Word;
136 SelStart : Sw_Word;
137 SelEnd : Sw_Word;
138 CurPtr : Sw_Word;
139 CurPos : Objects.TPoint;
140 Delta : Objects.TPoint;
141 Limit : Objects.TPoint;
142 DrawLine : Sw_Integer;
143 DrawPtr : Sw_Word;
144 DelCount : Sw_Word;
145 InsCount : Sw_Word;
146 Flags : Longint;
147 IsReadOnly : Boolean;
148 IsValid : Boolean;
149 CanUndo : Boolean;
150 Modified : Boolean;
151 Selecting : Boolean;
152 Overwrite : Boolean;
153 AutoIndent : Boolean;
154 NoSelect : Boolean;
155 TabSize : Sw_Word; { tabsize for displaying }
156 BlankLine : Sw_Word; { First blank line after a paragraph. }
157 Word_Wrap : Boolean; { Added boolean to toggle wordwrap on/off. }
158 Line_Number : string[8]; { Holds line number to jump to. }
159 Right_Margin : Sw_Integer; { Added integer to set right margin. }
160 Tab_Settings : String[Tab_Stop_Length]; { Added string to hold tab stops. }
161
162 constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar;
163 AIndicator : PIndicator; ABufSize : Sw_Word);
164 constructor Load (var S : Objects.TStream);
165 destructor Done; virtual;
BufCharnull166 function BufChar (P : Sw_Word) : Char;
BufPtrnull167 function BufPtr (P : Sw_Word) : Sw_Word;
168 procedure ChangeBounds (var Bounds : TRect); virtual;
169 procedure ConvertEvent (var Event : Drivers.TEvent); virtual;
CursorVisiblenull170 function CursorVisible : Boolean;
171 procedure DeleteSelect;
172 procedure DoneBuffer; virtual;
173 procedure Draw; virtual;
174 procedure FormatLine (var DrawBuf; LinePtr : Sw_Word; Width : Sw_Integer; Colors : Word);virtual;
GetPalettenull175 function GetPalette : PPalette; virtual;
176 procedure HandleEvent (var Event : Drivers.TEvent); virtual;
177 procedure InitBuffer; virtual;
InsertBuffernull178 function InsertBuffer (var P : PEditBuffer; Offset, Length : Sw_Word;AllowUndo, SelectText : Boolean) : Boolean;
InsertFromnull179 function InsertFrom (Editor : PEditor) : Boolean; virtual;
InsertTextnull180 function InsertText (Text : Pointer; Length : Sw_Word; SelectText : Boolean) : Boolean;
181 procedure ScrollTo (X, Y : Sw_Integer);
Searchnull182 function Search (const FindStr : String; Opts : Word) : Boolean;
SetBufSizenull183 function SetBufSize (NewSize : Sw_Word) : Boolean; virtual;
184 procedure SetCmdState (Command : Word; Enable : Boolean);
185 procedure SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean);
186 procedure SetCurPtr (P : Sw_Word; SelectMode : Byte);
187 procedure SetState (AState : Word; Enable : Boolean); virtual;
188 procedure Store (var S : Objects.TStream);
189 procedure TrackCursor (Center : Boolean);
190 procedure Undo;
191 procedure UpdateCommands; virtual;
Validnull192 function Valid (Command : Word) : Boolean; virtual;
193
194 private
195 KeyState : Integer;
196 LockCount : Byte;
197 UpdateFlags : Byte;
198 Place_Marker : Array [1..10] of Sw_Word; { Inserted array to hold place markers. }
199 Search_Replace : Boolean; { Added boolean to test for Search and Replace insertions. }
200
201 procedure Center_Text (Select_Mode : Byte);
CharPosnull202 function CharPos (P, Target : Sw_Word) : Sw_Integer;
CharPtrnull203 function CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word;
204 procedure Check_For_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean);
ClipCopynull205 function ClipCopy : Boolean;
206 procedure ClipCut;
207 procedure ClipPaste;
208 procedure DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean);
209 procedure DoSearchReplace;
210 procedure DoUpdate;
Do_Word_Wrapnull211 function Do_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean;
212 procedure DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word);
213 procedure Find;
GetMousePtrnull214 function GetMousePtr (Mouse : Objects.TPoint) : Sw_Word;
HasSelectionnull215 function HasSelection : Boolean;
216 procedure HideSelect;
217 procedure Insert_Line (Select_Mode : Byte);
IsClipboardnull218 function IsClipboard : Boolean;
219 procedure Jump_Place_Marker (Element : Byte; Select_Mode : Byte);
220 procedure Jump_To_Line (Select_Mode : Byte);
LineEndnull221 function LineEnd (P : Sw_Word) : Sw_Word;
LineMovenull222 function LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word;
LineStartnull223 function LineStart (P : Sw_Word) : Sw_Word;
LineNrnull224 function LineNr (P : Sw_Word) : Sw_Word;
225 procedure Lock;
NewLinenull226 function NewLine (Select_Mode : Byte) : Boolean;
NextCharnull227 function NextChar (P : Sw_Word) : Sw_Word;
NextLinenull228 function NextLine (P : Sw_Word) : Sw_Word;
NextWordnull229 function NextWord (P : Sw_Word) : Sw_Word;
PrevCharnull230 function PrevChar (P : Sw_Word) : Sw_Word;
PrevLinenull231 function PrevLine (P : Sw_Word) : Sw_Word;
PrevWordnull232 function PrevWord (P : Sw_Word) : Sw_Word;
233 procedure Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean);
Reformat_Paragraphnull234 function Reformat_Paragraph (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean;
235 procedure Remove_EOL_Spaces (Select_Mode : Byte);
236 procedure Replace;
237 procedure Scroll_Down;
238 procedure Scroll_Up;
239 procedure Select_Word;
240 procedure SetBufLen (Length : Sw_Word);
241 procedure Set_Place_Marker (Element : Byte);
242 procedure Set_Right_Margin;
243 procedure Set_Tabs;
244 procedure StartSelect;
245 procedure Tab_Key (Select_Mode : Byte);
246 procedure ToggleInsMode;
247 procedure Unlock;
248 procedure Update (AFlags : Byte);
249 procedure Update_Place_Markers (AddCount : Word; KillCount : Word; StartPtr,EndPtr : Sw_Word);
250 end;
251
252 TMemoData = record
253 Length : Sw_Word;
254 Buffer : TEditBuffer;
255 end;
256
257 PMemo = ^TMemo;
258 TMemo = object (TEditor)
259 constructor Load (var S : Objects.TStream);
DataSizenull260 function DataSize : Sw_Word; virtual;
261 procedure GetData (var Rec); virtual;
GetPalettenull262 function GetPalette : PPalette; virtual;
263 procedure HandleEvent (var Event : Drivers.TEvent); virtual;
264 procedure SetData (var Rec); virtual;
265 procedure Store (var S : Objects.TStream);
266 end;
267
268 PFileEditor = ^TFileEditor;
269 TFileEditor = object (TEditor)
270 FileName : FNameStr;
271 constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar;
272 AIndicator : PIndicator; AFileName : FNameStr);
273 constructor Load (var S : Objects.TStream);
274 procedure DoneBuffer; virtual;
275 procedure HandleEvent (var Event : Drivers.TEvent); virtual;
276 procedure InitBuffer; virtual;
LoadFilenull277 function LoadFile : Boolean;
Savenull278 function Save : Boolean;
SaveAsnull279 function SaveAs : Boolean;
SaveFilenull280 function SaveFile : Boolean;
SetBufSizenull281 function SetBufSize (NewSize : Sw_Word) : Boolean; virtual;
282 procedure Store (var S : Objects.TStream);
283 procedure UpdateCommands; virtual;
Validnull284 function Valid (Command : Word) : Boolean; virtual;
285 end;
286
287 PEditWindow = ^TEditWindow;
288 TEditWindow = object (TWindow)
289 Editor : PFileEditor;
290 constructor Init (var Bounds : TRect; FileName : FNameStr; ANumber : Integer);
291 constructor Load (var S : Objects.TStream);
292 procedure Close; virtual;
GetTitlenull293 function GetTitle (MaxSize : Sw_Integer) : TTitleStr; virtual;
294 procedure HandleEvent (var Event : Drivers.TEvent); virtual;
295 procedure SizeLimits(var Min, Max: TPoint); virtual;
296 procedure Store (var S : Objects.TStream);
297 end;
298
299
DefEditorDialognull300 function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word;
CreateFindDialognull301 function CreateFindDialog: PDialog;
CreateReplaceDialognull302 function CreateReplaceDialog: PDialog;
JumpLineDialognull303 function JumpLineDialog : PDialog;
ReformDocDialognull304 function ReformDocDialog : PDialog;
RightMarginDialognull305 function RightMarginDialog : PDialog;
TabStopDialognull306 function TabStopDialog : Dialogs.PDialog;
StdEditorDialognull307 function StdEditorDialog(Dialog: Integer; Info: Pointer): Word;
308
309 const
310 WordChars : set of Char = ['!'..#255];
311
312 LineBreak : string[2]=
313 {$ifdef UNIXLF}
314 #10;
315 {$else}
316 #13#10;
317 {$endif}
318
319
320 { The Allow_Reformat boolean is a programmer hook. }
321 { I've placed this here to allow programmers to }
322 { determine whether or not paragraph and document }
323 { reformatting are allowed if Word_Wrap is not }
324 { active. Some people say don't allow, and others }
325 { say allow it. I've left it up to the programmer. }
326 { Set to FALSE if not allowed, or TRUE if allowed. }
327 Allow_Reformat : Boolean = True;
328
329 EditorDialog : TEditorDialog = {$ifdef fpc}@{$endif}DefEditorDialog;
330 EditorFlags : Word = efBackupFiles + efPromptOnReplace;
331 FindStr : String[80] = '';
332 ReplaceStr : String[80] = '';
333 Clipboard : PEditor = nil;
334
335 ToClipCmds : TCommandSet = ([cmCut,cmCopy,cmClear]);
336 FromClipCmds : TCommandSet = ([cmPaste]);
337 UndoCmds : TCommandSet = ([cmUndo,cmRedo]);
338
339 TYPE
340 TFindDialogRec =
341 {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
342 packed
343 {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
344 record
345 Find : String[80];
346 Options : Word;
347 end;
348
349 TReplaceDialogRec =
350 {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
351 packed
352 {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
353 record
354 Find : String[80];
355 Replace : String[80];
356 Options : Word;
357 end;
358
359 TRightMarginRec =
360 {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
361 packed
362 {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
363 record
364 Margin_Position : String[3];
365 end;
366
367 TTabStopRec =
368 {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
369 packed
370 {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
371 record
372 Tab_String : String [Tab_Stop_Length];
373 end;
374
375 CONST
376 { VMT constants. }
377 REditor : TStreamRec = (ObjType : 70;
378 VmtLink : Ofs (TypeOf (TEditor)^);
379 Load : @TEditor.Load;
380 Store : @TEditor.Store);
381
382 RMemo : TStreamRec = (ObjType : 71;
383 VmtLink : Ofs (TypeOf (TMemo)^);
384 Load : @TMemo.Load;
385 Store : @TMemo.Store);
386
387 RFileEditor : TStreamRec = (ObjType : 72;
388 VmtLink : Ofs (TypeOf (TFileEditor)^);
389 Load : @TFileEditor.Load;
390 Store : @TFileEditor.Store);
391
392 RIndicator : TStreamRec = (ObjType : 73;
393 VmtLink : Ofs (TypeOf (TIndicator)^);
394 Load : @TIndicator.Load;
395 Store : @TIndicator.Store);
396
397 REditWindow : TStreamRec = (ObjType : 74;
398 VmtLink : Ofs (TypeOf (TEditWindow)^);
399 Load : @TEditWindow.Load;
400 Store : @TEditWindow.Store);
401
402 procedure RegisterEditors;
403
404
405 {****************************************************************************
406 Implementation
407 ****************************************************************************}
408
409 implementation
410
411 uses
412 Dos, App, StdDlg, MsgBox{, Resource};
413
414 type
415 pword = ^word;
416
417 resourcestring sClipboard='Clipboard';
418 sFileCreateError='Error creating file %s';
419 sFileReadError='Error reading file %s';
420 sFileUntitled='Save untitled file?';
421 sFileWriteError='Error writing to file %s';
422 sFind='Find';
423 sJumpTo='Jump To';
424 sModified=''#3'%s'#13#10#13#3'has been modified. Save?';
425 sOutOfMemory='Not enough memory for this operation.';
426 sPasteNotPossible='Wordwrap on: Paste not possible in current margins when at end of line.';
427 sReformatDocument='Reformat Document';
428 sReformatNotPossible='Paragraph reformat not possible while trying to wrap current line with current margins.';
429 sReformattingTheDocument='Reformatting the document:';
430 sReplaceNotPossible='Wordwrap on: Replace not possible in current margins when at end of line.';
431 sReplaceThisOccurence='Replace this occurrence?';
432 sRightMargin='Right Margin';
433 sSearchStringNotFound='Search string not found.';
434 sSelectWhereToBegin='Please select where to begin.';
435 sSetting='Setting:';
436 sTabSettings='Tab Settings';
437 sUnknownDialog='Unknown dialog requested!';
438 sUntitled='Untitled';
439 sWordWrapNotPossible='Wordwrap on: Wordwrap not possible in current margins with continuous line.';
440 sWordWrapOff='You must turn on wordwrap before you can reformat.';
441
442 slCaseSensitive='~C~ase sensitive';
443 slCurrentLine='~C~urrent line';
444 slEntireDocument='~E~ntire document';
445 slLineNumber='~L~ine number';
446 slNewText='~N~ew text';
447 slPromptOnReplace='~P~rompt on replace';
448 slReplace='~R~eplace';
449 slReplaceAll='~R~eplace all';
450 slTextToFind='~T~ext to find';
451 slWholeWordsOnly='~W~hole words only';
452
453
454 CONST
455 { Update flag constants. }
456 ufUpdate = $01;
457 ufLine = $02;
458 ufView = $04;
459 ufStats = $05;
460
461 { SelectMode constants. }
462 smExtend = $01;
463 smDouble = $02;
464
465 sfSearchFailed = NotFoundValue;
466
467 { Arrays that hold all the command keys and options. }
468 FirstKeys : array[0..46 * 2] of Word = (46, Ord (^A), cmWordLeft,
469 Ord (^B), cmReformPara,
470 Ord (^C), cmPageDown,
471 Ord (^D), cmCharRight,
472 Ord (^E), cmLineUp,
473 Ord (^F), cmWordRight,
474 Ord (^G), cmDelChar,
475 Ord (^H), cmBackSpace,
476 Ord (^I), cmTabKey,
477 Ord (^J), $FF04,
478 Ord (^K), $FF02,
479 Ord (^L), cmSearchAgain,
480 Ord (^M), cmNewLine,
481 Ord (^N), cmInsertLine,
482 Ord (^O), $FF03,
483 Ord (^Q), $FF01,
484 Ord (^R), cmPageUp,
485 Ord (^S), cmCharLeft,
486 Ord (^T), cmDelWord,
487 Ord (^U), cmUndo,
488 Ord (^V), cmInsMode,
489 Ord (^W), cmScrollUp,
490 Ord (^X), cmLineDown,
491 Ord (^Y), cmDelLine,
492 Ord (^Z), cmScrollDown,
493 kbLeft, cmCharLeft,
494 kbRight, cmCharRight,
495 kbCtrlLeft, cmWordLeft,
496 kbCtrlRight, cmWordRight,
497 kbHome, cmLineStart,
498 kbEnd, cmLineEnd,
499 kbCtrlHome, cmHomePage,
500 kbCtrlEnd, cmEndPage,
501 kbUp, cmLineUp,
502 kbDown, cmLineDown,
503 kbPgUp, cmPageUp,
504 kbPgDn, cmPageDown,
505 kbCtrlPgUp, cmTextStart,
506 kbCtrlPgDn, cmTextEnd,
507 kbIns, cmInsMode,
508 kbDel, cmDelChar,
509 kbCtrlBack, cmDelStart,
510 kbShiftIns, cmPaste,
511 kbShiftDel, cmCut,
512 kbCtrlIns, cmCopy,
513 kbCtrlDel, cmClear);
514
515 { SCRLUP - Stop. } { Added ^W to scroll screen up. }
516 { SCRLDN - Stop. } { Added ^Z to scroll screen down. }
517 { REFORM - Stop. } { Added ^B for paragraph reformatting. }
518 { PRETAB - Stop. } { Added ^I for preset tabbing. }
519 { JLINE - Stop. } { Added ^J to jump to a line number. }
520 { INSLIN - Stop. } { Added ^N to insert line at cursor. }
521 { INDENT - Stop. } { Removed ^O and put it into ^QI. }
522 { HOMEND - Stop. } { Added kbCtrlHome and kbCtrlEnd pages. }
523 { CTRLBK - Stop. } { Added kbCtrlBack same as ^QH. }
524
525 QuickKeys : array[0..21 * 2] of Word = (21, Ord ('0'), cmJumpMark0,
526 Ord ('1'), cmJumpMark1,
527 Ord ('2'), cmJumpMark2,
528 Ord ('3'), cmJumpMark3,
529 Ord ('4'), cmJumpMark4,
530 Ord ('5'), cmJumpMark5,
531 Ord ('6'), cmJumpMark6,
532 Ord ('7'), cmJumpMark7,
533 Ord ('8'), cmJumpMark8,
534 Ord ('9'), cmJumpMark9,
535 Ord ('A'), cmReplace,
536 Ord ('C'), cmTextEnd,
537 Ord ('D'), cmLineEnd,
538 Ord ('F'), cmFind,
539 Ord ('H'), cmDelStart,
540 Ord ('I'), cmIndentMode,
541 Ord ('L'), cmUndo,
542 Ord ('R'), cmTextStart,
543 Ord ('S'), cmLineStart,
544 Ord ('U'), cmReformDoc,
545 Ord ('Y'), cmDelEnd);
546
547 { UNDO - Stop. } { Added IDE undo feature of ^QL. }
548 { REFDOC - Stop. } { Added document reformat feature if ^QU pressed. }
549 { MARK - Stop. } { Added cmJumpMark# to allow place marking. }
550 { INDENT - Stop. } { Moved IndentMode here from Firstkeys. }
551
552 BlockKeys : array[0..20 * 2] of Word = (20, Ord ('0'), cmSetMark0,
553 Ord ('1'), cmSetMark1,
554 Ord ('2'), cmSetMark2,
555 Ord ('3'), cmSetMark3,
556 Ord ('4'), cmSetMark4,
557 Ord ('5'), cmSetMark5,
558 Ord ('6'), cmSetMark6,
559 Ord ('7'), cmSetMark7,
560 Ord ('8'), cmSetMark8,
561 Ord ('9'), cmSetMark9,
562 Ord ('B'), cmStartSelect,
563 Ord ('C'), cmPaste,
564 Ord ('D'), cmSave,
565 Ord ('F'), cmSaveAs,
566 Ord ('H'), cmHideSelect,
567 Ord ('K'), cmCopy,
568 Ord ('S'), cmSave,
569 Ord ('T'), cmSelectWord,
570 Ord ('Y'), cmCut,
571 Ord ('X'), cmSaveDone);
572
573 { SELWRD - Stop. } { Added ^KT to select word only. }
574 { SAVE - Stop. } { Added ^KD, ^KF, ^KS, ^KX key commands. }
575 { MARK - Stop. } { Added cmSetMark# to allow place marking. }
576
577 FormatKeys : array[0..5 * 2] of Word = (5, Ord ('C'), cmCenterText,
578 Ord ('T'), cmCenterText,
579 Ord ('I'), cmSetTabs,
580 Ord ('R'), cmRightMargin,
581 Ord ('W'), cmWordWrap);
582
583 { WRAP - Stop. } { Added Wordwrap feature if ^OW pressed. }
584 { RMSET - Stop. } { Added set right margin feature if ^OR pressed. }
585 { PRETAB - Stop. } { Added preset tab feature if ^OI pressed. }
586 { CENTER - Stop. } { Added center text option ^OC for a line. }
587
588 JumpKeys : array[0..1 * 2] of Word = (1, Ord ('L'), cmJumpLine);
589
590 { JLINE - Stop. } { Added jump to line number feature if ^JL pressed. }
591
592 KeyMap : array[0..4] of Pointer = (@FirstKeys,
593 @QuickKeys,
594 @BlockKeys,
595 @FormatKeys,
596 @JumpKeys);
597
598 { WRAP - Stop. } { Added @FormatKeys for new ^O? keys. }
599 { PRETAB - Stop. } { Added @FormatKeys for new ^O? keys. }
600 { JLINE - Stop. } { Added @JumpKeys for new ^J? keys. }
601 { CENTER - Stop. } { Added @FormatKeys for new ^O? keys. }
602
603
604 {****************************************************************************
605 Dialogs
606 ****************************************************************************}
607
DefEditorDialognull608 function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word;
609 begin
610 DefEditorDialog := cmCancel;
611 end; { DefEditorDialog }
612
613
CreateFindDialognull614 function CreateFindDialog: PDialog;
615 var
616 D: PDialog;
617 Control: PView;
618 R: TRect;
619 begin
620 R.Assign(0, 0, 38, 12);
621 D := New(PDialog, Init(R,sFind));
622 with D^ do
623 begin
624 Options := Options or ofCentered;
625
626 R.Assign(3, 3, 32, 4);
627 Control := New(PInputLine, Init(R, 80));
628 Control^.HelpCtx := hcDFindText;
629 Insert(Control);
630 R.Assign(2, 2, 15, 3);
631 Insert(New(PLabel, Init(R, slTextToFind, Control)));
632 R.Assign(32, 3, 35, 4);
633 Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
634
635 R.Assign(3, 5, 35, 7);
636 Control := New(PCheckBoxes, Init(R,
637 NewSItem (slCaseSensitive,
638 NewSItem (slWholeWordsOnly,nil))));
639 Control^.HelpCtx := hcCCaseSensitive;
640 Insert(Control);
641
642 R.Assign(14, 9, 24, 11);
643 Control := New (PButton, Init(R,slOK,cmOk,bfDefault));
644 Control^.HelpCtx := hcDOk;
645 Insert (Control);
646
647 Inc(R.A.X, 12); Inc(R.B.X, 12);
648 Control := New (PButton, Init(R,slCancel,cmCancel, bfNormal));
649 Control^.HelpCtx := hcDCancel;
650 Insert (Control);
651
652 SelectNext(False);
653 end;
654 CreateFindDialog := D;
655 end;
656
657
CreateReplaceDialognull658 function CreateReplaceDialog: PDialog;
659 var
660 D: PDialog;
661 Control: PView;
662 R: TRect;
663 begin
664 R.Assign(0, 0, 40, 16);
665 D := New(PDialog, Init(R,slReplace));
666 with D^ do
667 begin
668 Options := Options or ofCentered;
669
670 R.Assign(3, 3, 34, 4);
671 Control := New(PInputLine, Init(R, 80));
672 Control^.HelpCtx := hcDFindText;
673 Insert(Control);
674 R.Assign(2, 2, 15, 3);
675 Insert(New(PLabel, Init(R,slTextToFind, Control)));
676 R.Assign(34, 3, 37, 4);
677 Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
678
679 R.Assign(3, 6, 34, 7);
680 Control := New(PInputLine, Init(R, 80));
681 Control^.HelpCtx := hcDReplaceText;
682 Insert(Control);
683 R.Assign(2, 5, 12, 6);
684 Insert(New(PLabel, Init(R,slNewText, Control)));
685 R.Assign(34, 6, 37, 7);
686 Insert(New(PHistory, Init(R, PInputLine(Control), 11)));
687
688 R.Assign(3, 8, 37, 12);
689 Control := New (Dialogs.PCheckBoxes, Init (R,
690 NewSItem (slCasesensitive,
691 NewSItem (slWholewordsonly,
692 NewSItem (slPromptonreplace,
693 NewSItem (slReplaceall, nil))))));
694 Control^.HelpCtx := hcCCaseSensitive;
695 Insert (Control);
696
697 R.Assign (8, 13, 18, 15);
698 Control := New (PButton, Init (R,slOK, cmOk, bfDefault));
699 Control^.HelpCtx := hcDOk;
700 Insert (Control);
701
702 R.Assign (22, 13, 32, 15);
703 Control := New (PButton, Init (R,slCancel, cmCancel, bfNormal));
704 Control^.HelpCtx := hcDCancel;
705 Insert (Control);
706
707 SelectNext(False);
708 end;
709 CreateReplaceDialog := D;
710 end;
711
712
JumpLineDialognull713 function JumpLineDialog : PDialog;
714 VAR
715 D : PDialog;
716 R : TRect;
717 Control: PView;
718 Begin
719 R.Assign (0, 0, 26, 8);
720 D := New(PDialog, Init(R,sJumpTo));
721 with D^ do
722 begin
723 Options := Options or ofCentered;
724
725 R.Assign (3, 2, 15, 3);
726 Control := New (Dialogs.PStaticText, Init (R,slLineNumber));
727 Insert (Control);
728
729 R.Assign (15, 2, 21, 3);
730 Control := New (Dialogs.PInputLine, Init (R, 4));
731 Control^.HelpCtx := hcDLineNumber;
732 Insert (Control);
733
734 R.Assign (21, 2, 24, 3);
735 Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 12)));
736
737 R.Assign (2, 5, 12, 7);
738 Control := New (Dialogs.PButton, Init (R, slOK, cmOK, Dialogs.bfDefault));
739 Control^.HelpCtx := hcDOk;
740 Insert (Control);
741
742 R.Assign (14, 5, 24, 7);
743 Control := New (Dialogs.PButton, Init (R, slCancel, cmCancel, Dialogs.bfNormal));
744 Control^.HelpCtx := hcDCancel;
745 Insert (Control);
746
747 SelectNext (False);
748 end;
749 JumpLineDialog := D;
750 end; { JumpLineDialog }
751
752
ReformDocDialognull753 function ReformDocDialog : Dialogs.PDialog;
754 { This is a local function that brings up a dialog box }
755 { that asks where to start reformatting the document. }
756 VAR
757 R : TRect;
758 D : Dialogs.PDialog;
759 Control : PView;
760 Begin
761 R.Assign (0, 0, 32, 11);
762 D := New (Dialogs.PDialog, Init (R, sReformatDocument));
763 with D^ do
764 begin
765 Options := Options or ofCentered;
766
767 R.Assign (2, 2, 30, 3);
768 Control := New (Dialogs.PStaticText, Init (R, sSelectWhereToBegin));
769 Insert (Control);
770
771 R.Assign (3, 3, 29, 4);
772 Control := New (Dialogs.PStaticText, Init (R, sReformattingTheDocument));
773 Insert (Control);
774
775 R.Assign (50, 5, 68, 6);
776 Control := New (Dialogs.PLabel, Init (R, sReformatDocument, Control));
777 Insert (Control);
778
779 R.Assign (5, 5, 26, 7);
780 Control := New (Dialogs.PRadioButtons, Init (R,
781 NewSItem (slCurrentLine,
782 NewSItem (slEntireDocument, Nil))));
783 Control^.HelpCtx := hcDReformDoc;
784 Insert (Control);
785
786 R.Assign (4, 8, 14, 10);
787 Control := New (Dialogs.PButton, Init (R, slOK, cmOK, Dialogs.bfDefault));
788 Control^.HelpCtx := hcDOk;
789 Insert (Control);
790
791 R.Assign (17, 8, 27, 10);
792 Control := New (Dialogs.PButton, Init (R, slCancel, cmCancel, Dialogs.bfNormal));
793 Control^.HelpCtx := hcDCancel;
794 Insert (Control);
795
796 SelectNext (False);
797 end;
798 ReformDocDialog := D;
799 end; { ReformDocDialog }
800
801
RightMarginDialognull802 function RightMarginDialog : Dialogs.PDialog;
803 { This is a local function that brings up a dialog box }
804 { that allows the user to change the Right_Margin. }
805 VAR
806 R : TRect;
807 D : PDialog;
808 Control : PView;
809 Begin
810 R.Assign (0, 0, 26, 8);
811 D := New (Dialogs.PDialog, Init (R, sRightMargin));
812 with D^ do
813 begin
814 Options := Options or ofCentered;
815
816 R.Assign (5, 2, 13, 3);
817 Control := New (Dialogs.PStaticText, Init (R, sSetting));
818 Insert (Control);
819
820 R.Assign (13, 2, 18, 3);
821 Control := New (Dialogs.PInputLine, Init (R, 3));
822 Control^.HelpCtx := hcDRightMargin;
823 Insert (Control);
824
825 R.Assign (18, 2, 21, 3);
826 Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 13)));
827
828 R.Assign (2, 5, 12, 7);
829 Control := New (Dialogs.PButton, Init (R, slOK, cmOK, Dialogs.bfDefault));
830 Control^.HelpCtx := hcDOk;
831 Insert (Control);
832
833 R.Assign (14, 5, 24, 7);
834 Control := New (Dialogs.PButton, Init (R, slCancel, cmCancel, Dialogs.bfNormal));
835 Control^.HelpCtx := hcDCancel;
836 Insert (Control);
837
838 SelectNext (False);
839 end;
840 RightMarginDialog := D;
841 end; { RightMarginDialog; }
842
843
TabStopDialognull844 function TabStopDialog : Dialogs.PDialog;
845 { This is a local function that brings up a dialog box }
846 { that allows the user to set their own tab stops. }
847 VAR
848 Index : Sw_Integer; { Local Indexing variable. }
849 R : TRect;
850 D : PDialog;
851 Control : PView;
852 Tab_Stop : String[2]; { Local string to print tab column number. }
853 Begin
854 R.Assign (0, 0, 80, 8);
855 D := New (Dialogs.PDialog, Init (R, sTabSettings));
856 with D^ do
857 begin
858 Options := Options or ofCentered;
859
860 R.Assign (2, 2, 77, 3);
861 Control := New (Dialogs.PStaticText, Init (R,
862 ' ....|....|....|....|....|....|....|....|....|....|....|....|....|....|....'));
863 Insert (Control);
864
865 for Index := 1 to 7 do
866 begin
867 R.Assign (Index * 10 + 1, 1, Index * 10 + 3, 2);
868 Str (Index * 10, Tab_Stop);
869 Control := New (Dialogs.PStaticText, Init (R, Tab_Stop));
870 Insert (Control);
871 end;
872
873 R.Assign (2, 3, 78, 4);
874 Control := New (Dialogs.PInputLine, Init (R, 74));
875 Control^.HelpCtx := hcDTabStops;
876 Insert (Control);
877
878 R.Assign (38, 5, 41, 6);
879 Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 14)));
880
881 R.Assign (27, 5, 37, 7);
882 Control := New (Dialogs.PButton, Init (R, slOK, cmOK, Dialogs.bfDefault));
883 Control^.HelpCtx := hcDOk;
884 Insert (Control);
885
886 R.Assign (42, 5, 52, 7);
887 Control := New (Dialogs.PButton, Init (R, slCancel, cmCancel, Dialogs.bfNormal));
888 Control^.HelpCtx := hcDCancel;
889 Insert (Control);
890 SelectNext (False);
891 end;
892 TabStopDialog := D;
893 end { TabStopDialog };
894
895
StdEditorDialognull896 function StdEditorDialog(Dialog: Integer; Info: Pointer): Word;
897 var
898 R: TRect;
899 T: TPoint;
900 begin
901 case Dialog of
902 edOutOfMemory:
903 StdEditorDialog := MessageBox(sOutOfMemory, nil, mfError + mfOkButton);
904 edReadError:
905 StdEditorDialog := MessageBox(sFileReadError, @Info, mfError + mfOkButton);
906 edWriteError:
907 StdEditorDialog := MessageBox(sFileWriteError, @Info, mfError + mfOkButton);
908 edCreateError:
909 StdEditorDialog := MessageBox(sFileCreateError, @Info, mfError + mfOkButton);
910 edSaveModify:
911 StdEditorDialog := MessageBox(sModified, @Info, mfInformation + mfYesNoCancel);
912 edSaveUntitled:
913 StdEditorDialog := MessageBox(sFileUntitled, nil, mfInformation + mfYesNoCancel);
914 edSaveAs:
915 StdEditorDialog := Application^.ExecuteDialog(New(PFileDialog, Init('*.*',
916 slSaveFileAs, slName, fdOkButton, 101)), Info);
917 edFind:
918 StdEditorDialog := Application^.ExecuteDialog(CreateFindDialog, Info);
919 edSearchFailed:
920 StdEditorDialog := MessageBox(sSearchStringNotFound, nil, mfError + mfOkButton);
921 edReplace:
922 StdEditorDialog := Application^.ExecuteDialog(CreateReplaceDialog, Info);
923 edReplacePrompt:
924 begin
925 { Avoid placing the dialog on the same line as the cursor }
926 R.Assign(0, 1, 40, 8);
927 R.Move((Desktop^.Size.X - R.B.X) div 2, 0);
928 Desktop^.MakeGlobal(R.B, T);
929 Inc(T.Y);
930 if PPoint(Info)^.Y <= T.Y then
931 R.Move(0, Desktop^.Size.Y - R.B.Y - 2);
932 StdEditorDialog := MessageBoxRect(R, sReplaceThisOccurence,
933 nil, mfYesNoCancel + mfInformation);
934 end;
935 edJumpToLine:
936 StdEditorDialog := Application^.ExecuteDialog(JumpLineDialog, Info);
937 edSetTabStops:
938 StdEditorDialog := Application^.ExecuteDialog(TabStopDialog, Info);
939 edPasteNotPossible:
940 StdEditorDialog := MessageBox (sPasteNotPossible, nil, mfError + mfOkButton);
941 edReformatDocument:
942 StdEditorDialog := Application^.ExecuteDialog(ReformDocDialog, Info);
943 edReformatNotAllowed:
944 StdEditorDialog := MessageBox (sWordWrapOff, nil, mfError + mfOkButton);
945 edReformNotPossible:
946 StdEditorDialog := MessageBox (sReformatNotPossible, nil, mfError + mfOkButton);
947 edReplaceNotPossible:
948 StdEditorDialog := MessageBox (sReplaceNotPossible, nil, mfError + mfOkButton);
949 edRightMargin:
950 StdEditorDialog := Application^.ExecuteDialog(RightMarginDialog, Info);
951 edWrapNotPossible:
952 StdEditorDialog := MessageBox (sWordWrapNotPossible, nil, mfError + mfOKButton);
953 else
954 StdEditorDialog := MessageBox (sUnknownDialog, nil, mfError + mfOkButton);
955 end;
956 end;
957
958
959 {****************************************************************************
960 Helpers
961 ****************************************************************************}
962
CountLinesnull963 function CountLines(var Buf; Count: sw_Word): sw_Integer;
964 var
965 p : pchar;
966 lines : sw_word;
967 begin
968 p:=pchar(@buf);
969 lines:=0;
970 while (count>0) do
971 begin
972 if p^ in [#10,#13] then
973 begin
974 inc(lines);
975 if ord((p+1)^)+ord(p^)=23 then
976 begin
977 inc(p);
978 dec(count);
979 if count=0 then
980 break;
981 end;
982 end;
983 inc(p);
984 dec(count);
985 end;
986 CountLines:=Lines;
987 end;
988
989
990 procedure GetLimits(var Buf; Count: sw_Word;var lim:objects.TPoint);
991 { Get the limits needed for Buf, its an extended version of countlines (lim.y),
992 which also gets the maximum line length in lim.x }
993 var
994 p : pchar;
995 len : sw_word;
996 begin
997 lim.x:=0;
998 lim.y:=0;
999 len:=0;
1000 p:=pchar(@buf);
1001 while (count>0) do
1002 begin
1003 if p^ in [#10,#13] then
1004 begin
1005 if len>lim.x then
1006 lim.x:=len;
1007 inc(lim.y);
1008 if ord((p+1)^)+ord(p^)=23 then
1009 begin
1010 inc(p);
1011 dec(count);
1012 end;
1013 len:=0;
1014 end
1015 else
1016 inc(len);
1017 inc(p);
1018 dec(count);
1019 end;
1020 end;
1021
1022
ScanKeyMapnull1023 function ScanKeyMap(KeyMap: Pointer; KeyCode: Word): Word;
1024 var
1025 p : pword;
1026 count : sw_word;
1027 begin
1028 p:=keymap;
1029 count:=p^;
1030 inc(p);
1031 while (count>0) do
1032 begin
1033 if (lo(p^)=lo(keycode)) and
1034 ((hi(p^)=0) or (hi(p^)=hi(keycode))) then
1035 begin
1036 inc(p);
1037 scankeymap:=p^;
1038 exit;
1039 end;
1040 inc(p,2);
1041 dec(count);
1042 end;
1043 scankeymap:=0;
1044 end;
1045
1046
1047 Type
1048 Btable = Array[0..255] of Byte;
1049 Procedure BMMakeTable(const s:string; Var t : Btable);
1050 { Makes a Boyer-Moore search table. s = the search String t = the table }
1051 Var
1052 x : sw_integer;
1053 begin
1054 FillChar(t,sizeof(t),length(s));
1055 For x := length(s) downto 1 do
1056 if (t[ord(s[x])] = length(s)) then
1057 t[ord(s[x])] := length(s) - x;
1058 end;
1059
1060
Scannull1061 function Scan(var Block; Size: Sw_Word;const Str: String): Sw_Word;
1062 Var
1063 buffer : Array[0..MaxBufLength-1] of Byte Absolute block;
1064 s2 : String;
1065 len,
1066 numb : Sw_Word;
1067 found : Boolean;
1068 bt : Btable;
1069 begin
1070 BMMakeTable(str,bt);
1071 len:=length(str);
1072 s2[0]:=chr(len); { sets the length to that of the search String }
1073 found:=False;
1074 numb:=pred(len);
1075 While (not found) and (numb<(size-len)) do
1076 begin
1077 { partial match }
1078 if buffer[numb] = ord(str[len]) then
1079 begin
1080 { less partial! }
1081 if buffer[numb-pred(len)] = ord(str[1]) then
1082 begin
1083 move(buffer[numb-pred(len)],s2[1],len);
1084 if (str=s2) then
1085 begin
1086 found:=true;
1087 break;
1088 end;
1089 end;
1090 inc(numb);
1091 end
1092 else
1093 inc(numb,Bt[buffer[numb]]);
1094 end;
1095 if not found then
1096 Scan := NotFoundValue
1097 else
1098 Scan := numb - pred(len);
1099 end;
1100
1101
IScannull1102 function IScan(var Block; Size: Sw_Word;const Str: String): Sw_Word;
1103 Var
1104 buffer : Array[0..MaxBufLength-1] of Char Absolute block;
1105 s : String;
1106 len,
1107 numb,
1108 x : Sw_Word;
1109 found : Boolean;
1110 bt : Btable;
1111 p : pchar;
1112 c : char;
1113 begin
1114 len:=length(str);
1115 if (len=0) or (len>size) then
1116 begin
1117 IScan := NotFoundValue;
1118 exit;
1119 end;
1120 { create uppercased string }
1121 s[0]:=chr(len);
1122 for x:=1 to len do
1123 begin
1124 if str[x] in ['a'..'z'] then
1125 s[x]:=chr(ord(str[x])-32)
1126 else
1127 s[x]:=str[x];
1128 end;
1129 BMMakeTable(s,bt);
1130 found:=False;
1131 numb:=pred(len);
1132 While (not found) and (numb<(size-len)) do
1133 begin
1134 { partial match }
1135 c:=buffer[numb];
1136 if c in ['a'..'z'] then
1137 c:=chr(ord(c)-32);
1138 if (c=s[len]) then
1139 begin
1140 { less partial! }
1141 p:=@buffer[numb-pred(len)];
1142 x:=1;
1143 while (x<=len) do
1144 begin
1145 if not(((p^ in ['a'..'z']) and (chr(ord(p^)-32)=s[x])) or
1146 (p^=s[x])) then
1147 break;
1148 inc(p);
1149 inc(x);
1150 end;
1151 if (x>len) then
1152 begin
1153 found:=true;
1154 break;
1155 end;
1156 inc(numb);
1157 end
1158 else
1159 inc(numb,Bt[ord(c)]);
1160 end;
1161 if not found then
1162 IScan := NotFoundValue
1163 else
1164 IScan := numb - pred(len);
1165 end;
1166
1167
1168 {****************************************************************************
1169 TIndicator
1170 ****************************************************************************}
1171
1172 constructor TIndicator.Init (var Bounds : TRect);
1173 begin
1174 Inherited Init (Bounds);
1175 GrowMode := gfGrowLoY + gfGrowHiY;
1176 end; { TIndicator.Init }
1177
1178
1179 procedure TIndicator.Draw;
1180 VAR
1181 Color : Byte;
1182 Frame : Char;
1183 L : array[0..1] of PtrInt;
1184 S : String[15];
1185 B : TDrawBuffer;
1186 begin
1187 if State and sfDragging = 0 then
1188 begin
1189 Color := GetColor (1);
1190 Frame := #205;
1191 end
1192 else
1193 begin
1194 Color := GetColor (2);
1195 Frame := #196;
1196 end;
1197 MoveChar (B, Frame, Color, Size.X);
1198 { If the text has been modified, put an 'M' in the TIndicator display. }
1199 if Modified then
1200 WordRec (B[1]).Lo := 77;
1201 { If WordWrap is active put a 'W' in the TIndicator display. }
1202 if WordWrap then
1203 WordRec (B[2]).Lo := 87
1204 else
1205 WordRec (B[2]).Lo := Byte (Frame);
1206 { If AutoIndent is active put an 'I' in TIndicator display. }
1207 if AutoIndent then
1208 WordRec (B[0]).Lo := 73
1209 else
1210 WordRec (B[0]).Lo := Byte (Frame);
1211 L[0] := Location.Y + 1;
1212 L[1] := Location.X + 1;
1213 FormatStr (S, ' %d:%d ', L);
1214 MoveStr (B[9 - Pos (':', S)], S, Color); { Changed original 8 to 9. }
1215 WriteBuf (0, 0, Size.X, 1, B);
1216 end; { TIndicator.Draw }
1217
1218
GetPalettenull1219 function TIndicator.GetPalette : PPalette;
1220 const
1221 P : string[Length (CIndicator)] = CIndicator;
1222 begin
1223 GetPalette := PPalette(@P);
1224 end; { TIndicator.GetPalette }
1225
1226
1227 procedure TIndicator.SetState (AState : Word; Enable : Boolean);
1228 begin
1229 Inherited SetState (AState, Enable);
1230 if AState = sfDragging then
1231 DrawView;
1232 end; { TIndicator.SetState }
1233
1234
1235 procedure TIndicator.SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean;
1236 IsModified : Boolean;
1237 IsWordWrap : Boolean);
1238 begin
1239 if (Location.X<>ALocation.X) or
1240 (Location.Y<>ALocation.Y) or
1241 (AutoIndent <> IsAutoIndent) or
1242 (Modified <> IsModified) or
1243 (WordWrap <> IsWordWrap) then
1244 begin
1245 Location := ALocation;
1246 AutoIndent := IsAutoIndent; { Added provisions to show AutoIndent. }
1247 Modified := IsModified;
1248 WordWrap := IsWordWrap; { Added provisions to show WordWrap. }
1249 DrawView;
1250 end;
1251 end; { TIndicator.SetValue }
1252
1253
1254 {****************************************************************************
1255 TLineInfo
1256 ****************************************************************************}
1257
1258 constructor TLineInfo.Init;
1259 begin
1260 MaxPos:=0;
1261 Grow(1);
1262 end;
1263
1264
1265 destructor TLineInfo.Done;
1266 begin
1267 FreeMem(Info,MaxPos*sizeof(TLineInfoRec));
1268 Info := nil;
1269 end;
1270
1271
1272 procedure TLineInfo.Grow(pos:Sw_word);
1273 var
1274 NewSize : Sw_word;
1275 P : pointer;
1276 begin
1277 NewSize:=(Pos+LineInfoGrow-(Pos mod LineInfoGrow));
1278 GetMem(P,NewSize*sizeof(TLineInfoRec));
1279 FillChar(P^,NewSize*sizeof(TLineInfoRec),0);
1280 Move(Info^,P^,MaxPos*sizeof(TLineInfoRec));
1281 Freemem(Info,MaxPos*sizeof(TLineInfoRec));
1282 Info:=P;
1283 end;
1284
1285
1286 procedure TLineInfo.SetLen(pos,val:Sw_Word);
1287 begin
1288 if pos>=MaxPos then
1289 Grow(Pos);
1290 Info^[Pos].Len:=val
1291 end;
1292
1293
1294 procedure TLineInfo.SetAttr(pos,val:Sw_Word);
1295 begin
1296 if pos>=MaxPos then
1297 Grow(Pos);
1298 Info^[Pos].Attr:=val
1299 end;
1300
1301
GetLennull1302 function TLineInfo.GetLen(pos:Sw_Word):Sw_Word;
1303 begin
1304 GetLen:=Info^[Pos].Len;
1305 end;
1306
1307
TLineInfo.GetAttrnull1308 function TLineInfo.GetAttr(pos:Sw_Word):Sw_Word;
1309 begin
1310 GetAttr:=Info^[Pos].Attr;
1311 end;
1312
1313
1314
1315 {****************************************************************************
1316 TEditor
1317 ****************************************************************************}
1318
1319 constructor TEditor.Init (var Bounds : TRect;
1320 AHScrollBar, AVScrollBar : PScrollBar;
1321 AIndicator : PIndicator; ABufSize : Sw_Word);
1322 var
1323 Element : Byte; { Place_Marker array element to initialize array with. }
1324 begin
1325 Inherited Init (Bounds);
1326 GrowMode := gfGrowHiX + gfGrowHiY;
1327 Options := Options or ofSelectable;
1328 Flags := EditorFlags;
1329 EventMask := evMouseDown + evKeyDown + evCommand + evBroadcast;
1330 ShowCursor;
1331
1332 HScrollBar := AHScrollBar;
1333 VScrollBar := AVScrollBar;
1334
1335 Indicator := AIndicator;
1336 BufSize := ABufSize;
1337 CanUndo := True;
1338 InitBuffer;
1339
1340 if assigned(Buffer) then
1341 IsValid := True
1342 else
1343 begin
1344 EditorDialog (edOutOfMemory, nil);
1345 BufSize := 0;
1346 end;
1347
1348 SetBufLen (0);
1349
1350 for Element := 1 to 10 do
1351 Place_Marker[Element] := 0;
1352
1353 Element := 1;
1354 while Element <= 70 do
1355 begin
1356 if Element mod 5 = 0 then
1357 Insert ('x', Tab_Settings, Element)
1358 else
1359 Insert (#32, Tab_Settings, Element);
1360 Inc (Element);
1361 end;
1362 { Default Right_Margin value. Change it if you want another. }
1363 Right_Margin := 76;
1364 TabSize:=8;
1365 end; { TEditor.Init }
1366
1367
1368 constructor TEditor.Load (var S : Objects.TStream);
1369 begin
1370 Inherited Load (S);
1371 GetPeerViewPtr (S, HScrollBar);
1372 GetPeerViewPtr (S, VScrollBar);
1373 GetPeerViewPtr (S, Indicator);
1374 S.Read (BufSize, SizeOf (BufSize));
1375 S.Read (CanUndo, SizeOf (CanUndo));
1376 S.Read (AutoIndent, SizeOf (AutoIndent));
1377 S.Read (Line_Number, SizeOf (Line_Number));
1378 S.Read (Place_Marker, SizeOf (Place_Marker));
1379 S.Read (Right_Margin, SizeOf (Right_Margin));
1380 S.Read (Tab_Settings, SizeOf (Tab_Settings));
1381 S.Read (Word_Wrap, SizeOf (Word_Wrap));
1382 InitBuffer;
1383 if Assigned(Buffer) then
1384 IsValid := True
1385 else
1386 begin
1387 EditorDialog (edOutOfMemory, nil);
1388 BufSize := 0;
1389 end;
1390 Lock;
1391 SetBufLen (0);
1392 end; { TEditor.Load }
1393
1394
1395 destructor TEditor.Done;
1396 begin
1397 DoneBuffer;
1398 Inherited Done;
1399 end; { TEditor.Done }
1400
1401
TEditor.BufCharnull1402 function TEditor.BufChar(P: Sw_Word): Char;
1403 begin
1404 if P>=CurPtr then
1405 inc(P,Gaplen);
1406 BufChar:=Buffer^[P];
1407 end;
1408
1409
TEditor.BufPtrnull1410 function TEditor.BufPtr(P: Sw_Word): Sw_Word;
1411 begin
1412 if P>=CurPtr then
1413 BufPtr:=P+GapLen
1414 else
1415 BufPtr:=P;
1416 end;
1417
1418
1419 procedure TEditor.Center_Text (Select_Mode : Byte);
1420 { This procedure will center the current line of text. }
1421 { Centering is based on the current Right_Margin. }
1422 { If the Line_Length exceeds the Right_Margin, or the }
1423 { line is just a blank line, we exit and do nothing. }
1424 VAR
1425 Spaces : array [1..80] of Char; { Array to hold spaces we'll insert. }
1426 Index : Byte; { Index into Spaces array. }
1427 Line_Length : Sw_Integer; { Holds the length of the line. }
1428 E,S : Sw_Word; { End of the current line. }
1429 begin
1430 E := LineEnd (CurPtr);
1431 S := LineStart (CurPtr);
1432 { If the line is blank (only a CR/LF on it) then do noting. }
1433 if E = S then
1434 Exit;
1435 { Set CurPtr to start of line. Check if line begins with a space. }
1436 { We must strip out any spaces from the beginning, or end of lines. }
1437 { If line does not start with space, make sure line length does not }
1438 { exceed the Right_Margin. If it does, then do nothing. }
1439 SetCurPtr (S, Select_Mode);
1440 Remove_EOL_Spaces (Select_Mode);
1441 if Buffer^[CurPtr] = #32 then
1442 begin
1443 { If the next word is greater than the end of line then do nothing. }
1444 { If the line length is greater than Right_Margin then do nothing. }
1445 { Otherwise, delete all spaces at the start of line. }
1446 { Then reset end of line and put CurPtr at start of modified line. }
1447 E := LineEnd (CurPtr);
1448 if NextWord (CurPtr) > E then
1449 Exit;
1450 if E - NextWord (CurPtr) > Right_Margin then
1451 Exit;
1452 DeleteRange (CurPtr, NextWord (CurPtr), True);
1453 E := LineEnd (CurPtr);
1454 SetCurPtr (LineStart (CurPtr), Select_Mode);
1455 end
1456 else
1457 if E - CurPtr > Right_Margin then
1458 Exit;
1459 { Now we determine the real length of the line. }
1460 { Then we subtract the Line_Length from Right_Margin. }
1461 { Dividing the result by two tells us how many spaces }
1462 { must be inserted at start of line to center it. }
1463 { When we're all done, set the CurPtr to end of line. }
1464 Line_Length := E - CurPtr;
1465 for Index := 1 to ((Right_Margin - Line_Length) shr 1) do
1466 Spaces[Index] := #32;
1467 InsertText (@Spaces, Index, False);
1468 SetCurPtr (LineEnd (CurPtr), Select_Mode);
1469 end; { TEditor.Center_Text }
1470
1471
1472 procedure TEditor.ChangeBounds (var Bounds : TRect);
1473 begin
1474 SetBounds (Bounds);
1475 Delta.X := Max (0, Min (Delta.X, Limit.X - Size.X));
1476 Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y));
1477 Update (ufView);
1478 end; { TEditor.ChangeBounds }
1479
1480
CharPosnull1481 function TEditor.CharPos (P, Target : Sw_Word) : Sw_Integer;
1482 VAR
1483 Pos : Sw_Integer;
1484 begin
1485 Pos := 0;
1486 while P < Target do
1487 begin
1488 if BufChar (P) = #9 then
1489 Pos := Pos or 7;
1490 Inc (Pos);
1491 Inc (P);
1492 end;
1493 CharPos := Pos;
1494 end; { TEditor.CharPos }
1495
1496
TEditor.CharPtrnull1497 function TEditor.CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word;
1498 VAR
1499 Pos : Sw_Integer;
1500 begin
1501 Pos := 0;
1502 while (Pos < Target) and (P < BufLen) and not(BufChar (P) in [#10,#13]) do
1503 begin
1504 if BufChar (P) = #9 then
1505 Pos := Pos or 7;
1506 Inc (Pos);
1507 Inc (P);
1508 end;
1509 if Pos > Target then
1510 Dec (P);
1511 CharPtr := P;
1512 end; { TEditor.CharPtr }
1513
1514
1515 procedure TEditor.Check_For_Word_Wrap (Select_Mode : Byte;
1516 Center_Cursor : Boolean);
1517 { This procedure checks if CurPos.X > Right_Margin. }
1518 { If it is, then we Do_Word_Wrap. Simple, eh? }
1519 begin
1520 if CurPos.X > Right_Margin then
1521 Do_Word_Wrap (Select_Mode, Center_Cursor);
1522 end; {Check_For_Word_Wrap}
1523
1524
ClipCopynull1525 function TEditor.ClipCopy : Boolean;
1526 begin
1527 ClipCopy := False;
1528 if Assigned(Clipboard) and (Clipboard <> @Self) then
1529 begin
1530 ClipCopy := Clipboard^.InsertFrom (@Self);
1531 Selecting := False;
1532 Update (ufUpdate);
1533 end;
1534 end; { TEditor.ClipCopy }
1535
1536
1537 procedure TEditor.ClipCut;
1538 begin
1539 if ClipCopy then
1540 begin
1541 Update_Place_Markers (0,
1542 Self.SelEnd - Self.SelStart,
1543 Self.SelStart,
1544 Self.SelEnd);
1545 DeleteSelect;
1546 end;
1547 end; { TEditor.ClipCut }
1548
1549
1550 procedure TEditor.ClipPaste;
1551 begin
1552 if Assigned(Clipboard) and (Clipboard <> @Self) then
1553 begin
1554 { Do not allow paste operations that will exceed }
1555 { the Right_Margin when Word_Wrap is active and }
1556 { cursor is at EOL. }
1557 if Word_Wrap and (CurPos.X > Right_Margin) then
1558 begin
1559 EditorDialog (edPasteNotPossible, nil);
1560 Exit;
1561 end;
1562 { The editor will not copy selected text if the CurPtr }
1563 { is not the same value as the SelStart. However, it }
1564 { does return an InsCount. This may, or may not, be a }
1565 { bug. We don't want to update the Place_Marker if }
1566 { there's no text copied. }
1567 if CurPtr = SelStart then
1568 Update_Place_Markers (Clipboard^.SelEnd - Clipboard^.SelStart,
1569 0,
1570 Clipboard^.SelStart,
1571 Clipboard^.SelEnd);
1572 InsertFrom (Clipboard);
1573 end;
1574 end; { TEditor.ClipPaste }
1575
1576
1577 procedure TEditor.ConvertEvent (var Event : Drivers.TEvent);
1578 VAR
1579 ShiftState : Byte;
1580 Key : Word;
1581 begin
1582 ShiftState:=GetShiftState;
1583 if Event.What = evKeyDown then
1584 begin
1585 if (ShiftState and $03 <> 0)
1586 and (Event.ScanCode >= $47)
1587 and (Event.ScanCode <= $51) then
1588 Event.CharCode := #0;
1589 Key := Event.KeyCode;
1590 if KeyState <> 0 then
1591 begin
1592 if (Lo (Key) >= $01) and (Lo (Key) <= $1A) then
1593 Inc (Key, $40);
1594 if (Lo (Key) >= $61) and (Lo (Key) <= $7A) then
1595 Dec (Key, $20);
1596 end;
1597 Key := ScanKeyMap (KeyMap[KeyState], Key);
1598 KeyState := 0;
1599 if Key <> 0 then
1600 if Hi (Key) = $FF then
1601 begin
1602 KeyState := Lo (Key);
1603 ClearEvent (Event);
1604 end
1605 else
1606 begin
1607 Event.What := evCommand;
1608 Event.Command := Key;
1609 end;
1610 end;
1611 end; { TEditor.ConvertEvent }
1612
1613
CursorVisiblenull1614 function TEditor.CursorVisible : Boolean;
1615 begin
1616 CursorVisible := (CurPos.Y >= Delta.Y) and (CurPos.Y < Delta.Y + Size.Y);
1617 end; { TEditor.CursorVisible }
1618
1619
1620 procedure TEditor.DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean);
1621 begin
1622 { This will update Place_Marker for all deletions. }
1623 { EXCEPT the Remove_EOL_Spaces deletion. }
1624 Update_Place_Markers (0, EndPtr - StartPtr, StartPtr, EndPtr);
1625 if HasSelection and DelSelect then
1626 DeleteSelect
1627 else
1628 begin
1629 SetSelect (CurPtr, EndPtr, True);
1630 DeleteSelect;
1631 SetSelect (StartPtr, CurPtr, False);
1632 DeleteSelect;
1633 end;
1634 end; { TEditor.DeleteRange }
1635
1636
1637 procedure TEditor.DeleteSelect;
1638 begin
1639 InsertText (nil, 0, False);
1640 end; { TEditor.DeleteSelect }
1641
1642
1643 procedure TEditor.DoneBuffer;
1644 begin
1645 ReAllocMem(Buffer, 0);
1646 end; { TEditor.DoneBuffer }
1647
1648
1649 procedure TEditor.DoSearchReplace;
1650 VAR
1651 I : Sw_Word;
1652 C : Objects.TPoint;
1653 begin
1654 repeat
1655 I := cmCancel;
1656 if not Search (FindStr, Flags) then
1657 begin
1658 if Flags and (efReplaceAll + efDoReplace) <> (efReplaceAll + efDoReplace) then
1659 EditorDialog (edSearchFailed, nil)
1660 end
1661 else
1662 if Flags and efDoReplace <> 0 then
1663 begin
1664 I := cmYes;
1665 if Flags and efPromptOnReplace <> 0 then
1666 begin
1667 MakeGlobal (Cursor, C);
1668 I := EditorDialog (edReplacePrompt, Pointer(@C));
1669 end;
1670 if I = cmYes then
1671 begin
1672 { If Word_Wrap is active and we are at EOL }
1673 { disallow replace by bringing up a dialog }
1674 { stating that replace is not possible. }
1675 if Word_Wrap and
1676 ((CurPos.X + (Length (ReplaceStr) - Length (FindStr))) > Right_Margin) then
1677 EditorDialog (edReplaceNotPossible, nil)
1678 else
1679 begin
1680 Lock;
1681 Search_Replace := True;
1682 if length (ReplaceStr) < length (FindStr) then
1683 Update_Place_Markers (0,
1684 Length (FindStr) - Length (ReplaceStr),
1685 CurPtr - Length (FindStr) + Length (ReplaceStr),
1686 CurPtr)
1687 else
1688 if length (ReplaceStr) > length (FindStr) then
1689 Update_Place_Markers (Length (ReplaceStr) - Length (FindStr),
1690 0,
1691 CurPtr,
1692 CurPtr + (Length (ReplaceStr) - Length (FindStr)));
1693 InsertText (@ReplaceStr[1], Length (ReplaceStr), False);
1694 Search_Replace := False;
1695 TrackCursor (False);
1696 Unlock;
1697 end;
1698 end;
1699 end;
1700 until (I = cmCancel) or (Flags and efReplaceAll = 0);
1701 end; { TEditor.DoSearchReplace }
1702
1703
1704 procedure TEditor.DoUpdate;
1705 begin
1706 if UpdateFlags <> 0 then
1707 begin
1708 SetCursor (CurPos.X - Delta.X, CurPos.Y - Delta.Y);
1709 if UpdateFlags and ufView <> 0 then
1710 DrawView
1711 else
1712 if UpdateFlags and ufLine <> 0 then
1713 DrawLines (CurPos.Y - Delta.Y, 1, LineStart (CurPtr));
1714 if assigned(HScrollBar) then
1715 HScrollBar^.SetParams (Delta.X, 0, Limit.X - Size.X, Size.X div 2, 1);
1716 if assigned(VScrollBar) then
1717 VScrollBar^.SetParams (Delta.Y, 0, Limit.Y - Size.Y, Size.Y - 1, 1);
1718 if assigned(Indicator) then
1719 Indicator^.SetValue (CurPos, AutoIndent, Modified, Word_Wrap);
1720 if State and sfActive <> 0 then
1721 UpdateCommands;
1722 UpdateFlags := 0;
1723 end;
1724 end; { TEditor.DoUpdate }
1725
1726
Do_Word_Wrapnull1727 function TEditor.Do_Word_Wrap (Select_Mode : Byte;
1728 Center_Cursor : Boolean) : Boolean;
1729 { This procedure does the actual wordwrap. It always assumes the CurPtr }
1730 { is at Right_Margin + 1. It makes several tests for special conditions }
1731 { and processes those first. If they all fail, it does a normal wrap. }
1732 VAR
1733 A : Sw_Word; { Distance between line start and first word on line. }
1734 C : Sw_Word; { Current pointer when we come into procedure. }
1735 L : Sw_Word; { BufLen when we come into procedure. }
1736 P : Sw_Word; { Position of pointer at any given moment. }
1737 S : Sw_Word; { Start of a line. }
1738 begin
1739 Do_Word_Wrap := False;
1740 Select_Mode := 0;
1741 if BufLen >= (BufSize - 1) then
1742 exit;
1743 C := CurPtr;
1744 L := BufLen;
1745 S := LineStart (CurPtr);
1746 { If first character in the line is a space and autoindent mode is on }
1747 { then we check to see if NextWord(S) exceeds the CurPtr. If it does, }
1748 { we set CurPtr as the AutoIndent marker. If it doesn't, we will set }
1749 { NextWord(S) as the AutoIndent marker. If neither, we set it to S. }
1750 if AutoIndent and (Buffer^[S] = ' ') then
1751 begin
1752 if NextWord (S) > CurPtr then
1753 A := CurPtr
1754 else
1755 A := NextWord (S);
1756 end
1757 else
1758 A := NextWord (S);
1759 { Though NewLine will remove EOL spaces, we do it here too. }
1760 { This catches the instance where a user may try to space }
1761 { completely across the line, in which case CurPtr.X = 0. }
1762 Remove_EOL_Spaces (Select_Mode);
1763 if CurPos.X = 0 then
1764 begin
1765 NewLine (Select_Mode);
1766 Do_Word_Wrap := True;
1767 Exit;
1768 end;
1769 { At this point we have one of five situations: }
1770 { }
1771 { 1) AutoIndent is on and this line is all spaces before CurPtr. }
1772 { 2) AutoIndent is off and this line is all spaces before CurPtr. }
1773 { 3) AutoIndent is on and this line is continuous characters before CurPtr. }
1774 { 4) AutoIndent is off and this line is continuous characters before CurPtr. }
1775 { 5) This is just a normal line of text. }
1776 { }
1777 { Conditions 1 through 4 have to be taken into account before condition 5. }
1778 { First, we see if there are all spaces and/or all characters. }
1779 { Then we determine which one it really is. Finally, we take }
1780 { a course of action based on the state of AutoIndent. }
1781 if PrevWord (CurPtr) <= S then
1782 begin
1783 P := CurPtr - 1;
1784 while ((Buffer^[P] <> ' ') and (P > S)) do
1785 Dec (P);
1786 { We found NO SPACES. Conditions 4 and 5 are treated the same. }
1787 { We can NOT do word wrap and put up a dialog box stating such. }
1788 { Delete character just entered so we don't exceed Right_Margin. }
1789 if P = S then
1790 begin
1791 EditorDialog (edWrapNotPossible, nil);
1792 DeleteRange (PrevChar (CurPtr), CurPtr, True);
1793 Exit;
1794 end
1795 else
1796 begin
1797 { There are spaces. Now find out if they are all spaces. }
1798 { If so, see if AutoIndent is on. If it is, turn it off, }
1799 { do a NewLine, and turn it back on. Otherwise, just do }
1800 { the NewLine. We go through all of these gyrations for }
1801 { AutoIndent. Being way out here with a preceding line }
1802 { of spaces and wrapping with AutoIndent on is real dumb! }
1803 { However, the user expects something. The wrap will NOT }
1804 { autoindent, but they had no business being here anyway! }
1805 P := CurPtr - 1;
1806 while ((Buffer^[P] = ' ') and (P > S)) do
1807 Dec (P);
1808 if P = S then
1809 begin
1810 if Autoindent then
1811 begin
1812 AutoIndent := False;
1813 NewLine (Select_Mode);
1814 AutoIndent := True;
1815 end
1816 else
1817 NewLine (Select_Mode);
1818 end; { AutoIndent }
1819 end; { P = S for spaces }
1820 end { P = S for no spaces }
1821 else { PrevWord (CurPtr) <= S }
1822 begin
1823 { Hooray! We actually had a plain old line of text to wrap! }
1824 { Regardless if we are pushing out a line beyond the Right_Margin, }
1825 { or at the end of a line itself, the following will determine }
1826 { exactly where to do the wrap and re-set the cursor accordingly. }
1827 { However, if P = A then we can't wrap. Show dialog and exit. }
1828 P := CurPtr;
1829 while P - S > Right_Margin do
1830 P := PrevWord (P);
1831 if (P = A) then
1832 begin
1833 EditorDialog (edReformNotPossible, nil);
1834 SetCurPtr (P, Select_Mode);
1835 Exit;
1836 end;
1837 SetCurPtr (P, Select_Mode);
1838 NewLine (Select_Mode);
1839 end; { PrevWord (CurPtr <= S }
1840 { Track the cursor here (it is at CurPos.X = 0) so the view }
1841 { will redraw itself at column 0. This eliminates having it }
1842 { redraw starting at the current cursor and not being able }
1843 { to see text before the cursor. Of course, we also end up }
1844 { redrawing the view twice, here and back in HandleEvent. }
1845 { }
1846 { Reposition cursor so user can pick up where they left off. }
1847 TrackCursor (Center_Cursor);
1848 SetCurPtr (C - (L - BufLen), Select_Mode);
1849 Do_Word_Wrap := True;
1850 end; { TEditor.Do_Word_Wrap }
1851
1852
1853 procedure TEditor.Draw;
1854 begin
1855 if DrawLine <> Delta.Y then
1856 begin
1857 DrawPtr := LineMove (DrawPtr, Delta.Y - DrawLine);
1858 DrawLine := Delta.Y;
1859 end;
1860 DrawLines (0, Size.Y, DrawPtr);
1861 end; { TEditor.Draw }
1862
1863
1864 procedure TEditor.DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word);
1865 VAR
1866 Color : Word;
1867 B : array[0..MaxLineLength - 1] of Sw_Word;
1868 begin
1869 Color := GetColor ($0201);
1870 while Count > 0 do
1871 begin
1872 FormatLine (B, LinePtr, Delta.X + Size.X, Color);
1873 WriteBuf (0, Y, Size.X, 1, B[Delta.X]);
1874 LinePtr := NextLine (LinePtr);
1875 Inc (Y);
1876 Dec (Count);
1877 end;
1878 end; { TEditor.DrawLines }
1879
1880
1881 procedure TEditor.Find;
1882 VAR
1883 FindRec : TFindDialogRec;
1884 begin
1885 with FindRec do
1886 begin
1887 Find := FindStr;
1888 Options := Flags;
1889 if EditorDialog (edFind, @FindRec) <> cmCancel then
1890 begin
1891 FindStr := Find;
1892 Flags := Options and not efDoReplace;
1893 DoSearchReplace;
1894 end;
1895 end;
1896 end; { TEditor.Find }
1897
1898
1899 procedure TEditor.FormatLine (var DrawBuf; LinePtr : Sw_Word;
1900 Width : Sw_Integer;
1901 Colors : Word);
1902 var
1903 outptr : pword;
1904 outcnt,
1905 idxpos : Sw_Word;
1906 attr : Word;
1907
1908 procedure FillSpace(i:Sw_Word);
1909 var
1910 w : word;
1911 begin
1912 inc(OutCnt,i);
1913 w:=32 or attr;
1914 while (i>0) do
1915 begin
1916 OutPtr^:=w;
1917 inc(OutPtr);
1918 dec(i);
1919 end;
1920 end;
1921
FormatUntilnull1922 function FormatUntil(endpos:Sw_word):boolean;
1923 var
1924 p : pchar;
1925 begin
1926 FormatUntil:=false;
1927 p:=pchar(Buffer)+idxpos;
1928 while endpos>idxpos do
1929 begin
1930 if OutCnt>=Width then
1931 exit;
1932 case p^ of
1933 #9 :
1934 FillSpace(Tabsize-(outcnt mod Tabsize));
1935 #10,#13 :
1936 begin
1937 FillSpace(Width-OutCnt);
1938 FormatUntil:=true;
1939 exit;
1940 end;
1941 else
1942 begin
1943 inc(OutCnt);
1944 OutPtr^:=ord(p^) or attr;
1945 inc(OutPtr);
1946 end;
1947 end; { case }
1948 inc(p);
1949 inc(idxpos);
1950 end;
1951 end;
1952
1953 begin
1954 OutCnt:=0;
1955 OutPtr:=@DrawBuf;
1956 idxPos:=LinePtr;
1957 attr:=lo(Colors) shl 8;
1958 if FormatUntil(SelStart) then
1959 exit;
1960 attr:=hi(Colors) shl 8;
1961 if FormatUntil(CurPtr) then
1962 exit;
1963 inc(idxPos,GapLen);
1964 if FormatUntil(SelEnd+GapLen) then
1965 exit;
1966 attr:=lo(Colors) shl 8;
1967 if FormatUntil(BufSize) then
1968 exit;
1969 { fill up until width }
1970 FillSpace(Width-OutCnt);
1971 end; {TEditor.FormatLine}
1972
1973
TEditor.GetMousePtrnull1974 function TEditor.GetMousePtr (Mouse : Objects.TPoint) : Sw_Word;
1975 begin
1976 MakeLocal (Mouse, Mouse);
1977 Mouse.X := Max (0, Min (Mouse.X, Size.X - 1));
1978 Mouse.Y := Max (0, Min (Mouse.Y, Size.Y - 1));
1979 GetMousePtr := CharPtr (LineMove (DrawPtr, Mouse.Y + Delta.Y - DrawLine),
1980 Mouse.X + Delta.X);
1981 end; { TEditor.GetMousePtr }
1982
1983
TEditor.GetPalettenull1984 function TEditor.GetPalette : PPalette;
1985 CONST
1986 P : String[Length (CEditor)] = CEditor;
1987 begin
1988 GetPalette := PPalette(@P);
1989 end; { TEditor.GetPalette }
1990
1991
1992 procedure TEditor.HandleEvent (var Event : Drivers.TEvent);
1993 VAR
1994 ShiftState : Byte;
1995 CenterCursor : Boolean;
1996 SelectMode : Byte;
1997 D : Objects.TPoint;
1998 Mouse : Objects.TPoint;
1999
CheckScrollBarnull2000 function CheckScrollBar (P : PScrollBar; var D : Sw_Integer) : Boolean;
2001 begin
2002 CheckScrollBar := FALSE;
2003 if (Event.InfoPtr = P) and (P^.Value <> D) then
2004 begin
2005 D := P^.Value;
2006 Update (ufView);
2007 CheckScrollBar := TRUE;
2008 end;
2009 end; {CheckScrollBar}
2010
2011 begin
2012 Inherited HandleEvent (Event);
2013 ConvertEvent (Event);
2014 CenterCursor := not CursorVisible;
2015 SelectMode := 0;
2016 ShiftState:=GetShiftState;
2017 if Selecting or (ShiftState and $03 <> 0) then
2018 SelectMode := smExtend;
2019 case Event.What of
2020 Drivers.evMouseDown:
2021 begin
2022 if Event.Double then
2023 SelectMode := SelectMode or smDouble;
2024 repeat
2025 Lock;
2026 if Event.What = evMouseAuto then
2027 begin
2028 MakeLocal (Event.Where, Mouse);
2029 D := Delta;
2030 if Mouse.X < 0 then
2031 Dec (D.X);
2032 if Mouse.X >= Size.X then
2033 Inc (D.X);
2034 if Mouse.Y < 0 then
2035 Dec (D.Y);
2036 if Mouse.Y >= Size.Y then
2037 Inc (D.Y);
2038 ScrollTo (D.X, D.Y);
2039 end;
2040 SetCurPtr (GetMousePtr (Event.Where), SelectMode);
2041 SelectMode := SelectMode or smExtend;
2042 Unlock;
2043 until not MouseEvent (Event, evMouseMove + evMouseAuto);
2044 end; { Drivers.evMouseDown }
2045
2046 Drivers.evKeyDown:
2047 case Event.CharCode of
2048 #32..#255:
2049 begin
2050 Lock;
2051 if Overwrite and not HasSelection then
2052 if CurPtr <> LineEnd (CurPtr) then
2053 SelEnd := NextChar (CurPtr);
2054 InsertText (@Event.CharCode, 1, False);
2055 if Word_Wrap then
2056 Check_For_Word_Wrap (SelectMode, CenterCursor);
2057 TrackCursor (CenterCursor);
2058 Unlock;
2059 end;
2060
2061 else
2062 Exit;
2063 end; { Drivers.evKeyDown }
2064
2065 Drivers.evCommand:
2066 case Event.Command of
2067 cmFind : Find;
2068 cmReplace : Replace;
2069 cmSearchAgain : DoSearchReplace;
2070 else
2071 begin
2072 Lock;
2073 case Event.Command of
2074 cmCut : ClipCut;
2075 cmCopy : ClipCopy;
2076 cmPaste : ClipPaste;
2077 cmUndo : Undo;
2078 cmClear : DeleteSelect;
2079 cmCharLeft : SetCurPtr (PrevChar (CurPtr), SelectMode);
2080 cmCharRight : SetCurPtr (NextChar (CurPtr), SelectMode);
2081 cmWordLeft : SetCurPtr (PrevWord (CurPtr), SelectMode);
2082 cmWordRight : SetCurPtr (NextWord (CurPtr), SelectMode);
2083 cmLineStart : SetCurPtr (LineStart (CurPtr), SelectMode);
2084 cmLineEnd : SetCurPtr (LineEnd (CurPtr), SelectMode);
2085 cmLineUp : SetCurPtr (LineMove (CurPtr, -1), SelectMode);
2086 cmLineDown : SetCurPtr (LineMove (CurPtr, 1), SelectMode);
2087 cmPageUp : SetCurPtr (LineMove (CurPtr, - (Size.Y - 1)), SelectMode);
2088 cmPageDown : SetCurPtr (LineMove (CurPtr, Size.Y - 1), SelectMode);
2089 cmTextStart : SetCurPtr (0, SelectMode);
2090 cmTextEnd : SetCurPtr (BufLen, SelectMode);
2091 cmNewLine : NewLine (SelectMode);
2092 cmBackSpace : DeleteRange (PrevChar (CurPtr), CurPtr, True);
2093 cmDelChar : DeleteRange (CurPtr, NextChar (CurPtr), True);
2094 cmDelWord : DeleteRange (CurPtr, NextWord (CurPtr), False);
2095 cmDelStart : DeleteRange (LineStart (CurPtr), CurPtr, False);
2096 cmDelEnd : DeleteRange (CurPtr, LineEnd (CurPtr), False);
2097 cmDelLine : DeleteRange (LineStart (CurPtr), NextLine (CurPtr), False);
2098 cmInsMode : ToggleInsMode;
2099 cmStartSelect : StartSelect;
2100 cmHideSelect : HideSelect;
2101 cmIndentMode : begin
2102 AutoIndent := not AutoIndent;
2103 Update (ufStats);
2104 end; { Added provision to update TIndicator if ^QI pressed. }
2105 cmCenterText : Center_Text (SelectMode);
2106 cmEndPage : SetCurPtr (LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y - 1), SelectMode);
2107 cmHomePage : SetCurPtr (LineMove (CurPtr, -(CurPos.Y - Delta.Y)), SelectMode);
2108 cmInsertLine : Insert_Line (SelectMode);
2109 cmJumpLine : Jump_To_Line (SelectMode);
2110 cmReformDoc : Reformat_Document (SelectMode, CenterCursor);
2111 cmReformPara : Reformat_Paragraph (SelectMode, CenterCursor);
2112 cmRightMargin : Set_Right_Margin;
2113 cmScrollDown : Scroll_Down;
2114 cmScrollUp : Scroll_Up;
2115 cmSelectWord : Select_Word;
2116 cmSetTabs : Set_Tabs;
2117 cmTabKey : Tab_Key (SelectMode);
2118 cmWordWrap : begin
2119 Word_Wrap := not Word_Wrap;
2120 Update (ufStats);
2121 end; { Added provision to update TIndicator if ^OW pressed. }
2122 cmSetMark0 : Set_Place_Marker (10);
2123 cmSetMark1 : Set_Place_Marker (1);
2124 cmSetMark2 : Set_Place_Marker (2);
2125 cmSetMark3 : Set_Place_Marker (3);
2126 cmSetMark4 : Set_Place_Marker (4);
2127 cmSetMark5 : Set_Place_Marker (5);
2128 cmSetMark6 : Set_Place_Marker (6);
2129 cmSetMark7 : Set_Place_Marker (7);
2130 cmSetMark8 : Set_Place_Marker (8);
2131 cmSetMark9 : Set_Place_Marker (9);
2132 cmJumpMark0 : Jump_Place_Marker (10, SelectMode);
2133 cmJumpMark1 : Jump_Place_Marker (1, SelectMode);
2134 cmJumpMark2 : Jump_Place_Marker (2, SelectMode);
2135 cmJumpMark3 : Jump_Place_Marker (3, SelectMode);
2136 cmJumpMark4 : Jump_Place_Marker (4, SelectMode);
2137 cmJumpMark5 : Jump_Place_Marker (5, SelectMode);
2138 cmJumpMark6 : Jump_Place_Marker (6, SelectMode);
2139 cmJumpMark7 : Jump_Place_Marker (7, SelectMode);
2140 cmJumpMark8 : Jump_Place_Marker (8, SelectMode);
2141 cmJumpMark9 : Jump_Place_Marker (9, SelectMode);
2142 else
2143 Unlock;
2144 Exit;
2145 end; { Event.Command (Inner) }
2146 TrackCursor (CenterCursor);
2147 { If the user presses any key except cmNewline or cmBackspace }
2148 { we need to check if the file has been modified yet. There }
2149 { can be no spaces at the end of a line, or wordwrap doesn't }
2150 { work properly. We don't want to do this if the file hasn't }
2151 { been modified because the user could be bringing in an ASCII }
2152 { file from an editor that allows spaces at the EOL. If we }
2153 { took them out in that scenario the "M" would appear on the }
2154 { TIndicator line and the user would get upset or confused. }
2155 if (Event.Command <> cmNewLine) and
2156 (Event.Command <> cmBackSpace) and
2157 (Event.Command <> cmTabKey) and
2158 Modified then
2159 Remove_EOL_Spaces (SelectMode);
2160 Unlock;
2161 end; { Event.Command (Outer) }
2162 end; { Drivers.evCommand }
2163
2164 Drivers.evBroadcast:
2165 case Event.Command of
2166 cmScrollBarChanged:
2167 if (Event.InfoPtr = HScrollBar) or
2168 (Event.InfoPtr = VScrollBar) then
2169 begin
2170 CheckScrollBar (HScrollBar, Delta.X);
2171 CheckScrollBar (VScrollBar, Delta.Y);
2172 end
2173 else
2174 exit;
2175 else
2176 Exit;
2177 end; { Drivers.evBroadcast }
2178
2179 end;
2180 ClearEvent (Event);
2181 end; { TEditor.HandleEvent }
2182
2183
HasSelectionnull2184 function TEditor.HasSelection : Boolean;
2185 begin
2186 HasSelection := SelStart <> SelEnd;
2187 end; { TEditor.HasSelection }
2188
2189
2190 procedure TEditor.HideSelect;
2191 begin
2192 Selecting := False;
2193 SetSelect (CurPtr, CurPtr, False);
2194 end; { TEditor.HideSelect }
2195
2196
2197 procedure TEditor.InitBuffer;
2198 begin
2199 Assert(Buffer = nil, 'TEditor.InitBuffer: Buffer is not nil');
2200 ReAllocMem(Buffer, BufSize);
2201 end; { TEditor.InitBuffer }
2202
2203
InsertBuffernull2204 function TEditor.InsertBuffer (var P : PEditBuffer;
2205 Offset, Length : Sw_Word;
2206 AllowUndo, SelectText : Boolean) : Boolean;
2207 VAR
2208 SelLen : Sw_Word;
2209 DelLen : Sw_Word;
2210 SelLines : Sw_Word;
2211 Lines : Sw_Word;
2212 NewSize : Longint;
2213 begin
2214 InsertBuffer := True;
2215 Selecting := False;
2216 SelLen := SelEnd - SelStart;
2217 if (SelLen = 0) and (Length = 0) then
2218 Exit;
2219 DelLen := 0;
2220 if AllowUndo then
2221 if CurPtr = SelStart then
2222 DelLen := SelLen
2223 else
2224 if SelLen > InsCount then
2225 DelLen := SelLen - InsCount;
2226 NewSize := Longint (BufLen + DelCount - SelLen + DelLen) + Length;
2227 if NewSize > BufLen + DelCount then
2228 if (NewSize > MaxBufLength) or not SetBufSize (NewSize) then
2229 begin
2230 EditorDialog (edOutOfMemory, nil);
2231 InsertBuffer := False;
2232 SelEnd := SelStart;
2233 Exit;
2234 end;
2235 SelLines := CountLines (Buffer^[BufPtr (SelStart)], SelLen);
2236 if CurPtr = SelEnd then
2237 begin
2238 if AllowUndo then
2239 begin
2240 if DelLen > 0 then
2241 Move (Buffer^[SelStart], Buffer^[CurPtr + GapLen - DelCount - DelLen], DelLen);
2242 Dec (InsCount, SelLen - DelLen);
2243 end;
2244 CurPtr := SelStart;
2245 Dec (CurPos.Y, SelLines);
2246 end;
2247 if Delta.Y > CurPos.Y then
2248 begin
2249 Dec (Delta.Y, SelLines);
2250 if Delta.Y < CurPos.Y then
2251 Delta.Y := CurPos.Y;
2252 end;
2253 if Length > 0 then
2254 Move (P^[Offset], Buffer^[CurPtr], Length);
2255 Lines := CountLines (Buffer^[CurPtr], Length);
2256 Inc (CurPtr, Length);
2257 Inc (CurPos.Y, Lines);
2258 DrawLine := CurPos.Y;
2259 DrawPtr := LineStart (CurPtr);
2260 CurPos.X := CharPos (DrawPtr, CurPtr);
2261 if not SelectText then
2262 SelStart := CurPtr;
2263 SelEnd := CurPtr;
2264 if Length>Sellen then
2265 begin
2266 Inc (BufLen, Length - SelLen);
2267 Dec (GapLen, Length - SelLen);
2268 end
2269 else
2270 begin
2271 Dec (BufLen, Sellen - Length);
2272 Inc (GapLen, Sellen - Length);
2273 end;
2274 if AllowUndo then
2275 begin
2276 Inc (DelCount, DelLen);
2277 Inc (InsCount, Length);
2278 end;
2279 Inc (Limit.Y, Lines - SelLines);
2280 Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y));
2281 if not IsClipboard then
2282 Modified := True;
2283 SetBufSize (BufLen + DelCount);
2284 if (SelLines = 0) and (Lines = 0) then
2285 Update (ufLine)
2286 else
2287 Update (ufView);
2288 end; { TEditor.InsertBuffer }
2289
2290
InsertFromnull2291 function TEditor.InsertFrom (Editor : PEditor) : Boolean;
2292 begin
2293 InsertFrom := InsertBuffer (Editor^.Buffer,
2294 Editor^.BufPtr (Editor^.SelStart),
2295 Editor^.SelEnd - Editor^.SelStart, CanUndo, IsClipboard);
2296 end; { TEditor.InsertFrom }
2297
2298
2299 procedure TEditor.Insert_Line (Select_Mode : Byte);
2300 { This procedure inserts a newline at the current cursor position }
2301 { if a ^N is pressed. Unlike cmNewLine, the cursor will return }
2302 { to its original position. If the cursor was at the end of a }
2303 { line, and its spaces were removed, the cursor returns to the }
2304 { end of the line instead. }
2305 begin
2306 NewLine (Select_Mode);
2307 SetCurPtr (LineEnd (LineMove (CurPtr, -1)), Select_Mode);
2308 end; { TEditor.Insert_Line }
2309
2310
TEditor.InsertTextnull2311 function TEditor.InsertText (Text : Pointer;
2312 Length : Sw_Word;
2313 SelectText : Boolean) : Boolean;
2314 begin
2315 if assigned(Text) and not Search_Replace then
2316 Update_Place_Markers (Length, 0, Self.SelStart, Self.SelEnd);
2317 InsertText := InsertBuffer (PEditBuffer (Text),
2318 0, Length, CanUndo, SelectText);
2319 end; { TEditor.InsertText }
2320
2321
TEditor.IsClipboardnull2322 function TEditor.IsClipboard : Boolean;
2323 begin
2324 IsClipboard := Clipboard = @Self;
2325 end; { TEditor.IsClipboard }
2326
2327
2328 procedure TEditor.Jump_Place_Marker (Element : Byte; Select_Mode : Byte);
2329 { This procedure jumps to a place marker if ^Q# is pressed. }
2330 { We don't go anywhere if Place_Marker[Element] is not zero. }
2331 begin
2332 if (not IsClipboard) and (Place_Marker[Element] <> 0) then
2333 SetCurPtr (Place_Marker[Element], Select_Mode);
2334 end; { TEditor.Jump_Place_Marker }
2335
2336
2337 procedure TEditor.Jump_To_Line (Select_Mode : Byte);
2338 { This function brings up a dialog box that allows }
2339 { the user to select a line number to jump to. }
2340 VAR
2341 Code : Integer; { Used for Val conversion. }
2342 Temp_Value : Longint; { Holds converted dialog value. }
2343 begin
2344 if EditorDialog (edJumpToLine, @Line_Number) <> cmCancel then
2345 begin
2346 { Convert the Line_Number string to an interger. }
2347 { Put it into Temp_Value. If the number is not }
2348 { in the range 1..9999 abort. If the number is }
2349 { our current Y position, abort. Otherwise, }
2350 { go to top of document, and jump to the line. }
2351 { There are faster methods. This one's easy. }
2352 { Note that CurPos.Y is always 1 less than what }
2353 { the TIndicator line says. }
2354 val (Line_Number, Temp_Value, Code);
2355 if (Temp_Value < 1) or (Temp_Value > 9999999) then
2356 Exit;
2357 if Temp_Value = CurPos.Y + 1 then
2358 Exit;
2359 SetCurPtr (0, Select_Mode);
2360 SetCurPtr (LineMove (CurPtr, Temp_Value - 1), Select_Mode);
2361 end;
2362 end; {TEditor.Jump_To_Line}
2363
2364
LineEndnull2365 function TEditor.LineEnd (P : Sw_Word) : Sw_Word;
2366 var
2367 start,
2368 i : Sw_word;
2369 pc : pchar;
2370 begin
2371 if P<CurPtr then
2372 begin
2373 i:=CurPtr-P;
2374 pc:=pchar(Buffer)+P;
2375 while (i>0) do
2376 begin
2377 if pc^ in [#10,#13] then
2378 begin
2379 LineEnd:=pc-pchar(Buffer);
2380 exit;
2381 end;
2382 inc(pc);
2383 dec(i);
2384 end;
2385 start:=CurPtr;
2386 end
2387 else
2388 start:=P;
2389 i:=BufLen-Start;
2390 pc:=pchar(Buffer)+GapLen+start;
2391 while (i>0) do
2392 begin
2393 if pc^ in [#10,#13] then
2394 begin
2395 LineEnd:=pc-(pchar(Buffer)+Gaplen);
2396 exit;
2397 end;
2398 inc(pc);
2399 dec(i);
2400 end;
2401 LineEnd:=pc-(pchar(Buffer)+Gaplen);
2402 end; { TEditor.LineEnd }
2403
2404
LineMovenull2405 function TEditor.LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word;
2406 VAR
2407 Pos : Sw_Integer;
2408 I : Sw_Word;
2409 begin
2410 I := P;
2411 P := LineStart (P);
2412 Pos := CharPos (P, I);
2413 while Count <> 0 do
2414 begin
2415 I := P;
2416 if Count < 0 then
2417 begin
2418 P := PrevLine (P);
2419 Inc (Count);
2420 end
2421 else
2422 begin
2423 P := NextLine (P);
2424 Dec (Count);
2425 end;
2426 end;
2427 if P <> I then
2428 P := CharPtr (P, Pos);
2429 LineMove := P;
2430 end; { TEditor.LineMove }
2431
2432
TEditor.LineStartnull2433 function TEditor.LineStart (P : Sw_Word) : Sw_Word;
2434 var
2435 i : Sw_word;
2436 start,pc : pchar;
2437 oc : char;
2438 begin
2439 if P>CurPtr then
2440 begin
2441 start:=pchar(Buffer)+GapLen;
2442 pc:=start;
2443 i:=P-CurPtr;
2444 dec(pc);
2445 while (i>0) do
2446 begin
2447 if pc^ in [#10,#13] then
2448 break;
2449 dec(pc);
2450 dec(i);
2451 end;
2452 end
2453 else
2454 i:=0;
2455 if i=0 then
2456 begin
2457 start:=pchar(Buffer);
2458 i:=P;
2459 pc:=start+p;
2460 dec(pc);
2461 while (i>0) do
2462 begin
2463 if pc^ in [#10,#13] then
2464 break;
2465 dec(pc);
2466 dec(i);
2467 end;
2468 if i=0 then
2469 begin
2470 LineStart:=0;
2471 exit;
2472 end;
2473 end;
2474 oc:=pc^;
2475 LineStart:=pc-start+1;
2476 end; { TEditor.LineStart }
2477
2478
LineNrnull2479 function TEditor.LineNr (P : Sw_Word) : Sw_Word;
2480 var
2481 pc,endp : pchar;
2482 lines : sw_word;
2483 begin
2484 endp:=pchar(Buffer)+BufPtr(P);
2485 pc:=pchar(Buffer);
2486 lines:=0;
2487 while (pc<endp) do
2488 begin
2489 if pc^ in [#10,#13] then
2490 begin
2491 inc(lines);
2492 if ord((pc+1)^)+ord(pc^)=23 then
2493 begin
2494 inc(pc);
2495 if (pc>=endp) then
2496 break;
2497 end;
2498 end;
2499 inc(pc);
2500 end;
2501 LineNr:=Lines;
2502 end;
2503
2504
2505 procedure TEditor.Lock;
2506 begin
2507 Inc (LockCount);
2508 end; { TEditor.Lock }
2509
2510
NewLinenull2511 function TEditor.NewLine (Select_Mode : Byte) : Boolean;
2512 VAR
2513 I : Sw_Word; { Used to track spaces for AutoIndent. }
2514 P : Sw_Word; { Position of Cursor when we arrive and after Newline. }
2515 begin
2516 P := LineStart (CurPtr);
2517 I := P;
2518 { The first thing we do is remove any End Of Line spaces. }
2519 { Then we check to see how many spaces are on beginning }
2520 { of a line. We need this check to add them after CR/LF }
2521 { if AutoIndenting. Last of all we insert spaces required }
2522 { for the AutoIndenting, if it was on. }
2523 Remove_EOL_Spaces (Select_Mode);
2524 while (I < CurPtr) and ((Buffer^[I] in [#9,' '])) do
2525 Inc (I);
2526 if InsertText (@LineBreak[1], length(LineBreak), False) = FALSE then
2527 exit;
2528 if AutoIndent then
2529 InsertText (@Buffer^[P], I - P, False);
2530 { Remember where the CurPtr is at this moment. }
2531 { Remember the length of the buffer at the moment. }
2532 { Go to the previous line and remove EOL spaces. }
2533 { Once removed, re-set the cursor to where we were }
2534 { minus any spaces that might have been removed. }
2535 I := BufLen;
2536 P := CurPtr;
2537 SetCurPtr (LineMove (CurPtr, - 1), Select_Mode);
2538 Remove_EOL_Spaces (Select_Mode);
2539 if I - BufLen <> 0 then
2540 SetCurPtr (P - (I - BufLen), Select_Mode)
2541 else
2542 SetCurPtr (P, Select_Mode);
2543 NewLine:=true;
2544 end; { TEditor.NewLine }
2545
2546
NextCharnull2547 function TEditor.NextChar (P : Sw_Word) : Sw_Word;
2548 var
2549 pc : pchar;
2550 begin
2551 if P<>BufLen then
2552 begin
2553 inc(P);
2554 if P<>BufLen then
2555 begin
2556 pc:=pchar(Buffer);
2557 if P>=CurPtr then
2558 inc(pc,GapLen);
2559 inc(pc,P-1);
2560 if ord(pc^)+ord((pc+1)^)=23 then
2561 inc(p);
2562 end;
2563 end;
2564 NextChar:=P;
2565 end; { TEditor.NextChar }
2566
2567
TEditor.NextLinenull2568 function TEditor.NextLine (P : Sw_Word) : Sw_Word;
2569 begin
2570 NextLine := NextChar (LineEnd (P));
2571 end; { TEditor.NextLine }
2572
2573
TEditor.NextWordnull2574 function TEditor.NextWord (P : Sw_Word) : Sw_Word;
2575 begin
2576 { skip word }
2577 while (P < BufLen) and (BufChar (P) in WordChars) do
2578 P := NextChar (P);
2579 { skip spaces }
2580 while (P < BufLen) and not (BufChar (P) in WordChars) do
2581 P := NextChar (P);
2582 NextWord := P;
2583 end; { TEditor.NextWord }
2584
2585
TEditor.PrevCharnull2586 function TEditor.PrevChar (P : Sw_Word) : Sw_Word;
2587 var
2588 pc : pchar;
2589 begin
2590 if p<>0 then
2591 begin
2592 dec(p);
2593 if p<>0 then
2594 begin
2595 pc:=pchar(Buffer);
2596 if P>=CurPtr then
2597 inc(pc,GapLen);
2598 inc(pc,P-1);
2599 if ord(pc^)+ord((pc+1)^)=23 then
2600 dec(p);
2601 end;
2602 end;
2603 PrevChar:=P;
2604 end; { TEditor.PrevChar }
2605
2606
PrevLinenull2607 function TEditor.PrevLine (P : Sw_Word) : Sw_Word;
2608 begin
2609 PrevLine := LineStart (PrevChar (P));
2610 end; { TEditor.PrevLine }
2611
2612
TEditor.PrevWordnull2613 function TEditor.PrevWord (P : Sw_Word) : Sw_Word;
2614 begin
2615 { skip spaces }
2616 while (P > 0) and not (BufChar (PrevChar (P)) in WordChars) do
2617 P := PrevChar (P);
2618 { skip word }
2619 while (P > 0) and (BufChar (PrevChar (P)) in WordChars) do
2620 P := PrevChar (P);
2621 PrevWord := P;
2622 end; { TEditor.PrevWord }
2623
2624
2625 procedure TEditor.Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean);
2626 { This procedure will do a reformat of the entire document, or just }
2627 { from the current line to the end of the document, if ^QU is pressed. }
2628 { It simply brings up the correct dialog box, and then calls the }
2629 { TEditor.Reformat_Paragraph procedure to do the actual reformatting. }
2630 CONST
2631 efCurrentLine = $0000; { Radio button #1 selection for dialog box. }
2632 efWholeDocument = $0001; { Radio button #2 selection for dialog box. }
2633 VAR
2634 Reformat_Options : Word; { Holds the dialog options for reformatting. }
2635 begin
2636 { Check if Word_Wrap is toggled on. If NOT on, check if programmer }
2637 { allows reformatting of document and if not show user dialog that }
2638 { says reformatting is not permissable. }
2639 if not Word_Wrap then
2640 begin
2641 if not Allow_Reformat then
2642 begin
2643 EditorDialog (edReformatNotAllowed, nil);
2644 Exit;
2645 end;
2646 Word_Wrap := True;
2647 Update (ufStats);
2648 end;
2649 { Default radio button option to 1st one. Bring up dialog box. }
2650 Reformat_Options := efCurrentLine;
2651 if EditorDialog (edReformatDocument, @Reformat_Options) <> cmCancel then
2652 begin
2653 { If the option to reformat the whole document was selected }
2654 { we need to go back to start of document. Otherwise we stay }
2655 { on the current line. Call Reformat_Paragraph until we get }
2656 { to the end of the document to do the reformatting. }
2657 if Reformat_Options and efWholeDocument <> 0 then
2658 SetCurPtr (0, Select_Mode);
2659 Unlock;
2660 repeat
2661 Lock;
2662 if NOT Reformat_Paragraph (Select_Mode, Center_Cursor) then
2663 Exit;
2664 TrackCursor (False);
2665 Unlock;
2666 until CurPtr = BufLen;
2667 end;
2668 end; { TEditor.Reformat_Document }
2669
2670
TEditor.Reformat_Paragraphnull2671 function TEditor.Reformat_Paragraph (Select_Mode : Byte;
2672 Center_Cursor : Boolean) : Boolean;
2673 { This procedure will do a reformat of the current paragraph if ^B pressed. }
2674 { The feature works regardless if wordrap is on or off. It also supports }
2675 { the AutoIndent feature. Reformat is not possible if the CurPos exceeds }
2676 { the Right_Margin. Right_Margin is where the EOL is considered to be. }
2677 CONST
2678 Space : array [1..2] of Char = #32#32;
2679 VAR
2680 C : Sw_Word; { Position of CurPtr when we come into procedure. }
2681 E : Sw_Word; { End of a line. }
2682 S : Sw_Word; { Start of a line. }
2683 begin
2684 Reformat_Paragraph := False;
2685 { Check if Word_Wrap is toggled on. If NOT on, check if programmer }
2686 { allows reformatting of paragraph and if not show user dialog that }
2687 { says reformatting is not permissable. }
2688 if not Word_Wrap then
2689 begin
2690 if not Allow_Reformat then
2691 begin
2692 EditorDialog (edReformatNotAllowed, nil);
2693 Exit;
2694 end;
2695 Word_Wrap := True;
2696 Update (ufStats);
2697 end;
2698 C := CurPtr;
2699 E := LineEnd (CurPtr);
2700 S := LineStart (CurPtr);
2701 { Reformat possible only if current line is NOT blank! }
2702 if E <> S then
2703 begin
2704 { Reformat is NOT possible if the first word }
2705 { on the line is beyond the Right_Margin. }
2706 S := LineStart (CurPtr);
2707 if NextWord (S) - S >= Right_Margin - 1 then
2708 begin
2709 EditorDialog (edReformNotPossible, nil);
2710 Exit;
2711 end;
2712 { First objective is to find the first blank line }
2713 { after this paragraph so we know when to stop. }
2714 { That could be the end of the document. }
2715 Repeat
2716 SetCurPtr (LineMove (CurPtr, 1), Select_Mode);
2717 E := LineEnd (CurPtr);
2718 S := LineStart (CurPtr);
2719 BlankLine := E;
2720 until ((CurPtr = BufLen) or (E = S));
2721 SetCurPtr (C, Select_Mode);
2722 repeat
2723 { Set CurPtr to LineEnd and remove the EOL spaces. }
2724 { Pull up the next line and remove its EOL space. }
2725 { First make sure the next line is not BlankLine! }
2726 { Insert spaces as required between the two lines. }
2727 SetCurPtr (LineEnd (CurPtr), Select_Mode);
2728 Remove_EOL_Spaces (Select_Mode);
2729 if CurPtr <> Blankline - 2 then
2730 DeleteRange (CurPtr, Nextword (CurPtr), True);
2731 Remove_EOL_Spaces (Select_Mode);
2732 case Buffer^[CurPtr-1] of
2733 '!' : InsertText (@Space, 2, False);
2734 '.' : InsertText (@Space, 2, False);
2735 ':' : InsertText (@Space, 2, False);
2736 '?' : InsertText (@Space, 2, False);
2737 else
2738 InsertText (@Space, 1, False);
2739 end;
2740 { Reset CurPtr to EOL. While line length is > Right_Margin }
2741 { go Do_Word_Wrap. If wordrap failed, exit routine. }
2742 SetCurPtr (LineEnd (CurPtr), Select_Mode);
2743 while LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin do
2744 if not Do_Word_Wrap (Select_Mode, Center_Cursor) then
2745 Exit;
2746 { If LineEnd - LineStart > Right_Margin then set CurPtr }
2747 { to Right_Margin on current line. Otherwise we set the }
2748 { CurPtr to LineEnd. This gyration sets up the conditions }
2749 { to test for time of loop exit. }
2750 if LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin then
2751 SetCurPtr (LineStart (CurPtr) + Right_Margin, Select_Mode)
2752 else
2753 SetCurPtr (LineEnd (CurPtr), Select_Mode);
2754 until ((CurPtr >= BufLen) or (CurPtr >= BlankLine - 2));
2755 end;
2756 { If not at the end of the document reset CurPtr to start of next line. }
2757 { This should be a blank line between paragraphs. }
2758 if CurPtr < BufLen then
2759 SetCurPtr (LineMove (CurPtr, 1), Select_Mode);
2760 Reformat_Paragraph := True;
2761 end; { TEditor.Reformat_Paragraph }
2762
2763
2764 procedure TEditor.Remove_EOL_Spaces (Select_Mode : Byte);
2765 { This procedure tests to see if there are consecutive spaces }
2766 { at the end of a line (EOL). If so, we delete all spaces }
2767 { after the last non-space character to the end of line. }
2768 { We then reset the CurPtr to where we ended up at. }
2769 VAR
2770 C : Sw_Word; { Current pointer when we come into procedure. }
2771 E : Sw_Word; { End of line. }
2772 P : Sw_Word; { Position of pointer at any given moment. }
2773 S : Sw_Word; { Start of a line. }
2774 begin
2775 C := CurPtr;
2776 E := LineEnd (CurPtr);
2777 P := E;
2778 S := LineStart (CurPtr);
2779 { Start at the end of a line and move towards the start. }
2780 { Find first non-space character in that direction. }
2781 while (P > S) and (BufChar (PrevChar (P)) = #32) do
2782 P := PrevChar (P);
2783 { If we found any spaces then delete them. }
2784 if P < E then
2785 begin
2786 SetSelect (P, E, True);
2787 DeleteSelect;
2788 Update_Place_Markers (0, E - P, P, E);
2789 end;
2790 { If C, our pointer when we came into this procedure, }
2791 { is less than the CurPtr then reset CurPtr to C so }
2792 { cursor is where we started. Otherwise, set it to }
2793 { the new CurPtr, for we have deleted characters. }
2794 if C < CurPtr then
2795 SetCurPtr (C, Select_Mode)
2796 else
2797 SetCurPtr (CurPtr, Select_Mode);
2798 end; { TEditor.Remove_EOL_Spaces }
2799
2800
2801 procedure TEditor.Replace;
2802 VAR
2803 ReplaceRec : TReplaceDialogRec;
2804 begin
2805 with ReplaceRec do
2806 begin
2807 Find := FindStr;
2808 Replace := ReplaceStr;
2809 Options := Flags;
2810 if EditorDialog (edReplace, @ReplaceRec) <> cmCancel then
2811 begin
2812 FindStr := Find;
2813 ReplaceStr := Replace;
2814 Flags := Options or efDoReplace;
2815 DoSearchReplace;
2816 end;
2817 end;
2818 end; { TEditor.Replace }
2819
2820
2821 procedure TEditor.Scroll_Down;
2822 { This procedure will scroll the screen up, and always keep }
2823 { the cursor on the CurPos.Y position, but not necessarily on }
2824 { the CurPos.X. If CurPos.Y scrolls off the screen, the cursor }
2825 { will stay in the upper left corner of the screen. This will }
2826 { simulate the same process in the IDE. The CurPos.X coordinate }
2827 { only messes up if we are on long lines and we then encounter }
2828 { a shorter or blank line beneath the current one as we scroll. }
2829 { In that case, it goes to the end of the new line. }
2830 VAR
2831 C : Sw_Word; { Position of CurPtr when we enter procedure. }
2832 P : Sw_Word; { Position of CurPtr at any given time. }
2833 W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y). }
2834 begin
2835 { Remember current cursor position. Remember current CurPos.Y position. }
2836 { Now issue the equivalent of a [Ctrl]-[End] command so the cursor will }
2837 { go to the bottom of the current screen. Reset the cursor to this new }
2838 { position and then send FALSE to TrackCursor so we fool it into }
2839 { incrementing Delta.Y by only +1. If we didn't do this it would try }
2840 { to center the cursor on the screen by fiddling with Delta.Y. }
2841 C := CurPtr;
2842 W.X := CurPos.Y;
2843 P := LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y);
2844 SetCurPtr (P, 0);
2845 TrackCursor (False);
2846 { Now remember where the new CurPos.Y is. See if distance between new }
2847 { CurPos.Y and old CurPos.Y are greater than the current screen size. }
2848 { If they are, we need to move cursor position itself down by one. }
2849 { Otherwise, send the cursor back to our original CurPtr. }
2850 W.Y := CurPos.Y;
2851 if W.Y - W.X > Size.Y - 1 then
2852 SetCurPtr (LineMove (C, 1), 0)
2853 else
2854 SetCurPtr (C, 0);
2855 end; { TEditor.Scroll_Down }
2856
2857
2858 procedure TEditor.Scroll_Up;
2859 { This procedure will scroll the screen down, and always keep }
2860 { the cursor on the CurPos.Y position, but not necessarily on }
2861 { the CurPos.X. If CurPos.Y scrolls off the screen, the cursor }
2862 { will stay in the bottom left corner of the screen. This will }
2863 { simulate the same process in the IDE. The CurPos.X coordinate }
2864 { only messes up if we are on long lines and we then encounter }
2865 { a shorter or blank line beneath the current one as we scroll. }
2866 { In that case, it goes to the end of the new line. }
2867 VAR
2868 C : Sw_Word; { Position of CurPtr when we enter procedure. }
2869 P : Sw_Word; { Position of CurPtr at any given time. }
2870 W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y). }
2871 begin
2872 { Remember current cursor position. Remember current CurPos.Y position. }
2873 { Now issue the equivalent of a [Ctrl]-[Home] command so the cursor will }
2874 { go to the top of the current screen. Reset the cursor to this new }
2875 { position and then send FALSE to TrackCursor so we fool it into }
2876 { decrementing Delta.Y by only -1. If we didn't do this it would try }
2877 { to center the cursor on the screen by fiddling with Delta.Y. }
2878 C := CurPtr;
2879 W.Y := CurPos.Y;
2880 P := LineMove (CurPtr, -(CurPos.Y - Delta.Y + 1));
2881 SetCurPtr (P, 0);
2882 TrackCursor (False);
2883 { Now remember where the new CurPos.Y is. See if distance between new }
2884 { CurPos.Y and old CurPos.Y are greater than the current screen size. }
2885 { If they are, we need to move the cursor position itself up by one. }
2886 { Otherwise, send the cursor back to our original CurPtr. }
2887 W.X := CurPos.Y;
2888 if W.Y - W.X > Size.Y - 1 then
2889 SetCurPtr (LineMove (C, -1), 0)
2890 else
2891 SetCurPtr (C, 0);
2892 end; { TEditor.Scroll_Up }
2893
2894
2895 procedure TEditor.ScrollTo (X, Y : Sw_Integer);
2896 begin
2897 X := Max (0, Min (X, Limit.X - Size.X));
2898 Y := Max (0, Min (Y, Limit.Y - Size.Y));
2899 if (X <> Delta.X) or (Y <> Delta.Y) then
2900 begin
2901 Delta.X := X;
2902 Delta.Y := Y;
2903 Update (ufView);
2904 end;
2905 end; { TEditor.ScrollTo }
2906
2907
TEditor.Searchnull2908 function TEditor.Search (const FindStr : String; Opts : Word) : Boolean;
2909 VAR
2910 I,Pos : Sw_Word;
2911 begin
2912 Search := False;
2913 Pos := CurPtr;
2914 repeat
2915 if Opts and efCaseSensitive <> 0 then
2916 I := Scan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr)
2917 else
2918 I := IScan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr);
2919 if (I <> sfSearchFailed) then
2920 begin
2921 Inc (I, Pos);
2922 if (Opts and efWholeWordsOnly = 0) or
2923 not (((I <> 0) and (BufChar (I - 1) in WordChars)) or
2924 ((I + Length (FindStr) <> BufLen) and
2925 (BufChar (I + Length (FindStr)) in WordChars))) then
2926 begin
2927 Lock;
2928 SetSelect (I, I + Length (FindStr), False);
2929 TrackCursor (not CursorVisible);
2930 Unlock;
2931 Search := True;
2932 Exit;
2933 end
2934 else
2935 Pos := I + 1;
2936 end;
2937 until I = sfSearchFailed;
2938 end; { TEditor.Search }
2939
2940
2941 procedure TEditor.Select_Word;
2942 { This procedure will select the a word to put into the clipboard. }
2943 { I've added it just to maintain compatibility with the IDE editor. }
2944 { Note that selection starts at the current cursor position and ends }
2945 { when a space or the end of line is encountered. }
2946 VAR
2947 E : Sw_Word; { End of the current line. }
2948 Select_Mode : Byte; { Allows us to turn select mode on inside procedure. }
2949 begin
2950 E := LineEnd (CurPtr);
2951 { If the cursor is on a space or at the end of a line, abort. }
2952 { Stupid action on users part for you can't select blanks! }
2953 if (BufChar (CurPtr) = #32) or (CurPtr = E) then
2954 Exit;
2955 { Turn on select mode and tell editor to start selecting text. }
2956 { As long as we have a character > a space (this is done to }
2957 { exclude CR/LF pairs at end of a line) and we are NOT at the }
2958 { end of a line, set the CurPtr to the next character. }
2959 { Once we find a space or CR/LF, selection is done and we }
2960 { automatically put the selected word into the Clipboard. }
2961 Select_Mode := smExtend;
2962 StartSelect;
2963 while (BufChar (NextChar (CurPtr)) > #32) and (CurPtr < E) do
2964 SetCurPtr (NextChar (CurPtr), Select_Mode);
2965 SetCurPtr (NextChar (CurPtr), Select_Mode);
2966 ClipCopy;
2967 end; {TEditor.Select_Word }
2968
2969
2970 procedure TEditor.SetBufLen (Length : Sw_Word);
2971 begin
2972 BufLen := Length;
2973 GapLen := BufSize - Length;
2974 SelStart := 0;
2975 SelEnd := 0;
2976 CurPtr := 0;
2977 CurPos.X:=0;
2978 CurPos.Y:=0;
2979 Delta.X:=0;
2980 Delta.Y:=0;
2981 GetLimits(Buffer^[GapLen], BufLen,Limit);
2982 inc(Limit.X);
2983 inc(Limit.Y);
2984 DrawLine := 0;
2985 DrawPtr := 0;
2986 DelCount := 0;
2987 InsCount := 0;
2988 Modified := False;
2989 Update (ufView);
2990 end; { TEditor.SetBufLen }
2991
2992
SetBufSizenull2993 function TEditor.SetBufSize (NewSize : Sw_Word) : Boolean;
2994 begin
2995 ReAllocMem(Buffer, NewSize);
2996 BufSize := NewSize;
2997 SetBufSize := True;
2998 end; { TEditor.SetBufSize }
2999
3000
3001 procedure TEditor.SetCmdState (Command : Word; Enable : Boolean);
3002 VAR
3003 S : TCommandSet;
3004 begin
3005 S := [Command];
3006 if Enable and (State and sfActive <> 0) then
3007 EnableCommands (S)
3008 else
3009 DisableCommands (S);
3010 end; { TEditor.SetCmdState }
3011
3012
3013 procedure TEditor.SetCurPtr (P : Sw_Word; SelectMode : Byte);
3014 VAR
3015 Anchor : Sw_Word;
3016 begin
3017 if SelectMode and smExtend = 0 then
3018 Anchor := P
3019 else
3020 if CurPtr = SelStart then
3021 Anchor := SelEnd
3022 else
3023 Anchor := SelStart;
3024 if P < Anchor then
3025 begin
3026 if SelectMode and smDouble <> 0 then
3027 begin
3028 P := PrevLine (NextLine (P));
3029 Anchor := NextLine (PrevLine (Anchor));
3030 end;
3031 SetSelect (P, Anchor, True);
3032 end
3033 else
3034 begin
3035 if SelectMode and smDouble <> 0 then
3036 begin
3037 P := NextLine (P);
3038 Anchor := PrevLine (NextLine (Anchor));
3039 end;
3040 SetSelect (Anchor, P, False);
3041 end;
3042 end; { TEditor.SetCurPtr }
3043
3044
3045 procedure TEditor.Set_Place_Marker (Element : Byte);
3046 { This procedure sets a place marker for the CurPtr if ^K# is pressed. }
3047 begin
3048 if not IsClipboard then
3049 Place_Marker[Element] := CurPtr;
3050 end; { TEditor.Set_Place_Marker }
3051
3052
3053 procedure TEditor.Set_Right_Margin;
3054 { This procedure will bring up a dialog box }
3055 { that allows the user to set Right_Margin. }
3056 { Values must be < MaxLineLength and > 9. }
3057 VAR
3058 Code : Integer; { Used for Val conversion. }
3059 Margin_Data : TRightMarginRec; { Holds dialog results. }
3060 Temp_Value : Sw_Integer; { Holds converted dialog value. }
3061 begin
3062 with Margin_Data do
3063 begin
3064 Str (Right_Margin, Margin_Position);
3065 if EditorDialog (edRightMargin, @Margin_Position) <> cmCancel then
3066 begin
3067 val (Margin_Position, Temp_Value, Code);
3068 if (Temp_Value <= MaxLineLength) and (Temp_Value > 9) then
3069 Right_Margin := Temp_Value;
3070 end;
3071 end;
3072 end; { TEditor.Set_Right_Margin }
3073
3074
3075 procedure TEditor.SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean);
3076 VAR
3077 UFlags : Byte;
3078 P : Sw_Word;
3079 L : Sw_Word;
3080 begin
3081 if CurStart then
3082 P := NewStart
3083 else
3084 P := NewEnd;
3085 UFlags := ufUpdate;
3086 if (NewStart <> SelStart) or (NewEnd <> SelEnd) then
3087 if (NewStart <> NewEnd) or (SelStart <> SelEnd) then
3088 UFlags := ufView;
3089 if P <> CurPtr then
3090 begin
3091 if P > CurPtr then
3092 begin
3093 L := P - CurPtr;
3094 Move (Buffer^[CurPtr + GapLen], Buffer^[CurPtr], L);
3095 Inc (CurPos.Y, CountLines (Buffer^[CurPtr], L));
3096 CurPtr := P;
3097 end
3098 else
3099 begin
3100 L := CurPtr - P;
3101 CurPtr := P;
3102 Dec (CurPos.Y, CountLines (Buffer^[CurPtr], L));
3103 Move (Buffer^[CurPtr], Buffer^[CurPtr + GapLen], L);
3104 end;
3105 DrawLine := CurPos.Y;
3106 DrawPtr := LineStart (P);
3107 CurPos.X := CharPos (DrawPtr, P);
3108 DelCount := 0;
3109 InsCount := 0;
3110 SetBufSize (BufLen);
3111 end;
3112 SelStart := NewStart;
3113 SelEnd := NewEnd;
3114 Update (UFlags);
3115 end; { TEditor.Select }
3116
3117
3118 procedure TEditor.SetState (AState : Word; Enable : Boolean);
3119 begin
3120 Inherited SetState (AState, Enable);
3121 case AState of
3122 sfActive: begin
3123 if assigned(HScrollBar) then
3124 HScrollBar^.SetState (sfVisible, Enable);
3125 if assigned(VScrollBar) then
3126 VScrollBar^.SetState (sfVisible, Enable);
3127 if assigned(Indicator) then
3128 Indicator^.SetState (sfVisible, Enable);
3129 UpdateCommands;
3130 end;
3131 sfExposed: if Enable then Unlock;
3132 end;
3133 end; { TEditor.SetState }
3134
3135
3136 procedure TEditor.Set_Tabs;
3137 { This procedure will bring up a dialog box }
3138 { that allows the user to set tab stops. }
3139 VAR
3140 Index : Sw_Integer; { Index into string array. }
3141 Tab_Data : TTabStopRec; { Holds dialog results. }
3142 begin
3143 with Tab_Data do
3144 begin
3145 { Assign current Tab_Settings to Tab_String. }
3146 { Bring up the tab dialog so user can set tabs. }
3147 Tab_String := Copy (Tab_Settings, 1, Tab_Stop_Length);
3148 if EditorDialog (edSetTabStops, @Tab_String) <> cmCancel then
3149 begin
3150 { If Tab_String comes back as empty then set Tab_Settings to nil. }
3151 { Otherwise, find the last character in Tab_String that is not }
3152 { a space and copy Tab_String into Tab_Settings up to that spot. }
3153 if Length (Tab_String) = 0 then
3154 begin
3155 FillChar (Tab_Settings, SizeOf (Tab_Settings), #0);
3156 Tab_Settings[0] := #0;
3157 Exit;
3158 end
3159 else
3160 begin
3161 Index := Length (Tab_String);
3162 while Tab_String[Index] <= #32 do
3163 Dec (Index);
3164 Tab_Settings := Copy (Tab_String, 1, Index);
3165 end;
3166 end;
3167 end;
3168 end; { TEditor.Set_Tabs }
3169
3170
3171 procedure TEditor.StartSelect;
3172 begin
3173 HideSelect;
3174 Selecting := True;
3175 end; { TEditor.StartSelect }
3176
3177
3178 procedure TEditor.Store (var S : Objects.TStream);
3179 begin
3180 Inherited Store (S);
3181 PutPeerViewPtr (S, HScrollBar);
3182 PutPeerViewPtr (S, VScrollBar);
3183 PutPeerViewPtr (S, Indicator);
3184 S.Write (BufSize, SizeOf (BufSize));
3185 S.Write (Canundo, SizeOf (Canundo));
3186 S.Write (AutoIndent, SizeOf (AutoIndent));
3187 S.Write (Line_Number, SizeOf (Line_Number));
3188 S.Write (Place_Marker, SizeOf (Place_Marker));
3189 S.Write (Right_Margin, SizeOf (Right_Margin));
3190 S.Write (Tab_Settings, SizeOf (Tab_Settings));
3191 S.Write (Word_Wrap, SizeOf (Word_Wrap));
3192 end; { Editor.Store }
3193
3194
3195 procedure TEditor.Tab_Key (Select_Mode : Byte);
3196 { This function determines if we are in overstrike or insert mode, }
3197 { and then moves the cursor if overstrike, or adds spaces if insert. }
3198 VAR
3199 E : Sw_Word; { End of current line. }
3200 Index : Sw_Integer; { Loop counter. }
3201 Position : Sw_Integer; { CurPos.X position. }
3202 S : Sw_Word; { Start of current line. }
3203 Spaces : array [1..80] of Char; { Array to hold spaces for insertion. }
3204 begin
3205 E := LineEnd (CurPtr);
3206 S := LineStart (CurPtr);
3207 { Find the current horizontal cursor position. }
3208 { Now loop through the Tab_Settings string and }
3209 { find the next available tab stop. }
3210 Position := CurPos.X + 1;
3211 repeat
3212 Inc (Position);
3213 until (Tab_Settings[Position] <> #32) or (Position >= Ord (Tab_Settings[0]));
3214 E := CurPos.X;
3215 Index := 1;
3216 { Now we enter a loop to go to the next tab position. }
3217 { If we are in overwrite mode, we just move the cursor }
3218 { through the text to the next tab stop. If we are in }
3219 { insert mode, we add spaces to the Spaces array for }
3220 { the number of times we loop. }
3221 while Index < Position - E do
3222 begin
3223 if Overwrite then
3224 begin
3225 if (Position > LineEnd (CurPtr) - LineStart (CurPtr))
3226 or (Position > Ord (Tab_Settings[0])) then
3227 begin
3228 SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode);
3229 Exit;
3230 end
3231 else
3232 if CurPtr < BufLen then
3233 SetCurPtr (NextChar (CurPtr), Select_Mode);
3234 end
3235 else
3236 begin
3237 if (Position > Right_Margin) or (Position > Ord (Tab_Settings[0])) then
3238 begin
3239 SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode);
3240 Exit;
3241 end
3242 else
3243 Spaces[Index] := #32;
3244 end;
3245 Inc (Index);
3246 end;
3247 { If we are insert mode, we insert spaces to the next tab stop. }
3248 { When we're all done, the cursor will be sitting on the new tab stop. }
3249 if not OverWrite then
3250 InsertText (@Spaces, Index - 1, False);
3251 end; { TEditor.Tab_Key }
3252
3253
3254 procedure TEditor.ToggleInsMode;
3255 begin
3256 Overwrite := not Overwrite;
3257 SetState (sfCursorIns, not GetState (sfCursorIns));
3258 end; { TEditor.ToggleInsMode }
3259
3260
3261 procedure TEditor.TrackCursor (Center : Boolean);
3262 begin
3263 if Center then
3264 ScrollTo (CurPos.X - Size.X + 1, CurPos.Y - Size.Y div 2)
3265 else
3266 ScrollTo (Max (CurPos.X - Size.X + 1, Min (Delta.X, CurPos.X)),
3267 Max (CurPos.Y - Size.Y + 1, Min (Delta.Y, CurPos.Y)));
3268 end; { TEditor.TrackCursor }
3269
3270
3271 procedure TEditor.Undo;
3272 VAR
3273 Length : Sw_Word;
3274 begin
3275 if (DelCount <> 0) or (InsCount <> 0) then
3276 begin
3277 Update_Place_Markers (DelCount, 0, CurPtr, CurPtr + DelCount);
3278 SelStart := CurPtr - InsCount;
3279 SelEnd := CurPtr;
3280 Length := DelCount;
3281 DelCount := 0;
3282 InsCount := 0;
3283 InsertBuffer (Buffer, CurPtr + GapLen - Length, Length, False, True);
3284 end;
3285 end; { TEditor.Undo }
3286
3287
3288 procedure TEditor.Unlock;
3289 begin
3290 if LockCount > 0 then
3291 begin
3292 Dec (LockCount);
3293 if LockCount = 0 then
3294 DoUpdate;
3295 end;
3296 end; { TEditor.Unlock }
3297
3298
3299 procedure TEditor.Update (AFlags : Byte);
3300 begin
3301 UpdateFlags := UpdateFlags or AFlags;
3302 if LockCount = 0 then
3303 DoUpdate;
3304 end; { TEditor.Update }
3305
3306
3307 procedure TEditor.UpdateCommands;
3308 begin
3309 SetCmdState (cmUndo, (DelCount <> 0) or (InsCount <> 0));
3310 if not IsClipboard then
3311 begin
3312 SetCmdState (cmCut, HasSelection);
3313 SetCmdState (cmCopy, HasSelection);
3314 SetCmdState (cmPaste, assigned(Clipboard) and (Clipboard^.HasSelection));
3315 end;
3316 SetCmdState (cmClear, HasSelection);
3317 SetCmdState (cmFind, True);
3318 SetCmdState (cmReplace, True);
3319 SetCmdState (cmSearchAgain, True);
3320 end; { TEditor.UpdateCommands }
3321
3322
3323 procedure TEditor.Update_Place_Markers (AddCount : Word; KillCount : Word;
3324 StartPtr,EndPtr : Sw_Word);
3325 { This procedure updates the position of the place markers }
3326 { as the user inserts and deletes text in the document. }
3327 VAR
3328 Element : Byte; { Place_Marker array element to traverse array with. }
3329 begin
3330 for Element := 1 to 10 do
3331 begin
3332 if AddCount > 0 then
3333 begin
3334 if (Place_Marker[Element] >= Curptr)
3335 and (Place_Marker[Element] <> 0) then
3336 Place_Marker[Element] := Place_Marker[Element] + AddCount;
3337 end
3338 else
3339 begin
3340 if Place_Marker[Element] >= StartPtr then
3341 begin
3342 if (Place_Marker[Element] >= StartPtr) and
3343 (Place_Marker[Element] < EndPtr) then
3344 Place_marker[Element] := 0
3345 else
3346 begin
3347 if integer (Place_Marker[Element]) - integer (KillCount) > 0 then
3348 Place_Marker[Element] := Place_Marker[Element] - KillCount
3349 else
3350 Place_Marker[Element] := 0;
3351 end;
3352 end;
3353 end;
3354 end;
3355 if AddCount > 0 then
3356 BlankLine := BlankLine + AddCount
3357 else
3358 begin
3359 if integer (BlankLine) - Integer (KillCount) > 0 then
3360 BlankLine := BlankLine - KillCount
3361 else
3362 BlankLine := 0;
3363 end;
3364 end; { TEditor.Update_Place_Markers }
3365
3366
Validnull3367 function TEditor.Valid (Command : Word) : Boolean;
3368 begin
3369 Valid := IsValid;
3370 end; { TEditor.Valid }
3371
3372
3373 {****************************************************************************
3374 TMEMO
3375 ****************************************************************************}
3376
3377 constructor TMemo.Load (var S : Objects.TStream);
3378 VAR
3379 Length : Sw_Word;
3380 begin
3381 Inherited Load (S);
3382 S.Read (Length, SizeOf (Length));
3383 if IsValid then
3384 begin
3385 S.Read (Buffer^[BufSize - Length], Length);
3386 SetBufLen (Length);
3387 end
3388 else
3389 S.Seek (S.GetPos + Length);
3390 end; { TMemo.Load }
3391
3392
DataSizenull3393 function TMemo.DataSize : Sw_Word;
3394 begin
3395 DataSize := BufSize + SizeOf (Sw_Word);
3396 end; { TMemo.DataSize }
3397
3398
3399 procedure TMemo.GetData (var Rec);
3400 VAR
3401 Data : TMemoData absolute Rec;
3402 begin
3403 Data.Length := BufLen;
3404 Move (Buffer^, Data.Buffer, CurPtr);
3405 Move (Buffer^[CurPtr + GapLen], Data.Buffer[CurPtr], BufLen - CurPtr);
3406 FillChar (Data.Buffer[BufLen], BufSize - BufLen, 0);
3407 end; { TMemo.GetData }
3408
3409
TMemo.GetPalettenull3410 function TMemo.GetPalette : PPalette;
3411 CONST
3412 P : String[Length (CMemo)] = CMemo;
3413 begin
3414 GetPalette := PPalette(@P);
3415 end; { TMemo.GetPalette }
3416
3417
3418 procedure TMemo.HandleEvent (var Event : Drivers.TEvent);
3419 begin
3420 if (Event.What <> Drivers.evKeyDown) or (Event.KeyCode <> Drivers.kbTab) then
3421 Inherited HandleEvent (Event);
3422 end; { TMemo.HandleEvent }
3423
3424
3425 procedure TMemo.SetData (var Rec);
3426 VAR
3427 Data : TMemoData absolute Rec;
3428 begin
3429 Move (Data.Buffer, Buffer^[BufSize - Data.Length], Data.Length);
3430 SetBufLen (Data.Length);
3431 end; { TMemo.SetData }
3432
3433
3434 procedure TMemo.Store (var S : Objects.TStream);
3435 begin
3436 Inherited Store (S);
3437 S.Write (BufLen, SizeOf (BufLen));
3438 S.Write (Buffer^, CurPtr);
3439 S.Write (Buffer^[CurPtr + GapLen], BufLen - CurPtr);
3440 end; { TMemo.Store }
3441
3442
3443 {****************************************************************************
3444 TFILEEDITOR
3445 ****************************************************************************}
3446
3447
3448 constructor TFileEditor.Init (var Bounds : TRect;
3449 AHScrollBar, AVScrollBar : PScrollBar;
3450 AIndicator : PIndicator;
3451 AFileName : FNameStr);
3452 begin
3453 Inherited Init (Bounds, AHScrollBar, AVScrollBar, AIndicator, 0);
3454 if AFileName <> '' then
3455 begin
3456 FileName := FExpand (AFileName);
3457 if IsValid then
3458 IsValid := LoadFile;
3459 end;
3460 end; { TFileEditor.Init }
3461
3462
3463 constructor TFileEditor.Load (var S : Objects.TStream);
3464 VAR
3465 SStart,SEnd,Curs : Sw_Word;
3466 begin
3467 Inherited Load (S);
3468 BufSize := 0;
3469 S.Read (FileName[0], SizeOf (Byte));
3470 S.Read (Filename[1], Length (FileName));
3471 if IsValid then
3472 IsValid := LoadFile;
3473 S.Read (SStart, SizeOf (SStart));
3474 S.Read (SEnd, SizeOf (SEnd));
3475 S.Read (Curs, SizeOf (Curs));
3476 if IsValid and (SEnd <= BufLen) then
3477 begin
3478 SetSelect (SStart, SEnd, Curs = SStart);
3479 TrackCursor (True);
3480 end;
3481 end; { TFileEditor.Load }
3482
3483
3484 procedure TFileEditor.DoneBuffer;
3485 begin
3486 ReAllocMem(Buffer, 0);
3487 end; { TFileEditor.DoneBuffer }
3488
3489
3490 procedure TFileEditor.HandleEvent (var Event : Drivers.TEvent);
3491 begin
3492 Inherited HandleEvent (Event);
3493 case Event.What of
3494 Drivers.evCommand:
3495 case Event.Command of
3496 cmSave : Save;
3497 cmSaveAs : SaveAs;
3498 cmSaveDone : if Save then
3499 Message (Owner, Drivers.evCommand, cmClose, nil);
3500 else
3501 Exit;
3502 end;
3503 else
3504 Exit;
3505 end;
3506 ClearEvent (Event);
3507 end; { TFileEditor.HandleEvent }
3508
3509
3510 procedure TFileEditor.InitBuffer;
3511 begin
3512 Assert(Buffer = nil, 'TFileEditor.InitBuffer: Buffer is not nil');
3513 ReAllocMem(Buffer, MinBufLength);
3514 BufSize := MinBufLength;
3515 end; { TFileEditor.InitBuffer }
3516
3517
LoadFilenull3518 function TFileEditor.LoadFile: Boolean;
3519 VAR
3520 Length : Sw_Word;
3521 FSize : Longint;
3522 FRead : Sw_Integer;
3523 F : File;
3524 begin
3525 LoadFile := False;
3526 Length := 0;
3527 Assign(F, FileName);
3528 Reset(F, 1);
3529 if IOResult <> 0 then
3530 EditorDialog(edReadError, @FileName)
3531 else
3532 begin
3533 FSize := FileSize(F);
3534 if (FSize > MaxBufLength) or not SetBufSize(FSize) then
3535 EditorDialog(edOutOfMemory, nil)
3536 else
3537 begin
3538 BlockRead(F, Buffer^[BufSize-FSize], FSize, FRead);
3539 if (IOResult <> 0) or (FRead<>FSize) then
3540 EditorDialog(edReadError, @FileName)
3541 else
3542 begin
3543 LoadFile := True;
3544 Length := FRead;
3545 end;
3546 end;
3547 Close(F);
3548 end;
3549 SetBufLen(Length);
3550 end; { TFileEditor.LoadFile }
3551
3552
TFileEditor.Savenull3553 function TFileEditor.Save : Boolean;
3554 begin
3555 if FileName = '' then
3556 Save := SaveAs
3557 else
3558 Save := SaveFile;
3559 end; { TFileEditor.Save }
3560
3561
TFileEditor.SaveAsnull3562 function TFileEditor.SaveAs : Boolean;
3563 begin
3564 SaveAs := False;
3565 if EditorDialog (edSaveAs, @FileName) <> cmCancel then
3566 begin
3567 FileName := FExpand (FileName);
3568 Message (Owner, Drivers.evBroadcast, cmUpdateTitle, nil);
3569 SaveAs := SaveFile;
3570 if IsClipboard then
3571 FileName := '';
3572 end;
3573 end; { TFileEditor.SaveAs }
3574
3575
SaveFilenull3576 function TFileEditor.SaveFile : Boolean;
3577 VAR
3578 F : File;
3579 BackupName : Objects.FNameStr;
3580 D : DOS.DirStr;
3581 N : DOS.NameStr;
3582 E : DOS.ExtStr;
3583 begin
3584 SaveFile := False;
3585 if Flags and efBackupFiles <> 0 then
3586 begin
3587 FSplit (FileName, D, N, E);
3588 BackupName := D + N + '.bak';
3589 Assign (F, BackupName);
3590 Erase (F);
3591 Assign (F, FileName);
3592 Rename (F, BackupName);
3593 InOutRes := 0;
3594 end;
3595 Assign (F, FileName);
3596 Rewrite (F, 1);
3597 if IOResult <> 0 then
3598 EditorDialog (edCreateError, @FileName)
3599 else
3600 begin
3601 BlockWrite (F, Buffer^, CurPtr);
3602 BlockWrite (F, Buffer^[CurPtr + GapLen], BufLen - CurPtr);
3603 if IOResult <> 0 then
3604 EditorDialog (edWriteError, @FileName)
3605 else
3606 begin
3607 Modified := False;
3608 Update (ufUpdate);
3609 SaveFile := True;
3610 end;
3611 Close (F);
3612 end;
3613 end; { TFileEditor.SaveFile }
3614
3615
TFileEditor.SetBufSizenull3616 function TFileEditor.SetBufSize (NewSize : Sw_Word) : Boolean;
3617 VAR
3618 N : Sw_Word;
3619 begin
3620 SetBufSize := False;
3621 if NewSize = 0 then
3622 NewSize := MinBufLength
3623 else
3624 if NewSize > (MaxBufLength-MinBufLength) then
3625 NewSize := MaxBufLength
3626 else
3627 NewSize := (NewSize + (MinBufLength-1)) and (MaxBufLength and (not (MinBufLength-1)));
3628 if NewSize <> BufSize then
3629 begin
3630 if NewSize > BufSize then ReAllocMem(Buffer, NewSize);
3631 N := BufLen - CurPtr + DelCount;
3632 Move(Buffer^[BufSize - N], Buffer^[NewSize - N], N);
3633 if NewSize < BufSize then ReAllocMem(Buffer, NewSize);
3634 BufSize := NewSize;
3635 GapLen := BufSize - BufLen;
3636 end;
3637 SetBufSize := True;
3638 end; { TFileEditor.SetBufSize }
3639
3640
3641 procedure TFileEditor.Store (var S : Objects.TStream);
3642 begin
3643 Inherited Store (S);
3644 S.Write (FileName, Length (FileName) + 1);
3645 S.Write (SelStart, SizeOf (SelStart));
3646 S.Write (SelEnd, SizeOf (SelEnd));
3647 S.Write (CurPtr, SizeOf (CurPtr));
3648 end; { TFileEditor.Store }
3649
3650
3651 procedure TFileEditor.UpdateCommands;
3652 begin
3653 Inherited UpdateCommands;
3654 SetCmdState (cmSave, True);
3655 SetCmdState (cmSaveAs, True);
3656 SetCmdState (cmSaveDone, True);
3657 end; { TFileEditor.UpdateCommands }
3658
3659
TFileEditor.Validnull3660 function TFileEditor.Valid (Command : Word) : Boolean;
3661 VAR
3662 D : Integer;
3663 begin
3664 if Command = cmValid then
3665 Valid := IsValid
3666 else
3667 begin
3668 Valid := True;
3669 if Modified then
3670 begin
3671 if FileName = '' then
3672 D := edSaveUntitled
3673 else
3674 D := edSaveModify;
3675 case EditorDialog (D, @FileName) of
3676 cmYes : Valid := Save;
3677 cmNo : Modified := False;
3678 cmCancel : Valid := False;
3679 end;
3680 end;
3681 end;
3682 end; { TFileEditor.Valid }
3683
3684
3685 {****************************************************************************
3686 TEDITWINDOW
3687 ****************************************************************************}
3688
3689 constructor TEditWindow.Init (var Bounds : TRect;
3690 FileName : Objects.FNameStr;
3691 ANumber : Integer);
3692 var
3693 HScrollBar : PScrollBar;
3694 VScrollBar : PScrollBar;
3695 Indicator : PIndicator;
3696 R : TRect;
3697 begin
3698 Inherited Init (Bounds, '', ANumber);
3699 Options := Options or ofTileable;
3700
3701 R.Assign (18, Size.Y - 1, Size.X - 2, Size.Y);
3702 HScrollBar := New (PScrollBar, Init (R));
3703 HScrollBar^.Hide;
3704 Insert (HScrollBar);
3705
3706 R.Assign (Size.X - 1, 1, Size.X, Size.Y - 1);
3707 VScrollBar := New (PScrollBar, Init (R));
3708 VScrollBar^.Hide;
3709 Insert (VScrollBar);
3710
3711 R.Assign (2, Size.Y - 1, 16, Size.Y);
3712 Indicator := New (PIndicator, Init (R));
3713 Indicator^.Hide;
3714 Insert (Indicator);
3715
3716 GetExtent (R);
3717 R.Grow (-1, -1);
3718 Editor := New (PFileEditor, Init (R, HScrollBar, VScrollBar, Indicator, FileName));
3719 Insert (Editor);
3720 end; { TEditWindow.Init }
3721
3722
3723 constructor TEditWindow.Load (var S : Objects.TStream);
3724 begin
3725 Inherited Load (S);
3726 GetSubViewPtr (S, Editor);
3727 end; { TEditWindow.Load }
3728
3729
3730 procedure TEditWindow.Close;
3731 begin
3732 if Editor^.IsClipboard then
3733 Hide
3734 else
3735 Inherited Close;
3736 end; { TEditWindow.Close }
3737
3738
TEditWindow.GetTitlenull3739 function TEditWindow.GetTitle (MaxSize : Sw_Integer) : TTitleStr;
3740 begin
3741 if Editor^.IsClipboard then
3742 GetTitle := sClipboard
3743 else
3744 if Editor^.FileName = '' then
3745 GetTitle := sUntitled
3746 else
3747 GetTitle := Editor^.FileName;
3748 end; { TEditWindow.GetTile }
3749
3750
3751 procedure TEditWindow.HandleEvent (var Event : Drivers.TEvent);
3752 begin
3753 Inherited HandleEvent (Event);
3754 if (Event.What = Drivers.evBroadcast) then
3755 { and (Event.Command = cmUpdateTitle) then }
3756 { Changed if statement above so I could test for cmBlugeonStats. }
3757 { Stats would not show up when loading a file until a key was pressed. }
3758 case Event.Command of
3759 cmUpdateTitle :
3760 begin
3761 Frame^.DrawView;
3762 ClearEvent (Event);
3763 end;
3764 cmBludgeonStats :
3765 begin
3766 Editor^.Update (ufStats);
3767 ClearEvent (Event);
3768 end;
3769 end;
3770 end; { TEditWindow.HandleEvent }
3771
3772
3773 procedure TEditWindow.SizeLimits(var Min, Max: TPoint);
3774 begin
3775 inherited SizeLimits(Min, Max);
3776 Min.X := 23;
3777 end;
3778
3779
3780 procedure TEditWindow.Store (var S : Objects.TStream);
3781 begin
3782 Inherited Store (S);
3783 PutSubViewPtr (S, Editor);
3784 end; { TEditWindow.Store }
3785
3786
3787 procedure RegisterEditors;
3788 begin
3789 RegisterType (REditor);
3790 RegisterType (RMemo);
3791 RegisterType (RFileEditor);
3792 RegisterType (RIndicator);
3793 RegisterType (REditWindow);
3794 end; { RegisterEditors }
3795
3796
3797 end. { Unit NewEdit }
3798