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