home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / vp21beta.zip / ATVSRC.RAR / EDITORS.PAS < prev    next >
Pascal/Delphi Source File  |  2000-08-15  |  56KB  |  2,106 lines

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