home *** CD-ROM | disk | FTP | other *** search
/ The Devil's Doorknob BBS Capture (1996-2003) / devilsdoorknobbbscapture1996-2003.iso / Dloads / OTHERUTI / TPASCAL3.ZIP / TVISION.ZIP / EDITORS.PAS < prev    next >
Pascal/Delphi Source File  |  1991-06-11  |  46KB  |  1,935 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Turbo Pascal Version 6.0                        }
  5. {       Turbo Vision Unit                               }
  6. {                                                       }
  7. {       Copyright (c) 1990 Borland International        }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11. unit Editors;
  12.  
  13. {$F+,I-,O+,S-,V-,X+}
  14.  
  15. interface
  16.  
  17. uses Drivers, Objects, Views;
  18.  
  19. const
  20.   cmSave        = 80;
  21.   cmSaveAs      = 81;
  22.   cmFind        = 82;
  23.   cmReplace     = 83;
  24.   cmSearchAgain = 84;
  25.  
  26. const
  27.   cmCharLeft    = 500;
  28.   cmCharRight   = 501;
  29.   cmWordLeft    = 502;
  30.   cmWordRight   = 503;
  31.   cmLineStart   = 504;
  32.   cmLineEnd     = 505;
  33.   cmLineUp      = 506;
  34.   cmLineDown    = 507;
  35.   cmPageUp      = 508;
  36.   cmPageDown    = 509;
  37.   cmTextStart   = 510;
  38.   cmTextEnd     = 511;
  39.   cmNewLine     = 512;
  40.   cmBackSpace   = 513;
  41.   cmDelChar     = 514;
  42.   cmDelWord     = 515;
  43.   cmDelStart    = 516;
  44.   cmDelEnd      = 517;
  45.   cmDelLine     = 518;
  46.   cmInsMode     = 519;
  47.   cmStartSelect = 520;
  48.   cmHideSelect  = 521;
  49.   cmIndentMode  = 522;
  50.   cmUpdateTitle = 523;
  51.  
  52. const
  53.   edOutOfMemory   = 0;
  54.   edReadError     = 1;
  55.   edWriteError    = 2;
  56.   edCreateError   = 3;
  57.   edSaveModify    = 4;
  58.   edSaveUntitled  = 5;
  59.   edSaveAs        = 6;
  60.   edFind          = 7;
  61.   edSearchFailed  = 8;
  62.   edReplace       = 9;
  63.   edReplacePrompt = 10;
  64.  
  65. const
  66.   efCaseSensitive   = $0001;
  67.   efWholeWordsOnly  = $0002;
  68.   efPromptOnReplace = $0004;
  69.   efReplaceAll      = $0008;
  70.   efDoReplace       = $0010;
  71.   efBackupFiles     = $0100;
  72.  
  73. const
  74.   CIndicator = #2#3;
  75.   CEditor    = #6#7;
  76.   CMemo      = #26#27;
  77.  
  78. const
  79.   MaxLineLength = 256;
  80.  
  81. type
  82.   TEditorDialog = function(Dialog: Integer; Info: Pointer): Word;
  83.  
  84. type
  85.   PIndicator = ^TIndicator;
  86.   TIndicator = object(TView)
  87.     Location: TPoint;
  88.     Modified: Boolean;
  89.     constructor Init(var Bounds: TRect);
  90.     procedure Draw; virtual;
  91.     function GetPalette: PPalette; virtual;
  92.     procedure SetState(AState: Word; Enable: Boolean); virtual;
  93.     procedure SetValue(ALocation: TPoint; AModified: Boolean);
  94.   end;
  95.  
  96. type
  97.   PEditBuffer = ^TEditBuffer;
  98.   TEditBuffer = array[0..65519] of Char;
  99.  
  100. type
  101.   PEditor = ^TEditor;
  102.   TEditor = object(TView)
  103.     HScrollBar: PScrollBar;
  104.     VScrollBar: PScrollBar;
  105.     Indicator: PIndicator;
  106.     Buffer: PEditBuffer;
  107.     BufSize: Word;
  108.     BufLen: Word;
  109.     GapLen: Word;
  110.     SelStart: Word;
  111.     SelEnd: Word;
  112.     CurPtr: Word;
  113.     CurPos: TPoint;
  114.     Delta: TPoint;
  115.     Limit: TPoint;
  116.     DrawLine: Integer;
  117.     DrawPtr: Word;
  118.     DelCount: Word;
  119.     InsCount: Word;
  120.     IsValid: Boolean;
  121.     CanUndo: Boolean;
  122.     Modified: Boolean;
  123.     Selecting: Boolean;
  124.     Overwrite: Boolean;
  125.     AutoIndent: Boolean;
  126.     constructor Init(var Bounds: TRect;
  127.       AHScrollBar, AVScrollBar: PScrollBar;
  128.       AIndicator: PIndicator; ABufSize: Word);
  129.     constructor Load(var S: TStream);
  130.     destructor Done; virtual;
  131.     function BufChar(P: Word): Char;
  132.     function BufPtr(P: Word): Word;
  133.     procedure ChangeBounds(var Bounds: TRect); virtual;
  134.     procedure ConvertEvent(var Event: TEvent); virtual;
  135.     function CursorVisible: Boolean;
  136.     procedure DeleteSelect;
  137.     procedure DoneBuffer; virtual;
  138.     procedure Draw; virtual;
  139.     function GetPalette: PPalette; virtual;
  140.     procedure HandleEvent(var Event: TEvent); virtual;
  141.     procedure InitBuffer; virtual;
  142.     function InsertBuffer(var P: PEditBuffer; Offset, Length: Word;
  143.       AllowUndo, SelectText: Boolean): Boolean;
  144.     function InsertFrom(Editor: PEditor): Boolean; virtual;
  145.     function InsertText(Text: Pointer; Length: Word;
  146.       SelectText: Boolean): Boolean;
  147.     procedure ScrollTo(X, Y: Integer);
  148.     function Search(FindStr: String; Opts: Word): Boolean;
  149.     function SetBufSize(NewSize: Word): Boolean; virtual;
  150.     procedure SetCmdState(Command: Word; Enable: Boolean);
  151.     procedure SetSelect(NewStart, NewEnd: Word; CurStart: Boolean);
  152.     procedure SetState(AState: Word; Enable: Boolean); virtual;
  153.     procedure Store(var S: TStream);
  154.     procedure TrackCursor(Center: Boolean);
  155.     procedure Undo;
  156.     procedure UpdateCommands; virtual;
  157.     function Valid(Command: Word): Boolean; virtual;
  158.   private
  159.     LockCount: Byte;
  160.     UpdateFlags: Byte;
  161.     KeyState: Integer;
  162.     function CharPos(P, Target: Word): Integer;
  163.     function CharPtr(P: Word; Target: Integer): Word;
  164.     function ClipCopy: Boolean;
  165.     procedure ClipCut;
  166.     procedure ClipPaste;
  167.     procedure DeleteRange(StartPtr, EndPtr: Word; DelSelect: Boolean);
  168.     procedure DoUpdate;
  169.     procedure DoSearchReplace;
  170.     procedure DrawLines(Y, Count: Integer; LinePtr: Word);
  171.     procedure FormatLine(var DrawBuf; LinePtr: Word;
  172.       Width: Integer; Colors: Word);
  173.     procedure Find;
  174.     function GetMousePtr(Mouse: TPoint): Word;
  175.     function HasSelection: Boolean;
  176.     procedure HideSelect;
  177.     function IsClipboard: Boolean;
  178.     function LineEnd(P: Word): Word;
  179.     function LineMove(P: Word; Count: Integer): Word;
  180.     function LineStart(P: Word): Word;
  181.     procedure Lock;
  182.     procedure NewLine;
  183.     function NextChar(P: Word): Word;
  184.     function NextLine(P: Word): Word;
  185.     function NextWord(P: Word): Word;
  186.     function PrevChar(P: Word): Word;
  187.     function PrevLine(P: Word): Word;
  188.     function PrevWord(P: Word): Word;
  189.     procedure Replace;
  190.     procedure SetBufLen(Length: Word);
  191.     procedure SetCurPtr(P: Word; SelectMode: Byte);
  192.     procedure StartSelect;
  193.     procedure ToggleInsMode;
  194.     procedure Unlock;
  195.     procedure Update(AFlags: Byte);
  196.   end;
  197.  
  198. type
  199.   TMemoData = record
  200.     Length: Word;
  201.     Buffer: TEditBuffer;
  202.   end;
  203.  
  204. type
  205.   PMemo = ^TMemo;
  206.   TMemo = object(TEditor)
  207.     constructor Load(var S: TStream);
  208.     function DataSize: Word; virtual;
  209.     procedure GetData(var Rec); virtual;
  210.     function GetPalette: PPalette; virtual;
  211.     procedure HandleEvent(var Event: TEvent); virtual;
  212.     procedure SetData(var Rec); virtual;
  213.     procedure Store(var S: TStream);
  214.   end;
  215.  
  216. type
  217.   PFileEditor = ^TFileEditor;
  218.   TFileEditor = object(TEditor)
  219.     FileName: FNameStr;
  220.     constructor Init(var Bounds: TRect;
  221.       AHScrollBar, AVScrollBar: PScrollBar;
  222.       AIndicator: PIndicator; AFileName: FNameStr);
  223.     constructor Load(var S: TStream);
  224.     procedure DoneBuffer; virtual;
  225.     procedure HandleEvent(var Event: TEvent); virtual;
  226.     procedure InitBuffer; virtual;
  227.     function LoadFile: Boolean;
  228.     function Save: Boolean;
  229.     function SaveAs: Boolean;
  230.     function SaveFile: Boolean;
  231.     function SetBufSize(NewSize: Word): Boolean; virtual;
  232.     procedure Store(var S: TStream);
  233.     procedure UpdateCommands; virtual;
  234.     function Valid(Command: Word): Boolean; virtual;
  235.   end;
  236.  
  237. type
  238.   PEditWindow = ^TEditWindow;
  239.   TEditWindow = object(TWindow)
  240.     Editor: PFileEditor;
  241.     constructor Init(var Bounds: TRect;
  242.       FileName: FNameStr; ANumber: Integer);
  243.     constructor Load(var S: TStream);
  244.     procedure Close; virtual;
  245.     function GetTitle(MaxSize: Integer): TTitleStr; virtual;
  246.     procedure HandleEvent(var Event: TEvent); virtual;
  247.     procedure Store(var S: TStream);
  248.   end;
  249.  
  250. function DefEditorDialog(Dialog: Integer; Info: Pointer): Word;
  251.  
  252. const
  253.   WordChars: set of Char = ['0'..'9', 'A'..'Z', '_', 'a'..'z'];
  254.   EditorDialog: TEditorDialog = DefEditorDialog;
  255.   EditorFlags: Word = efBackupFiles + efPromptOnReplace;
  256.   FindStr: String[80] = '';
  257.   ReplaceStr: String[80] = '';
  258.   Clipboard: PEditor = nil;
  259.  
  260. type
  261.   TFindDialogRec = record
  262.     Find: String[80];
  263.     Options: Word;
  264.   end;
  265.  
  266. type
  267.   TReplaceDialogRec = record
  268.     Find: String[80];
  269.     Replace: String[80];
  270.     Options: Word;
  271.   end;
  272.  
  273. const
  274.   REditor: TStreamRec = (
  275.     ObjType: 70;
  276.     VmtLink: Ofs(TypeOf(TEditor)^);
  277.     Load: @TEditor.Load;
  278.     Store: @TEditor.Store
  279.   );
  280.   RMemo: TStreamRec = (
  281.     ObjType: 71;
  282.     VmtLink: Ofs(TypeOf(TMemo)^);
  283.     Load: @TMemo.Load;
  284.     Store: @TMemo.Store
  285.   );
  286.   RFileEditor: TStreamRec = (
  287.     ObjType: 72;
  288.     VmtLink: Ofs(TypeOf(TFileEditor)^);
  289.     Load: @TFileEditor.Load;
  290.     Store: @TFileEditor.Store
  291.   );
  292.   RIndicator: TStreamRec = (
  293.     ObjType: 73;
  294.     VmtLink: Ofs(TypeOf(TIndicator)^);
  295.     Load: @TIndicator.Load;
  296.     Store: @TIndicator.Store
  297.   );
  298.   REditWindow: TStreamRec = (
  299.     ObjType: 74;
  300.     VmtLink: Ofs(TypeOf(TEditWindow)^);
  301.     Load: @TEditWindow.Load;
  302.     Store: @TEditWindow.Store
  303.   );
  304.  
  305. procedure RegisterEditors;
  306.  
  307. implementation
  308.  
  309. uses Memory, Buffers, Dos;
  310.  
  311. const
  312.   ufUpdate = $01;
  313.   ufLine   = $02;
  314.   ufView   = $04;
  315.  
  316. const
  317.   smExtend = $01;
  318.   smDouble = $02;
  319.  
  320. const
  321.   sfSearchFailed = $FFFF;
  322.  
  323. const
  324.   FirstKeys: array[0..37 * 2] of Word = (37,
  325.     Ord(^A), cmWordLeft, Ord(^C), cmPageDown,
  326.     Ord(^D), cmCharRight, Ord(^E), cmLineUp,
  327.     Ord(^F), cmWordRight, Ord(^G), cmDelChar,
  328.     Ord(^H), cmBackSpace, Ord(^K), $FF02,
  329.     Ord(^L), cmSearchAgain, Ord(^M), cmNewLine,
  330.     Ord(^O), cmIndentMode, Ord(^Q), $FF01,
  331.     Ord(^R), cmPageUp, Ord(^S), cmCharLeft,
  332.     Ord(^T), cmDelWord, Ord(^U), cmUndo,
  333.     Ord(^V), cmInsMode, Ord(^X), cmLineDown,
  334.     Ord(^Y), cmDelLine, kbLeft, cmCharLeft,
  335.     kbRight, cmCharRight, kbCtrlLeft, cmWordLeft,
  336.     kbCtrlRight, cmWordRight, kbHome, cmLineStart,
  337.     kbEnd, cmLineEnd, kbUp, cmLineUp,
  338.     kbDown, cmLineDown, kbPgUp, cmPageUp,
  339.     kbPgDn, cmPageDown, kbCtrlPgUp, cmTextStart,
  340.     kbCtrlPgDn, cmTextEnd, kbIns, cmInsMode,
  341.     kbDel, cmDelChar, kbShiftIns, cmPaste,
  342.     kbShiftDel, cmCut, kbCtrlIns, cmCopy,
  343.     kbCtrlDel, cmClear);
  344.   QuickKeys: array[0..8 * 2] of Word = (8,
  345.     Ord('A'), cmReplace, Ord('C'), cmTextEnd,
  346.     Ord('D'), cmLineEnd, Ord('F'), cmFind,
  347.     Ord('H'), cmDelStart, Ord('R'), cmTextStart,
  348.     Ord('S'), cmLineStart, Ord('Y'), cmDelEnd);
  349.   BlockKeys: array[0..5 * 2] of Word = (5,
  350.     Ord('B'), cmStartSelect, Ord('C'), cmPaste,
  351.     Ord('H'), cmHideSelect, Ord('K'), cmCopy,
  352.     Ord('Y'), cmCut);
  353.   KeyMap: array[0..2] of Pointer = (@FirstKeys, @QuickKeys, @BlockKeys);
  354.  
  355. function DefEditorDialog(Dialog: Integer; Info: Pointer): Word;
  356. begin
  357.   DefEditorDialog := cmCancel;
  358. end;
  359.  
  360. function Min(X, Y: Integer): Integer; assembler;
  361. asm
  362.     MOV    AX,X
  363.     CMP    AX,Y
  364.     JLE    @@1
  365.     MOV    AX,Y
  366. @@1:
  367. end;
  368.  
  369. function Max(X, Y: Integer): Integer; assembler;
  370. asm
  371.     MOV    AX,X
  372.     CMP    AX,Y
  373.     JGE    @@1
  374.     MOV    AX,Y
  375. @@1:
  376. end;
  377.  
  378. function MinWord(X, Y: Word): Word; assembler;
  379. asm
  380.     MOV    AX,X
  381.     CMP    AX,Y
  382.     JBE    @@1
  383.     MOV    AX,Y
  384. @@1:
  385. end;
  386.  
  387. function MaxWord(X, Y: Word): Word; assembler;
  388. asm
  389.     MOV    AX,X
  390.     CMP    AX,Y
  391.     JAE    @@1
  392.     MOV    AX,Y
  393. @@1:
  394. end;
  395.  
  396. function CountLines(var Buf; Count: Word): Integer; assembler;
  397. asm
  398.     LES    DI,Buf
  399.     MOV    CX,Count
  400.     XOR    DX,DX
  401.     MOV    AL,0DH
  402.     CLD
  403. @@1:    JCXZ    @@2
  404.     REPNE    SCASB
  405.     JNE    @@2
  406.     INC    DX
  407.     JMP    @@1
  408. @@2:    MOV    AX,DX
  409. end;
  410.  
  411. function ScanKeyMap(KeyMap: Pointer; KeyCode: Word): Word; assembler;
  412. asm
  413.     PUSH    DS
  414.     LDS    SI,KeyMap
  415.     MOV    DX,KeyCode
  416.     CLD
  417.     LODSW
  418.     MOV    CX,AX
  419. @@1:    LODSW
  420.     MOV    BX,AX
  421.     LODSW
  422.     CMP    BL,DL
  423.     JNE    @@3
  424.     OR    BH,BH
  425.     JE    @@4
  426.     CMP    BH,DH
  427.     JE    @@4
  428. @@3:    LOOP    @@1
  429.     XOR    AX,AX
  430. @@4:    POP    DS
  431. end;
  432.  
  433. function Scan(var Block; Size: Word; Str: String): Word; assembler;
  434. asm
  435.     PUSH    DS
  436.     LES    DI,Block
  437.     LDS    SI,Str
  438.     MOV    CX,Size
  439.     JCXZ    @@3
  440.     CLD
  441.     LODSB
  442.     CMP    AL,1
  443.     JB    @@5
  444.     JA    @@1
  445.     LODSB
  446.     REPNE    SCASB
  447.     JNE    @@3
  448.     JMP    @@5
  449. @@1:    XOR    AH,AH
  450.     MOV    BX,AX
  451.         DEC     BX
  452.     MOV    DX,CX
  453.     SUB    DX,AX
  454.     JB    @@3
  455.     LODSB
  456.     INC    DX
  457.     INC    DX
  458. @@2:    DEC    DX
  459.     MOV    CX,DX
  460.     REPNE    SCASB
  461.     JNE    @@3
  462.     MOV    DX,CX
  463.     MOV    CX,BX
  464.     REP    CMPSB
  465.     JE    @@4
  466.     SUB    CX,BX
  467.     ADD    SI,CX
  468.     ADD    DI,CX
  469.     INC    DI
  470.     OR    DX,DX
  471.     JNE    @@2
  472. @@3:    XOR    AX,AX
  473.     JMP    @@6
  474. @@4:    SUB    DI,BX
  475. @@5:    MOV    AX,DI
  476.     SUB    AX,WORD PTR Block
  477. @@6:    DEC    AX
  478.     POP    DS
  479. end;
  480.  
  481. function IScan(var Block; Size: Word; Str: String): Word; assembler;
  482. var
  483.   S: String;
  484. asm
  485.     PUSH    DS
  486.     MOV    AX,SS
  487.     MOV    ES,AX
  488.     LEA    DI,S
  489.     LDS    SI,Str
  490.     XOR    AH,AH
  491.     LODSB
  492.     STOSB
  493.     MOV    CX,AX
  494.     MOV    BX,AX
  495.     JCXZ    @@9
  496. @@1:    LODSB
  497.     CMP    AL,'a'
  498.     JB    @@2
  499.     CMP    AL,'z'
  500.     JA    @@2
  501.     SUB    AL,20H
  502. @@2:    STOSB
  503.     LOOP    @@1
  504.     SUB    DI,BX
  505.     LDS    SI,Block
  506.     MOV    CX,Size
  507.     JCXZ    @@8
  508.     CLD
  509.     SUB    CX,BX
  510.     JB    @@8
  511.     INC    CX
  512. @@4:    MOV    AH,ES:[DI]
  513.     AND    AH,$DF
  514. @@5:    LODSB
  515.     AND    AL,$DF
  516.     CMP    AL,AH
  517.     LOOPNE    @@5
  518.     JNE    @@8
  519.     DEC    SI
  520.     MOV    DX,CX
  521.         MOV    CX,BX
  522. @@6:    REPE    CMPSB
  523.     JE    @@10
  524.     MOV    AL,DS:[SI-1]
  525.     CMP    AL,'a'
  526.     JB    @@7
  527.     CMP    AL,'z'
  528.     JA    @@7
  529.     SUB    AL,20H
  530. @@7:    CMP    AL,ES:[DI-1]
  531.     JE    @@6
  532.     SUB    CX,BX
  533.     ADD    SI,CX
  534.     ADD    DI,CX
  535.     INC    SI
  536.     MOV    CX,DX
  537.     JNE    @@4
  538. @@8:    XOR    AX,AX
  539.     JMP    @@11
  540. @@9:    MOV    AX, 1
  541.     JMP    @@11
  542. @@10:    SUB    SI,BX
  543.     MOV    AX,SI
  544.     SUB    AX,WORD PTR Block
  545.     INC    AX
  546. @@11:    DEC    AX
  547.     POP    DS
  548. end;
  549.  
  550. { TIndicator }
  551.  
  552. constructor TIndicator.Init(var Bounds: TRect);
  553. var
  554.   R: TRect;
  555. begin
  556.   TView.Init(Bounds);
  557.   GrowMode := gfGrowLoY + gfGrowHiY;
  558. end;
  559.  
  560. procedure TIndicator.Draw;
  561. var
  562.   Color: Byte;
  563.   Frame: Char;
  564.   L: array[0..1] of Longint;
  565.   S: String[15];
  566.   B: TDrawBuffer;
  567. begin
  568.   if State and sfDragging = 0 then
  569.   begin
  570.     Color := GetColor(1);
  571.     Frame := #205;
  572.   end else
  573.   begin
  574.     Color := GetColor(2);
  575.     Frame := #196;
  576.   end;
  577.   MoveChar(B, Frame, Color, Size.X);
  578.   if Modified then WordRec(B[0]).Lo := 15;
  579.   L[0] := Location.Y + 1;
  580.   L[1] := Location.X + 1;
  581.   FormatStr(S, ' %d:%d ', L);
  582.   MoveStr(B[8 - Pos(':', S)], S, Color);
  583.   WriteBuf(0, 0, Size.X, 1, B);
  584. end;
  585.  
  586. function TIndicator.GetPalette: PPalette;
  587. const
  588.   P: string[Length(CIndicator)] = CIndicator;
  589. begin
  590.   GetPalette := @P;
  591. end;
  592.  
  593. procedure TIndicator.SetState(AState: Word; Enable: Boolean);
  594. begin
  595.   TView.SetState(AState, Enable);
  596.   if AState = sfDragging then DrawView;
  597. end;
  598.  
  599. procedure TIndicator.SetValue(ALocation: TPoint; AModified: Boolean);
  600. begin
  601.   if (Longint(Location) <> Longint(ALocation)) or
  602.     (Modified <> AModified) then
  603.   begin
  604.     Location := ALocation;
  605.     Modified := AModified;
  606.     DrawView;
  607.   end;
  608. end;
  609.  
  610. { TEditor }
  611.  
  612. constructor TEditor.Init(var Bounds: TRect;
  613.   AHScrollBar, AVScrollBar: PScrollBar;
  614.   AIndicator: PIndicator; ABufSize: Word);
  615. begin
  616.   TView.Init(Bounds);
  617.   GrowMode := gfGrowHiX + gfGrowHiY;
  618.   Options := Options or ofSelectable;
  619.   EventMask := evMouseDown + evKeyDown + evCommand + evBroadcast;
  620.   ShowCursor;
  621.   HScrollBar := AHScrollBar;
  622.   VScrollBar := AVScrollBar;
  623.   Indicator := AIndicator;
  624.   BufSize := ABufSize;
  625.   CanUndo := True;
  626.   InitBuffer;
  627.   if Buffer <> nil then IsValid := True else
  628.   begin
  629.     EditorDialog(edOutOfMemory, nil);
  630.     BufSize := 0;
  631.   end;
  632.   SetBufLen(0);
  633. end;
  634.  
  635. constructor TEditor.Load(var S: TStream);
  636. begin
  637.   TView.Load(S);
  638.   GetPeerViewPtr(S, HScrollBar);
  639.   GetPeerViewPtr(S, VScrollBar);
  640.   GetPeerViewPtr(S, Indicator);
  641.   S.Read(BufSize, SizeOf(Word));
  642.   S.Read(CanUndo, SizeOf(Boolean));
  643.   InitBuffer;
  644.   if Buffer <> nil then IsValid := True else
  645.   begin
  646.     EditorDialog(edOutOfMemory, nil);
  647.     BufSize := 0;
  648.   end;
  649.   Lock;
  650.   SetBufLen(0);
  651. end;
  652.  
  653. destructor TEditor.Done;
  654. begin
  655.   DoneBuffer;
  656.   TView.Done;
  657. end;
  658.  
  659. function TEditor.BufChar(P: Word): Char; assembler;
  660. asm
  661.     LES    DI,Self
  662.     MOV    BX,P
  663.     CMP    BX,ES:[DI].TEditor.CurPtr
  664.     JB    @@1
  665.     ADD    BX,ES:[DI].TEditor.GapLen
  666. @@1:    LES    DI,ES:[DI].TEditor.Buffer
  667.     MOV    AL,ES:[DI+BX]
  668. end;
  669.  
  670. function TEditor.BufPtr(P: Word): Word; assembler;
  671. asm
  672.     LES    DI,Self
  673.     MOV    AX,P
  674.     CMP    AX,ES:[DI].TEditor.CurPtr
  675.     JB    @@1
  676.     ADD    AX,ES:[DI].TEditor.GapLen
  677. @@1:
  678. end;
  679.  
  680. procedure TEditor.ChangeBounds(var Bounds: TRect);
  681. begin
  682.   SetBounds(Bounds);
  683.   Delta.X := Max(0, Min(Delta.X, Limit.X - Size.X));
  684.   Delta.Y := Max(0, Min(Delta.Y, Limit.Y - Size.Y));
  685.   Update(ufView);
  686. end;
  687.  
  688. function TEditor.CharPos(P, Target: Word): Integer;
  689. var
  690.   Pos: Integer;
  691. begin
  692.   Pos := 0;
  693.   while P < Target do
  694.   begin
  695.     if BufChar(P) = #9 then Pos := Pos or 7;
  696.     Inc(Pos);
  697.     Inc(P);
  698.   end;
  699.   CharPos := Pos;
  700. end;
  701.  
  702. function TEditor.CharPtr(P: Word; Target: Integer): Word;
  703. var
  704.   Pos: Integer;
  705. begin
  706.   Pos := 0;
  707.   while (Pos < Target) and (P < BufLen) and (BufChar(P) <> #13) do
  708.   begin
  709.     if BufChar(P) = #9 then Pos := Pos or 7;
  710.     Inc(Pos);
  711.     Inc(P);
  712.   end;
  713.   if Pos > Target then Dec(P);
  714.   CharPtr := P;
  715. end;
  716.  
  717. function TEditor.ClipCopy: Boolean;
  718. begin
  719.   ClipCopy := False;
  720.   if (Clipboard <> nil) and (Clipboard <> @Self) then
  721.   begin
  722.     ClipCopy := Clipboard^.InsertFrom(@Self);
  723.     Selecting := False;
  724.     Update(ufUpdate);
  725.   end;
  726. end;
  727.  
  728. procedure TEditor.ClipCut;
  729. begin
  730.   if ClipCopy then DeleteSelect;
  731. end;
  732.  
  733. procedure TEditor.ClipPaste;
  734. begin
  735.   if (Clipboard <> nil) and (Clipboard <> @Self) then InsertFrom(Clipboard);
  736. end;
  737.  
  738. procedure TEditor.ConvertEvent(var Event: TEvent);
  739. var
  740.   ShiftState: Byte absolute $40:$17;
  741.   Key: Word;
  742. begin
  743.   if Event.What = evKeyDown then
  744.   begin
  745.     if (ShiftState and $03 <> 0) and
  746.       (Event.ScanCode >= $47) and (Event.ScanCode <= $51) then
  747.       Event.CharCode := #0;
  748.     Key := Event.KeyCode;
  749.     if KeyState <> 0 then
  750.     begin
  751.       if (Lo(Key) >= $01) and (Lo(Key) <= $1A) then Inc(Key, $40);
  752.       if (Lo(Key) >= $61) and (Lo(Key) <= $7A) then Dec(Key, $20);
  753.     end;
  754.     Key := ScanKeyMap(KeyMap[KeyState], Key);
  755.     KeyState := 0;
  756.     if Key <> 0 then
  757.       if Hi(Key) = $FF then
  758.       begin
  759.         KeyState := Lo(Key);
  760.         ClearEvent(Event);
  761.       end else
  762.       begin
  763.         Event.What := evCommand;
  764.         Event.Command := Key;
  765.       end;
  766.   end;
  767. end;
  768.  
  769. function TEditor.CursorVisible: Boolean;
  770. begin
  771.   CursorVisible := (CurPos.Y >= Delta.Y) and (CurPos.Y < Delta.Y + Size.Y);
  772. end;
  773.  
  774. procedure TEditor.DeleteRange(StartPtr, EndPtr: Word; DelSelect: Boolean);
  775. begin
  776.   if HasSelection and DelSelect then DeleteSelect else
  777.   begin
  778.     SetSelect(CurPtr, EndPtr, True);
  779.     DeleteSelect;
  780.     SetSelect(StartPtr, CurPtr, False);
  781.     DeleteSelect;
  782.   end;
  783. end;
  784.  
  785. procedure TEditor.DeleteSelect;
  786. begin
  787.   InsertText(nil, 0, False);
  788. end;
  789.  
  790. procedure TEditor.DoneBuffer;
  791. begin
  792.   if Buffer <> nil then FreeMem(Buffer, BufSize);
  793. end;
  794.  
  795. procedure TEditor.DoSearchReplace;
  796. var
  797.   I: Word;
  798.   C: TPoint;
  799. begin
  800.   repeat
  801.     I := cmCancel;
  802.     if not Search(FindStr, EditorFlags) then
  803.     begin
  804.       if EditorFlags and (efReplaceAll + efDoReplace) <>
  805.           (efReplaceAll + efDoReplace) then
  806.         EditorDialog(edSearchFailed, nil)
  807.     end
  808.     else if EditorFlags and efDoReplace <> 0 then
  809.     begin
  810.       I := cmYes;
  811.       if EditorFlags and efPromptOnReplace <> 0 then
  812.       begin
  813.         MakeGlobal(Cursor, C);
  814.         I := EditorDialog(edReplacePrompt, Pointer(C));
  815.       end;
  816.       if I = cmYes then
  817.       begin
  818.         Lock;
  819.         InsertText(@ReplaceStr[1], Length(ReplaceStr), False);
  820.         TrackCursor(False);
  821.         Unlock;
  822.       end;
  823.     end;
  824.   until (I = cmCancel) or (EditorFlags and efReplaceAll = 0);
  825. end;
  826.  
  827. procedure TEditor.DoUpdate;
  828. begin
  829.   if UpdateFlags <> 0 then
  830.   begin
  831.     SetCursor(CurPos.X - Delta.X, CurPos.Y - Delta.Y);
  832.     if UpdateFlags and ufView <> 0 then DrawView else
  833.       if UpdateFlags and ufLine <> 0 then
  834.         DrawLines(CurPos.Y - Delta.Y, 1, LineStart(CurPtr));
  835.     if HScrollBar <> nil then
  836.       HScrollBar^.SetParams(Delta.X, 0, Limit.X - Size.X, Size.X div 2, 1);
  837.     if VScrollBar <> nil then
  838.       VScrollBar^.SetParams(Delta.Y, 0, Limit.Y - Size.Y, Size.Y - 1, 1);
  839.     if Indicator <> nil then Indicator^.SetValue(CurPos, Modified);
  840.     if State and sfActive <> 0 then UpdateCommands;
  841.     UpdateFlags := 0;
  842.   end;
  843. end;
  844.  
  845. procedure TEditor.Draw;
  846. begin
  847.   if DrawLine <> Delta.Y then
  848.   begin
  849.     DrawPtr := LineMove(DrawPtr, Delta.Y - DrawLine);
  850.     DrawLine := Delta.Y;
  851.   end;
  852.   DrawLines(0, Size.Y, DrawPtr);
  853. end;
  854.  
  855. procedure TEditor.DrawLines(Y, Count: Integer; LinePtr: Word);
  856. var
  857.   Color: Word;
  858.   B: array[0..MaxLineLength - 1] of Word;
  859. begin
  860.   Color := GetColor($0201);
  861.   while Count > 0 do
  862.   begin
  863.     FormatLine(B, LinePtr, Delta.X + Size.X, Color);
  864.     WriteBuf(0, Y, Size.X, 1, B[Delta.X]);
  865.     LinePtr := NextLine(LinePtr);
  866.     Inc(Y);
  867.     Dec(Count);
  868.   end;
  869. end;
  870.  
  871. procedure TEditor.Find;
  872. var
  873.   FindRec: TFindDialogRec;
  874. begin
  875.   with FindRec do
  876.   begin
  877.     Find := FindStr;
  878.     Options := EditorFlags;
  879.     if EditorDialog(edFind, @FindRec) <> cmCancel then
  880.     begin
  881.       FindStr := Find;
  882.       EditorFlags := Options and not efDoReplace;
  883.       DoSearchReplace;
  884.     end;
  885.   end;
  886. end;
  887.  
  888. procedure TEditor.FormatLine(var DrawBuf; LinePtr: Word;
  889.   Width: Integer; Colors: Word); assembler;
  890. asm
  891.     PUSH    DS
  892.     LDS    BX,Self
  893.     LES    DI,DrawBuf
  894.     MOV    SI,LinePtr
  895.     XOR    DX,DX
  896.     CLD
  897.     MOV    AH,Colors.Byte[0]
  898.     MOV    CX,DS:[BX].TEditor.SelStart
  899.     CALL    @@10
  900.     MOV    AH,Colors.Byte[1]
  901.     MOV    CX,DS:[BX].TEditor.CurPtr
  902.     CALL    @@10
  903.     ADD    SI,DS:[BX].TEditor.GapLen
  904.     MOV    CX,DS:[BX].TEditor.SelEnd
  905.     ADD    CX,DS:[BX].TEditor.GapLen
  906.     CALL    @@10
  907.     MOV    AH,Colors.Byte[0]
  908.     MOV    CX,DS:[BX].TEditor.BufSize
  909.     CALL    @@10
  910.     JMP    @@31
  911. @@10:    SUB    CX,SI
  912.     JA    @@11
  913.     RETN
  914. @@11:    LDS    BX,DS:[BX].TEditor.Buffer
  915.     ADD    SI,BX
  916.     MOV    BX,Width
  917. @@12:    LODSB
  918.     CMP    AL,' '
  919.     JB    @@20
  920. @@13:    STOSW
  921.     INC    DX
  922. @@14:    CMP    DX,BX
  923.     JAE    @@30
  924.     LOOP    @@12
  925.     LDS    BX,Self
  926.     SUB    SI,DS:[BX].TEditor.Buffer.Word[0]
  927.     RETN
  928. @@20:    CMP    AL,0DH
  929.     JE    @@30
  930.     CMP    AL,09H
  931.     JNE    @@13
  932.     MOV    AL,' '
  933. @@21:    STOSW
  934.     INC    DX
  935.     TEST    DL,7
  936.     JNE    @@21
  937.     JMP    @@14
  938. @@30:    POP    CX
  939. @@31:    MOV    AL,' '
  940.     MOV    CX,Width
  941.     SUB    CX,DX
  942.     JBE    @@32
  943.     REP    STOSW
  944. @@32:    POP    DS
  945. end;
  946.  
  947. function TEditor.GetMousePtr(Mouse: TPoint): Word;
  948. begin
  949.   MakeLocal(Mouse, Mouse);
  950.   Mouse.X := Max(0, Min(Mouse.X, Size.X - 1));
  951.   Mouse.Y := Max(0, Min(Mouse.Y, Size.Y - 1));
  952.   GetMousePtr := CharPtr(LineMove(DrawPtr, Mouse.Y + Delta.Y - DrawLine),
  953.     Mouse.X + Delta.X);
  954. end;
  955.  
  956. function TEditor.GetPalette: PPalette;
  957. const
  958.   P: String[Length(CEditor)] = CEditor;
  959. begin
  960.   GetPalette := @P;
  961. end;
  962.  
  963. procedure TEditor.HandleEvent(var Event: TEvent);
  964. var
  965.   ShiftState: Byte absolute $40:$17;
  966.   CenterCursor: Boolean;
  967.   SelectMode: Byte;
  968.   I: Integer;
  969.   NewPtr: Word;
  970.   D, Mouse: TPoint;
  971.  
  972. procedure CheckScrollBar(P: PScrollBar; var D: Integer);
  973. begin
  974.   if (Event.InfoPtr = P) and (P^.Value <> D) then
  975.   begin
  976.     D := P^.Value;
  977.     Update(ufView);
  978.   end;
  979. end;
  980.  
  981. begin
  982.   TView.HandleEvent(Event);
  983.   ConvertEvent(Event);
  984.   CenterCursor := not CursorVisible;
  985.   SelectMode := 0;
  986.   if Selecting or (ShiftState and $03 <> 0) then SelectMode := smExtend;
  987.   case Event.What of
  988.     evMouseDown:
  989.       begin
  990.         if Event.Double then SelectMode := SelectMode or smDouble;
  991.         repeat
  992.           Lock;
  993.           if Event.What = evMouseAuto then
  994.           begin
  995.             MakeLocal(Event.Where, Mouse);
  996.             D := Delta;
  997.             if Mouse.X < 0 then Dec(D.X);
  998.             if Mouse.X >= Size.X then Inc(D.X);
  999.             if Mouse.Y < 0 then Dec(D.Y);
  1000.             if Mouse.Y >= Size.Y then Inc(D.Y);
  1001.             ScrollTo(D.X, D.Y);
  1002.           end;
  1003.           SetCurPtr(GetMousePtr(Event.Where), SelectMode);
  1004.           SelectMode := SelectMode or smExtend;
  1005.           Unlock;
  1006.         until not MouseEvent(Event, evMouseMove + evMouseAuto);
  1007.       end;
  1008.     evKeyDown:
  1009.       case Event.CharCode of
  1010.         #9,#32..#255:
  1011.           begin
  1012.             Lock;
  1013.             if Overwrite and not HasSelection then
  1014.               if CurPtr <> LineEnd(CurPtr) then SelEnd := NextChar(CurPtr);
  1015.             InsertText(@Event.CharCode, 1, False);
  1016.             TrackCursor(CenterCursor);
  1017.             Unlock;
  1018.           end;
  1019.       else
  1020.         Exit;           
  1021.       end;
  1022.     evCommand:
  1023.       case Event.Command of
  1024.         cmFind: Find;
  1025.         cmReplace: Replace;
  1026.         cmSearchAgain: DoSearchReplace;
  1027.       else
  1028.         begin
  1029.           Lock;
  1030.           case Event.Command of
  1031.             cmCut: ClipCut;
  1032.             cmCopy: ClipCopy;
  1033.             cmPaste: ClipPaste;
  1034.             cmUndo: Undo;
  1035.             cmClear: DeleteSelect;
  1036.             cmCharLeft: SetCurPtr(PrevChar(CurPtr), SelectMode);
  1037.             cmCharRight: SetCurPtr(NextChar(CurPtr), SelectMode);
  1038.             cmWordLeft: SetCurPtr(PrevWord(CurPtr), SelectMode);
  1039.             cmWordRight: SetCurPtr(NextWord(CurPtr), SelectMode);
  1040.             cmLineStart: SetCurPtr(LineStart(CurPtr), SelectMode);
  1041.             cmLineEnd: SetCurPtr(LineEnd(CurPtr), SelectMode);
  1042.             cmLineUp: SetCurPtr(LineMove(CurPtr, -1), SelectMode);
  1043.             cmLineDown: SetCurPtr(LineMove(CurPtr, 1), SelectMode);
  1044.             cmPageUp: SetCurPtr(LineMove(CurPtr, -(Size.Y - 1)), SelectMode);
  1045.             cmPageDown: SetCurPtr(LineMove(CurPtr, Size.Y - 1), SelectMode);
  1046.             cmTextStart: SetCurPtr(0, SelectMode);
  1047.             cmTextEnd: SetCurPtr(BufLen, SelectMode);
  1048.             cmNewLine: NewLine;
  1049.             cmBackSpace: DeleteRange(PrevChar(CurPtr), CurPtr, True);
  1050.             cmDelChar: DeleteRange(CurPtr, NextChar(CurPtr), True);
  1051.             cmDelWord: DeleteRange(CurPtr, NextWord(CurPtr), False);
  1052.             cmDelStart: DeleteRange(LineStart(CurPtr), CurPtr, False);
  1053.             cmDelEnd: DeleteRange(CurPtr, LineEnd(CurPtr), False);
  1054.             cmDelLine: DeleteRange(LineStart(CurPtr), NextLine(CurPtr), False);
  1055.             cmInsMode: ToggleInsMode;
  1056.             cmStartSelect: StartSelect;
  1057.             cmHideSelect: HideSelect;
  1058.             cmIndentMode: AutoIndent := not AutoIndent;
  1059.           else
  1060.             Unlock;
  1061.             Exit;
  1062.           end;
  1063.           TrackCursor(CenterCursor);
  1064.           Unlock;
  1065.         end;
  1066.       end;
  1067.     evBroadcast:
  1068.       case Event.Command of
  1069.         cmScrollBarChanged:
  1070.           begin
  1071.             CheckScrollBar(HScrollBar, Delta.X);
  1072.             CheckScrollBar(VScrollBar, Delta.Y);
  1073.           end;
  1074.       else
  1075.         Exit;
  1076.       end;
  1077.   end;
  1078.   ClearEvent(Event);
  1079. end;
  1080.  
  1081. function TEditor.HasSelection: Boolean;
  1082. begin
  1083.   HasSelection := SelStart <> SelEnd;
  1084. end;
  1085.  
  1086. procedure TEditor.HideSelect;
  1087. begin
  1088.   Selecting := False;
  1089.   SetSelect(CurPtr, CurPtr, False);
  1090. end;
  1091.  
  1092. procedure TEditor.InitBuffer;
  1093. begin
  1094.   Buffer := MemAlloc(BufSize);
  1095. end;
  1096.  
  1097. function TEditor.InsertBuffer(var P: PEditBuffer; Offset, Length: Word;
  1098.   AllowUndo, SelectText: Boolean): Boolean;
  1099. var
  1100.   SelLen, DelLen, SelLines, Lines: Word;
  1101.   NewSize: Longint;
  1102. begin
  1103.   InsertBuffer := True;
  1104.   Selecting := False;
  1105.   SelLen := SelEnd - SelStart;
  1106.   if (SelLen = 0) and (Length = 0) then Exit;
  1107.   DelLen := 0;
  1108.   if AllowUndo then
  1109.     if CurPtr = SelStart then DelLen := SelLen else
  1110.       if SelLen > InsCount then DelLen := SelLen - InsCount;
  1111.   NewSize := Longint(BufLen + DelCount - SelLen + DelLen) + Length;
  1112.   if NewSize > BufLen + DelCount then
  1113.     if (NewSize > $FFF0) or not SetBufSize(NewSize) then
  1114.     begin
  1115.       EditorDialog(edOutOfMemory, nil);
  1116.       InsertBuffer := False;
  1117.       Exit;
  1118.     end;
  1119.   SelLines := CountLines(Buffer^[BufPtr(SelStart)], SelLen);
  1120.   if CurPtr = SelEnd then
  1121.   begin
  1122.     if AllowUndo then
  1123.     begin
  1124.       if DelLen > 0 then Move(Buffer^[SelStart],
  1125.         Buffer^[CurPtr + GapLen - DelCount - DelLen], DelLen);
  1126.       Dec(InsCount, SelLen - DelLen);
  1127.     end;
  1128.     CurPtr := SelStart;
  1129.     Dec(CurPos.Y, SelLines);
  1130.   end;
  1131.   if Delta.Y > CurPos.Y then
  1132.   begin
  1133.     Dec(Delta.Y, SelLines);
  1134.     if Delta.Y < CurPos.Y then Delta.Y := CurPos.Y;
  1135.   end;
  1136.   if Length > 0 then Move(P^[Offset], Buffer^[CurPtr], Length);
  1137.   Lines := CountLines(Buffer^[CurPtr], Length);
  1138.   Inc(CurPtr, Length);
  1139.   Inc(CurPos.Y, Lines);
  1140.   DrawLine := CurPos.Y;
  1141.   DrawPtr := LineStart(CurPtr);
  1142.   CurPos.X := CharPos(DrawPtr, CurPtr);
  1143.   if not SelectText then SelStart := CurPtr;
  1144.   SelEnd := CurPtr;
  1145.   Inc(BufLen, Length - SelLen);
  1146.   Dec(GapLen, Length - SelLen);
  1147.   if AllowUndo then
  1148.   begin
  1149.     Inc(DelCount, DelLen);
  1150.     Inc(InsCount, Length);
  1151.   end;
  1152.   Inc(Limit.Y, Lines - SelLines);
  1153.   Delta.Y := Max(0, Min(Delta.Y, Limit.Y - Size.Y));
  1154.   if not IsClipboard then Modified := True;
  1155.   SetBufSize(BufLen + DelCount);
  1156.   if (SelLines = 0) and (Lines = 0) then Update(ufLine) else Update(ufView);
  1157. end;
  1158.  
  1159. function TEditor.InsertFrom(Editor: PEditor): Boolean;
  1160. begin
  1161.   InsertFrom := InsertBuffer(Editor^.Buffer,
  1162.     Editor^.BufPtr(Editor^.SelStart),
  1163.     Editor^.SelEnd - Editor^.SelStart, CanUndo, IsClipboard);
  1164. end;
  1165.  
  1166. function TEditor.InsertText(Text: Pointer; Length: Word;
  1167.   SelectText: Boolean): Boolean;
  1168. begin
  1169.   InsertText := InsertBuffer(PEditBuffer(Text),
  1170.     0, Length, CanUndo, SelectText);
  1171. end;
  1172.  
  1173. function TEditor.IsClipboard: Boolean;
  1174. begin
  1175.   IsClipboard := Clipboard = @Self;
  1176. end;
  1177.  
  1178. function TEditor.LineEnd(P: Word): Word; assembler;
  1179. asm
  1180.     PUSH    DS
  1181.     LDS    SI,Self
  1182.     LES    BX,DS:[SI].TEditor.Buffer
  1183.     MOV    DI,P
  1184.     MOV    AL,0DH
  1185.     CLD
  1186.     MOV    CX,DS:[SI].TEditor.CurPtr
  1187.     SUB    CX,DI
  1188.     JBE    @@1
  1189.     ADD    DI,BX
  1190.     REPNE    SCASB
  1191.     JE    @@2
  1192.     MOV    DI,DS:[SI].TEditor.CurPtr
  1193. @@1:    MOV    CX,DS:[SI].TEditor.BufLen
  1194.     SUB    CX,DI
  1195.     JCXZ    @@4
  1196.     ADD    BX,DS:[SI].TEditor.GapLen
  1197.     ADD    DI,BX
  1198.     REPNE    SCASB
  1199.     JNE    @@3
  1200. @@2:    DEC    DI
  1201. @@3:    SUB    DI,BX
  1202. @@4:    MOV    AX,DI
  1203.     POP    DS
  1204. end;
  1205.  
  1206. function TEditor.LineMove(P: Word; Count: Integer): Word;
  1207. var
  1208.   Pos: Integer;
  1209.   I: Word;
  1210. begin
  1211.   I := P;
  1212.   P := LineStart(P);
  1213.   Pos := CharPos(P, I);
  1214.   while Count <> 0 do
  1215.   begin
  1216.     I := P;
  1217.     if Count < 0 then
  1218.     begin
  1219.       P := PrevLine(P);
  1220.       Inc(Count);
  1221.     end else
  1222.     begin
  1223.       P := NextLine(P);
  1224.       Dec(Count);
  1225.     end;
  1226.   end;
  1227.   if P <> I then P := CharPtr(P, Pos);
  1228.   LineMove := P;
  1229. end;
  1230.  
  1231. function TEditor.LineStart(P: Word): Word; assembler;
  1232. asm
  1233.     PUSH    DS
  1234.     LDS    SI,Self
  1235.     LES    BX,DS:[SI].TEditor.Buffer
  1236.     MOV    DI,P
  1237.     MOV    AL,0DH
  1238.     STD
  1239.     MOV    CX,DI
  1240.     SUB    CX,DS:[SI].TEditor.CurPtr
  1241.     JBE    @@1
  1242.         ADD    BX,DS:[SI].TEditor.GapLen
  1243.     ADD    DI,BX
  1244.     DEC    DI
  1245.     REPNE    SCASB
  1246.     JE    @@2
  1247.     SUB    BX,DS:[SI].TEditor.GapLen
  1248.     MOV    DI,DS:[SI].TEditor.CurPtr
  1249. @@1:    MOV    CX,DI
  1250.     JCXZ    @@4
  1251.     ADD    DI,BX
  1252.     DEC    DI
  1253.     REPNE    SCASB
  1254.     JNE    @@3
  1255. @@2:    INC    DI
  1256.     INC    DI
  1257.     SUB    DI,BX
  1258.     CMP    DI,DS:[SI].TEditor.CurPtr
  1259.     JE    @@4
  1260.     CMP    DI,DS:[SI].TEditor.BufLen
  1261.     JE    @@4
  1262.     CMP    ES:[BX+DI].Byte,0AH
  1263.     JNE    @@4
  1264.     INC    DI
  1265.     JMP    @@4
  1266. @@3:    XOR    DI,DI
  1267. @@4:    MOV    AX,DI
  1268.     POP    DS
  1269. end;
  1270.  
  1271. procedure TEditor.Lock;
  1272. begin
  1273.   Inc(LockCount);
  1274. end;
  1275.  
  1276. procedure TEditor.NewLine;
  1277. const
  1278.   CrLf: array[1..2] of Char = #13#10;
  1279. var
  1280.   I, P: Word;
  1281. begin
  1282.   P := LineStart(CurPtr);
  1283.   I := P;
  1284.   while (I < CurPtr) and ((Buffer^[I] = ' ') or (Buffer^[I] = #9)) do Inc(I);
  1285.   InsertText(@CrLf, 2, False);
  1286.   if AutoIndent then InsertText(@Buffer^[P], I - P, False);
  1287. end;
  1288.  
  1289. function TEditor.NextChar(P: Word): Word; assembler;
  1290. asm
  1291.     PUSH    DS
  1292.     LDS    SI,Self
  1293.     MOV    DI,P
  1294.     CMP    DI,DS:[SI].TEditor.BufLen
  1295.     JE    @@2
  1296.     INC    DI
  1297.     CMP    DI,DS:[SI].TEditor.BufLen
  1298.     JE    @@2
  1299.     LES    BX,DS:[SI].TEditor.Buffer
  1300.     CMP    DI,DS:[SI].TEditor.CurPtr
  1301.     JB    @@1
  1302.     ADD    BX,DS:[SI].TEditor.GapLen
  1303. @@1:    CMP    ES:[BX+DI-1].Word,0A0DH
  1304.     JNE    @@2
  1305.     INC    DI
  1306. @@2:    MOV    AX,DI
  1307.     POP    DS
  1308. end;
  1309.  
  1310. function TEditor.NextLine(P: Word): Word;
  1311. begin
  1312.   NextLine := NextChar(LineEnd(P));
  1313. end;
  1314.  
  1315. function TEditor.NextWord(P: Word): Word;
  1316. begin
  1317.   while (P < BufLen) and (BufChar(P) in WordChars) do
  1318.     P := NextChar(P);
  1319.   while (P < BufLen) and not (BufChar(P) in WordChars) do
  1320.     P := NextChar(P);
  1321.   NextWord := P;
  1322. end;
  1323.  
  1324. function TEditor.PrevChar(P: Word): Word; assembler;
  1325. asm
  1326.     PUSH    DS
  1327.     LDS    SI,Self
  1328.     MOV    DI,P
  1329.     OR    DI,DI
  1330.     JE    @@2
  1331.     DEC    DI
  1332.     JE    @@2
  1333.     LES    BX,DS:[SI].TEditor.Buffer
  1334.     CMP    DI,DS:[SI].TEditor.CurPtr
  1335.     JB    @@1
  1336.     ADD    BX,DS:[SI].TEditor.GapLen
  1337. @@1:    CMP    ES:[BX+DI-1].Word,0A0DH
  1338.     JNE    @@2
  1339.     DEC    DI
  1340. @@2:    MOV    AX,DI
  1341.     POP    DS
  1342. end;
  1343.  
  1344. function TEditor.PrevLine(P: Word): Word;
  1345. begin
  1346.   PrevLine := LineStart(PrevChar(P));
  1347. end;
  1348.  
  1349. function TEditor.PrevWord(P: Word): Word;
  1350. begin
  1351.   while (P > 0) and not (BufChar(PrevChar(P)) in WordChars) do
  1352.     P := PrevChar(P);
  1353.   while (P > 0) and (BufChar(PrevChar(P)) in WordChars) do
  1354.     P := PrevChar(P);
  1355.   PrevWord := P;
  1356. end;
  1357.  
  1358. procedure TEditor.Replace;
  1359. var
  1360.   ReplaceRec: TReplaceDialogRec;
  1361. begin
  1362.   with ReplaceRec do
  1363.   begin
  1364.     Find := FindStr;
  1365.     Replace := ReplaceStr;
  1366.     Options := EditorFlags;
  1367.     if EditorDialog(edReplace, @ReplaceRec) <> cmCancel then
  1368.     begin
  1369.       FindStr := Find;
  1370.       ReplaceStr := Replace;
  1371.       EditorFlags := Options or efDoReplace;
  1372.       DoSearchReplace;
  1373.     end;
  1374.   end;
  1375. end;
  1376.  
  1377. procedure TEditor.ScrollTo(X, Y: Integer);
  1378. begin
  1379.   X := Max(0, Min(X, Limit.X - Size.X));
  1380.   Y := Max(0, Min(Y, Limit.Y - Size.Y));
  1381.   if (X <> Delta.X) or (Y <> Delta.Y) then
  1382.   begin
  1383.     Delta.X := X;
  1384.     Delta.Y := Y;
  1385.     Update(ufView);
  1386.   end;
  1387. end;
  1388.  
  1389. function TEditor.Search(FindStr: String; Opts: Word): Boolean;
  1390. var
  1391.   I, Pos: Word;
  1392. begin
  1393.   Search := False;
  1394.   Pos := CurPtr;
  1395.   repeat
  1396.     if Opts and efCaseSensitive <> 0 then
  1397.       I := Scan(Buffer^[BufPtr(Pos)], BufLen - Pos, FindStr)
  1398.     else I := IScan(Buffer^[BufPtr(Pos)], BufLen - Pos, FindStr);
  1399.     if (I <> sfSearchFailed) then
  1400.     begin
  1401.       Inc(I, Pos);
  1402.       if (Opts and efWholeWordsOnly = 0) or
  1403.          not (((I <> 0) and (BufChar(I - 1) in WordChars)) or
  1404.               ((I + Length(FindStr) <> BufLen) and
  1405.                (BufChar(I + Length(FindStr)) in WordChars))) then
  1406.       begin
  1407.         Lock;
  1408.         SetSelect(I, I + Length(FindStr), False);
  1409.         TrackCursor(not CursorVisible);
  1410.         Unlock;
  1411.         Search := True;
  1412.         Exit;
  1413.       end else Pos := I + 1;
  1414.     end;
  1415.   until I = sfSearchFailed;
  1416. end;
  1417.  
  1418. procedure TEditor.SetBufLen(Length: Word);
  1419. begin
  1420.   BufLen := Length;
  1421.   GapLen := BufSize - Length;
  1422.   SelStart := 0;
  1423.   SelEnd := 0;
  1424.   CurPtr := 0;
  1425.   Longint(CurPos) := 0;
  1426.   Longint(Delta) := 0;
  1427.   Limit.X := MaxLineLength;
  1428.   Limit.Y := CountLines(Buffer^[GapLen], BufLen) + 1;
  1429.   DrawLine := 0;
  1430.   DrawPtr := 0;
  1431.   DelCount := 0;
  1432.   InsCount := 0;
  1433.   Modified := False;
  1434.   Update(ufView);
  1435. end;
  1436.  
  1437. function TEditor.SetBufSize(NewSize: Word): Boolean;
  1438. begin
  1439.   SetBufSize := NewSize <= BufSize;
  1440. end;
  1441.  
  1442. procedure TEditor.SetCmdState(Command: Word; Enable: Boolean);
  1443. var
  1444.   S: TCommandSet;
  1445. begin
  1446.   S := [Command];
  1447.   if Enable and (State and sfActive <> 0) then
  1448.     EnableCommands(S) else DisableCommands(S);
  1449. end;
  1450.  
  1451. procedure TEditor.SetCurPtr(P: Word; SelectMode: Byte);
  1452. var
  1453.   Anchor: Word;
  1454. begin
  1455.   if SelectMode and smExtend = 0 then Anchor := P else
  1456.     if CurPtr = SelStart then Anchor := SelEnd else Anchor := SelStart;
  1457.   if P < Anchor then
  1458.   begin
  1459.     if SelectMode and smDouble <> 0 then
  1460.     begin
  1461.       P := PrevLine(NextLine(P));
  1462.       Anchor := NextLine(PrevLine(Anchor));
  1463.     end;
  1464.     SetSelect(P, Anchor, True);
  1465.   end else
  1466.   begin
  1467.     if SelectMode and smDouble <> 0 then
  1468.     begin
  1469.       P := NextLine(P);
  1470.       Anchor := PrevLine(NextLine(Anchor));
  1471.     end;
  1472.     SetSelect(Anchor, P, False);
  1473.   end;
  1474. end;
  1475.  
  1476. procedure TEditor.SetSelect(NewStart, NewEnd: Word; CurStart: Boolean);
  1477. var
  1478.   Flags: Byte;
  1479.   P, L: Word;
  1480. begin
  1481.   if CurStart then P := NewStart else P := NewEnd;
  1482.   Flags := ufUpdate;
  1483.   if (NewStart <> SelStart) or (NewEnd <> SelEnd) then
  1484.     if (NewStart <> NewEnd) or (SelStart <> SelEnd) then
  1485.       Flags := ufView;
  1486.   if P <> CurPtr then
  1487.   begin
  1488.     if P > CurPtr then
  1489.     begin
  1490.       L := P - CurPtr;
  1491.       Move(Buffer^[CurPtr + GapLen], Buffer^[CurPtr], L);
  1492.       Inc(CurPos.Y, CountLines(Buffer^[CurPtr], L));
  1493.       CurPtr := P;
  1494.     end else
  1495.     begin
  1496.       L := CurPtr - P;
  1497.       CurPtr := P;
  1498.       Dec(CurPos.Y, CountLines(Buffer^[CurPtr], L));
  1499.       Move(Buffer^[CurPtr], Buffer^[CurPtr + GapLen], L);
  1500.     end;
  1501.     DrawLine := CurPos.Y;
  1502.     DrawPtr := LineStart(P);
  1503.     CurPos.X := CharPos(DrawPtr, P);
  1504.     DelCount := 0;
  1505.     InsCount := 0;
  1506.     SetBufSize(BufLen);
  1507.   end;
  1508.   SelStart := NewStart;
  1509.   SelEnd := NewEnd;
  1510.   Update(Flags);
  1511. end;
  1512.  
  1513. procedure TEditor.SetState(AState: Word; Enable: Boolean);
  1514. begin
  1515.   TView.SetState(AState, Enable);
  1516.   case AState of
  1517.     sfActive:
  1518.       begin
  1519.         if HScrollBar <> nil then HScrollBar^.SetState(sfVisible, Enable);
  1520.         if VScrollBar <> nil then VScrollBar^.SetState(sfVisible, Enable);
  1521.         if Indicator <> nil then Indicator^.SetState(sfVisible, Enable);
  1522.         UpdateCommands;
  1523.       end;
  1524.     sfExposed:
  1525.       if Enable then Unlock;
  1526.   end;
  1527. end;
  1528.  
  1529. procedure TEditor.StartSelect;
  1530. begin
  1531.   HideSelect;
  1532.   Selecting := True;
  1533. end;
  1534.  
  1535. procedure TEditor.Store(var S: TStream);
  1536. begin
  1537.   TView.Store(S);
  1538.   PutPeerViewPtr(S, HScrollBar);
  1539.   PutPeerViewPtr(S, VScrollBar);
  1540.   PutPeerViewPtr(S, Indicator);
  1541.   S.Write(BufSize, SizeOf(Word));
  1542.   S.Write(CanUndo, SizeOf(Boolean));
  1543. end;
  1544.  
  1545. procedure TEditor.ToggleInsMode;
  1546. begin
  1547.   Overwrite := not Overwrite;
  1548.   SetState(sfCursorIns, not GetState(sfCursorIns));
  1549. end;
  1550.  
  1551. procedure TEditor.TrackCursor(Center: Boolean);
  1552. begin
  1553.   if Center then
  1554.     ScrollTo(CurPos.X - Size.X + 1, CurPos.Y - Size.Y div 2) else
  1555.     ScrollTo(Max(CurPos.X - Size.X + 1, Min(Delta.X, CurPos.X)),
  1556.       Max(CurPos.Y - Size.Y + 1, Min(Delta.Y, CurPos.Y)));
  1557. end;
  1558.  
  1559. procedure TEditor.Undo;
  1560. var
  1561.   Length: Word;
  1562. begin
  1563.   if (DelCount <> 0) or (InsCount <> 0) then
  1564.   begin
  1565.     SelStart := CurPtr - InsCount;
  1566.     SelEnd := CurPtr;
  1567.     Length := DelCount;
  1568.     DelCount := 0;
  1569.     InsCount := 0;
  1570.     InsertBuffer(Buffer, CurPtr + GapLen - Length, Length, False, True);
  1571.   end;
  1572. end;
  1573.  
  1574. procedure TEditor.Unlock;
  1575. begin
  1576.   if LockCount > 0 then
  1577.   begin
  1578.     Dec(LockCount);
  1579.     if LockCount = 0 then DoUpdate;
  1580.   end;
  1581. end;
  1582.  
  1583. procedure TEditor.Update(AFlags: Byte);
  1584. begin
  1585.   UpdateFlags := UpdateFlags or AFlags;
  1586.   if LockCount = 0 then DoUpdate;
  1587. end;
  1588.  
  1589. procedure TEditor.UpdateCommands;
  1590. begin
  1591.   SetCmdState(cmUndo, (DelCount <> 0) or (InsCount <> 0));
  1592.   if not IsClipboard then
  1593.   begin
  1594.     SetCmdState(cmCut, HasSelection);
  1595.     SetCmdState(cmCopy, HasSelection);
  1596.     SetCmdState(cmPaste, (Clipboard <> nil) and (Clipboard^.HasSelection));
  1597.   end;
  1598.   SetCmdState(cmClear, HasSelection);
  1599.   SetCmdState(cmFind, True);
  1600.   SetCmdState(cmReplace, True);
  1601.   SetCmdState(cmSearchAgain, True);
  1602. end;
  1603.  
  1604. function TEditor.Valid(Command: Word): Boolean;
  1605. begin
  1606.   Valid := IsValid;
  1607. end;
  1608.  
  1609. { TMemo }
  1610.  
  1611. constructor TMemo.Load(var S: TStream);
  1612. var
  1613.   Length: Word;
  1614. begin
  1615.   TEditor.Load(S);
  1616.   S.Read(Length, SizeOf(Word));
  1617.   if IsValid then
  1618.   begin
  1619.     S.Read(Buffer^[BufSize - Length], Length);
  1620.     SetBufLen(Length);
  1621.   end
  1622.   else S.Seek(S.GetPos + Length);
  1623. end;
  1624.  
  1625. function TMemo.DataSize: Word;
  1626. begin
  1627.   DataSize := BufSize + SizeOf(Word);
  1628. end;
  1629.  
  1630. procedure TMemo.GetData(var Rec);
  1631. var
  1632.   Data: TMemoData absolute Rec;
  1633. begin
  1634.   Data.Length := BufLen;
  1635.   Move(Buffer^, Data.Buffer, CurPtr);
  1636.   Move(Buffer^[CurPtr + GapLen], Data.Buffer[CurPtr], BufLen - CurPtr);
  1637.   FillChar(Data.Buffer[BufLen], BufSize - BufLen, 0);
  1638. end;
  1639.  
  1640. function TMemo.GetPalette: PPalette;
  1641. const
  1642.   P: String[Length(CMemo)] = CMemo;
  1643. begin
  1644.   GetPalette := @P;
  1645. end;
  1646.  
  1647. procedure TMemo.HandleEvent(var Event: TEvent);
  1648. begin
  1649.   if (Event.What <> evKeyDown) or (Event.KeyCode <> kbTab) then
  1650.     TEditor.HandleEvent(Event);
  1651. end;
  1652.  
  1653. procedure TMemo.SetData(var Rec);
  1654. var
  1655.   Data: TMemoData absolute Rec;
  1656. begin
  1657.   Move(Data.Buffer, Buffer^[BufSize - Data.Length], Data.Length);
  1658.   SetBufLen(Data.Length);
  1659. end;
  1660.  
  1661. procedure TMemo.Store(var S: TStream);
  1662. begin
  1663.   TEditor.Store(S);
  1664.   S.Write(BufLen, SizeOf(Word));
  1665.   S.Write(Buffer^, CurPtr);
  1666.   S.Write(Buffer^[CurPtr + GapLen], BufLen - CurPtr);
  1667. end;
  1668.  
  1669. { TFileEditor }
  1670.  
  1671. constructor TFileEditor.Init(var Bounds: TRect;
  1672.   AHScrollBar, AVScrollBar: PScrollBar;
  1673.   AIndicator: PIndicator; AFileName: FNameStr);
  1674. begin
  1675.   TEditor.Init(Bounds, AHScrollBar, AVScrollBar, AIndicator, 0);
  1676.   if AFileName <> '' then
  1677.   begin
  1678.     FileName := FExpand(AFileName);
  1679.     if IsValid then IsValid := LoadFile;
  1680.   end;
  1681. end;
  1682.  
  1683. constructor TFileEditor.Load(var S: TStream);
  1684. var
  1685.   SStart, SEnd, Curs: Word;
  1686. begin
  1687.   TEditor.Load(S);
  1688.   S.Read(FileName[0], SizeOf(Char));
  1689.   S.Read(Filename[1], Length(FileName));
  1690.   if IsValid then IsValid := LoadFile;
  1691.   S.Read(SStart, SizeOf(Word));
  1692.   S.Read(SEnd, SizeOf(Word));
  1693.   S.Read(Curs, SizeOf(Word));
  1694.   if IsValid and (SEnd <= BufLen) then
  1695.   begin
  1696.     SetSelect(SStart, SEnd, Curs = SStart);
  1697.     TrackCursor(True);
  1698.   end;
  1699. end;
  1700.  
  1701. procedure TFileEditor.DoneBuffer;
  1702. begin
  1703.   if Buffer <> nil then DisposeBuffer(Buffer);
  1704. end;
  1705.  
  1706. procedure TFileEditor.HandleEvent(var Event: TEvent);
  1707. begin
  1708.   TEditor.HandleEvent(Event);
  1709.   case Event.What of
  1710.     evCommand:
  1711.       case Event.Command of
  1712.         cmSave: Save;
  1713.         cmSaveAs: SaveAs;
  1714.       else
  1715.         Exit;
  1716.       end;
  1717.   else
  1718.     Exit;
  1719.   end;
  1720.   ClearEvent(Event);
  1721. end;
  1722.  
  1723. procedure TFileEditor.InitBuffer;
  1724. begin
  1725.   NewBuffer(Pointer(Buffer));
  1726. end;
  1727.  
  1728. function TFileEditor.LoadFile: Boolean;
  1729. var
  1730.   Length: Word;
  1731.   FSize: Longint;
  1732.   F: File;
  1733. begin
  1734.   LoadFile := False;
  1735.   Length := 0;
  1736.   Assign(F, FileName);
  1737.   Reset(F, 1);
  1738.   if IOResult <> 0 then LoadFile := True else
  1739.   begin
  1740.     FSize := FileSize(F);
  1741.     if (FSize > $FFF0) or not SetBufSize(Word(FSize)) then
  1742.       EditorDialog(edOutOfMemory, nil) else
  1743.     begin
  1744.       BlockRead(F, Buffer^[BufSize - Word(FSize)], FSize);
  1745.       if IOResult <> 0 then EditorDialog(edReadError, @FileName) else
  1746.       begin
  1747.         LoadFile := True;
  1748.         Length := FSize;
  1749.       end;
  1750.     end;
  1751.     Close(F);
  1752.   end;
  1753.   SetBufLen(Length);
  1754. end;
  1755.  
  1756. function TFileEditor.Save: Boolean;
  1757. begin
  1758.   if FileName = '' then Save := SaveAs else Save := SaveFile;
  1759. end;
  1760.  
  1761. function TFileEditor.SaveAs: Boolean;
  1762. begin
  1763.   SaveAs := False;
  1764.   if EditorDialog(edSaveAs, @FileName) <> cmCancel then
  1765.   begin
  1766.     FileName := FExpand(FileName);
  1767.     Message(Owner, evBroadcast, cmUpdateTitle, nil);
  1768.     SaveAs := SaveFile;
  1769.     if IsClipboard then FileName := '';
  1770.   end;
  1771. end;
  1772.  
  1773. function TFileEditor.SaveFile: Boolean;
  1774. var
  1775.   F: File;
  1776.   BackupName: FNameStr;
  1777.   D: DirStr;
  1778.   N: NameStr;
  1779.   E: ExtStr;
  1780. begin
  1781.   SaveFile := False;
  1782.   if EditorFlags and efBackupFiles <> 0 then
  1783.   begin
  1784.     FSplit(FileName, D, N, E);
  1785.     BackupName := D + N + '.BAK';
  1786.     Assign(F, BackupName);
  1787.     Erase(F);
  1788.     Assign(F, FileName);
  1789.     Rename(F, BackupName);
  1790.     InOutRes := 0;
  1791.   end;
  1792.   Assign(F, FileName);
  1793.   Rewrite(F, 1);
  1794.   if IOResult <> 0 then EditorDialog(edCreateError, @FileName) else
  1795.   begin
  1796.     BlockWrite(F, Buffer^, CurPtr);
  1797.     BlockWrite(F, Buffer^[CurPtr + GapLen], BufLen - CurPtr);
  1798.     if IOResult <> 0 then EditorDialog(edWriteError, @FileName) else
  1799.     begin
  1800.       Modified := False;
  1801.       Update(ufUpdate);
  1802.       SaveFile := True;
  1803.     end;
  1804.     Close(F);
  1805.   end;
  1806. end;
  1807.  
  1808. function TFileEditor.SetBufSize(NewSize: Word): Boolean;
  1809. var
  1810.   N: Word;
  1811. begin
  1812.   SetBufSize := False;
  1813.   if NewSize > $F000 then NewSize := $FFF0 else
  1814.     NewSize := (NewSize + $0FFF) and $F000;
  1815.   if NewSize <> BufSize then
  1816.   begin
  1817.     if NewSize > BufSize then
  1818.       if not SetBufferSize(Buffer, NewSize) then Exit;
  1819.     N := BufLen - CurPtr + DelCount;
  1820.     Move(Buffer^[BufSize - N], Buffer^[NewSize - N], N);
  1821.     if NewSize < BufSize then SetBufferSize(Buffer, NewSize);
  1822.     BufSize := NewSize;
  1823.     GapLen := BufSize - BufLen;
  1824.   end;
  1825.   SetBufSize := True;
  1826. end;
  1827.  
  1828. procedure TFileEditor.Store(var S: TStream);
  1829. begin
  1830.   TEditor.Store(S);
  1831.   S.Write(FileName, Length(FileName) + 1);
  1832.   S.Write(SelStart, SizeOf(Word) * 3);
  1833. end;
  1834.  
  1835. procedure TFileEditor.UpdateCommands;
  1836. begin
  1837.   TEditor.UpdateCommands;
  1838.   SetCmdState(cmSave, True);
  1839.   SetCmdState(cmSaveAs, True);
  1840. end;
  1841.  
  1842. function TFileEditor.Valid(Command: Word): Boolean;
  1843. var
  1844.   D: Integer;
  1845. begin
  1846.   if Command = cmValid then Valid := IsValid else
  1847.   begin
  1848.     Valid := True;
  1849.     if Modified then
  1850.     begin
  1851.       if FileName = '' then D := edSaveUntitled else D := edSaveModify;
  1852.       case EditorDialog(D, @FileName) of
  1853.         cmYes: Valid := Save;
  1854.         cmNo: Modified := False;
  1855.         cmCancel: Valid := False;
  1856.       end;
  1857.     end;
  1858.   end;
  1859. end;
  1860.  
  1861. { TEditWindow }
  1862.  
  1863. constructor TEditWindow.Init(var Bounds: TRect;
  1864.   FileName: FNameStr; ANumber: Integer);
  1865. var
  1866.   HScrollBar, VScrollBar: PScrollBar;
  1867.   Indicator: PIndicator;
  1868.   R: TRect;
  1869. begin
  1870.   TWindow.Init(Bounds, '', ANumber);
  1871.   Options := Options or ofTileable;
  1872.   R.Assign(18, Size.Y - 1, Size.X - 2, Size.Y);
  1873.   HScrollBar := New(PScrollBar, Init(R));
  1874.   HScrollBar^.Hide;
  1875.   Insert(HScrollBar);
  1876.   R.Assign(Size.X - 1, 1, Size.X, Size.Y - 1);
  1877.   VScrollBar := New(PScrollBar, Init(R));
  1878.   VScrollBar^.Hide;
  1879.   Insert(VScrollBar);
  1880.   R.Assign(2, Size.Y - 1, 16, Size.Y);
  1881.   Indicator := New(PIndicator, Init(R));
  1882.   Indicator^.Hide;
  1883.   Insert(Indicator);
  1884.   GetExtent(R);
  1885.   R.Grow(-1, -1);
  1886.   Editor := New(PFileEditor, Init(
  1887.     R, HScrollBar, VScrollBar, Indicator, FileName));
  1888.   Insert(Editor);
  1889. end;
  1890.  
  1891. constructor TEditWindow.Load(var S: TStream);
  1892. begin
  1893.   TWindow.Load(S);
  1894.   GetSubViewPtr(S, Editor);
  1895. end;
  1896.  
  1897. procedure TEditWindow.Close;
  1898. begin
  1899.   if Editor^.IsClipboard then Hide else TWindow.Close;
  1900. end;
  1901.  
  1902. function TEditWindow.GetTitle(MaxSize: Integer): TTitleStr;
  1903. begin
  1904.   if Editor^.IsClipboard then GetTitle := 'Clipboard' else
  1905.     if Editor^.FileName = '' then GetTitle := 'Untitled' else
  1906.       GetTitle := Editor^.FileName;
  1907. end;
  1908.  
  1909. procedure TEditWindow.HandleEvent(var Event: TEvent);
  1910. begin
  1911.   TWindow.HandleEvent(Event);
  1912.   if (Event.What = evBroadcast) and (Event.Command = cmUpdateTitle) then
  1913.   begin
  1914.     Frame^.DrawView;
  1915.     ClearEvent(Event);
  1916.   end;
  1917. end;
  1918.  
  1919. procedure TEditWindow.Store(var S: TStream);
  1920. begin
  1921.   TWindow.Store(S);
  1922.   PutSubViewPtr(S, Editor);
  1923. end;
  1924.  
  1925. procedure RegisterEditors;
  1926. begin
  1927.   RegisterType(REditor);
  1928.   RegisterType(RMemo);
  1929.   RegisterType(RFileEditor);
  1930.   RegisterType(RIndicator);
  1931.   RegisterType(REditWindow);
  1932. end;
  1933.  
  1934. end.
  1935.