返回
{***************************************************************}
{***               FVision Unit Version1.0                   ***}
{***                    蓝蚂蚁工作室                         ***}
{***************************************************************}
{***                     编辑器单元                          ***}
{***************************************************************}
{$O+,F+,X+,I-}
Unit FEdit;
Interface
Uses
  Dos,FXmsDrv,Graph,FGraph,FView,FWrite,FTool,
  FMouse,FEvent,FDialog,FControl,FExtDrv;

Const
  edHScroll     = $0001;
  edVScroll     = $0002;
  edViewerPos   = $0004;
  edProgress    = $0008;
  edBroad       = $0010;
  edUseXms      = $0020;

Const
  edTxtColor    :Byte=$9E;
  edSigColor    :Byte=$F1;
  edMakColor    :Byte=$04;

Const
  fiSearch      = $01;
  fiReplace     = $02;

Type
  PInsStatus=^TInsStatus;
  TInsStatus=Object(TView)
   Constructor Init;
   Procedure Paint;virtual;
   Procedure UpDate;virtual;
  end;

  PViewerPos=^TViewerPos;
  TViewerPos=object(TView)
   PosX,PosY:Integer;
   ModifyFlag:Boolean;
   Constructor Init(X,Y,PX,PY:Integer);
   Procedure Paint;virtual;
   Procedure Draw;virtual;
   Procedure Modify(M:Boolean;PX,PY:Integer);
  end;

  ViewLine=record
    Str:StringStrLong;
    Col:ColType;
  end;
  ViewType=array[1..1]of ViewLine;

  PLineItem = ^TLineItem;
  TLineItem = record
    Next : PLineItem;
    Str  : Stringstrlong;
  end;

  PViewer = ^TViewer;
  TViewer = object(TView)
   Style:Word;
   HScrollBar: PScrollBar;
   VScrollBar: PScrollBar;
   ViewPos: PViewerPos;
   Progress: PProgressBar;
   Head:PLineItem;
   View:^ViewType;
   XmsHandle:Word;
   Width,Height,LineNum,OldLineNum,
   StaLine,TotLine:Integer;
   Pos,Mark:TPoint;
   TColor,SColor,MColor:Byte;
   FileName:PathStr;
   ModifyFlag,CtrlkFlag,ReplaceFlag:Boolean;
   SPos,EPos:TPoint;
   CurPos,EndPos,CurMark:Integer;
   FindMode:Byte;
   Constructor Init(R:TRect;St:Word);
   Destructor Done;virtual;
   Procedure InsertScroll(H,V:PScrollBar);
   Procedure DeleteScroll;
   Procedure MoveTo(X,Y:Integer);virtual;
   Procedure ChangeBroad(X,Y:Integer);virtual;
   Procedure Paint;virtual;
   Procedure Draw;virtual;
   Procedure DrawLine(Num:Integer);virtual;
   Procedure DrawMark;
   Procedure SetView;virtual;
   Procedure SetViewLine(Num:Integer);virtual;
   Procedure SetViewColor(Num:Integer);virtual;
   Procedure SetScroll;
   Function  MoveMark(Shift:Boolean;X,Y:Integer):Boolean;
   Function  MoveView(Shift,Chk:Boolean;X,Y:Integer):Boolean;
   Procedure HandleMouse(var Event:TEvent);
   Procedure HandleEvent(var Event:TEvent);virtual;
   Procedure InitBuf;
   Procedure InitLine;
   Procedure FreeBuf;
   Procedure FreeLine;
   Function  InsertLine(Num:Integer;Str:string):Boolean;
   Function  DeleteLine(Num:Integer):Boolean;
   Function  Insert(Str:string):Boolean;
   Function  GetLine(Num:Integer):string;
   Procedure ModifyLine(Num:Integer;Str:string);
   Procedure DeleteBlock;
   Procedure LoadFromXms;
   Procedure StoreToXms;
   Procedure LoadFromFile(Name:PathStr);
   Procedure ConvTab(var S:string);
   Procedure SaveFile;
   Procedure SaveToFile(Name:PathStr);
   Procedure ProCtrlKB;
   Procedure ProCtrlKK;
   Function  ProShift(Shift:Boolean;X,Y:Integer):Boolean;
   Procedure CopyToClip(var P:PViewer);
   Procedure PasteFromClip(var P:PViewer);
   Function  MsgDlg(T,S:string;Sty:Word):Boolean;
   Function  RunView(V:PView;Event:TEvent):Boolean;
   Function  Search(Mode:Byte):Boolean;
   Function  Find(Mode:Byte):Boolean;
   Function  SearchAgain:Boolean;
   Procedure ReplaceAll;
  end;

  PEditor = ^TEditor;
  TEditor = object(TViewer)
   CanEdit:Boolean;
   Constructor Init(R:TRect;St:Word);
   Procedure CloseSelf;virtual;
   Procedure HandleEvent(var Event:TEvent);virtual;
   Procedure ProChar(Ch:Char);
   Procedure ProEnter;
   Procedure ProDel;
   Procedure ProBackSpace;
   Procedure ProCtrlKC;
   Procedure ProCtrlKV;
   Procedure ProPaste;
   Procedure ProCut;
  end;

  PFileViewer=^TFileViewer;
  TFileViewer=object(TWindow)
   Viewer:PViewer;
   Constructor Init(R:TRect;Name:string);
   Procedure LoadFromFile(Name:PathStr);
  end;

  PFileEditor=^TFileEditor;
  TFileEditor=object(TWindow)
   Editor:PEditor;
   Constructor Init(R:TRect;Name:string);
   Procedure SaveToFile(Name:PathStr);
   Procedure SaveFile;
   Procedure LoadFromFile(Name:PathStr);
  end;

var
  InsStatus:PInsStatus;

Function FindWin:PWindow;
Function ReplaceWin:PWindow;
Function GotoLineWin(var L:Integer):PWindow;
Function SetupEditEnv:PWindow;
Function SetEditColor:PWindow;
Implementation
Const
  NormalXmsSize = 300;
  MaxLine       = 30000;
  BufLine       = 500;
  MaxBufLine    = 800;

Const
  fiForward   = $01;
  fiBackward  = $02;
  fiCursor    = $01;
  fiEntire    = $02;

  FindStr     :string='';
  ReplaceStr  :string='';
  fiSensitive :Boolean=False;
  fiWholeWord :Boolean=False;
  fiScope     :Boolean=False;
  fiPrompt    :Boolean=True;
  fiDirection :Byte=$01;
  fiOrigin    :Byte=$01;

  HangTailFlag :Boolean=False;
  BackFile     :Boolean=True;
  AutoIndent   :Boolean=True;
  DelTailSpace :Boolean=True;
  ConvertTab   :Boolean=True;
  InsertMode   :Boolean=True;
  OldInsertMode:Boolean=False;

Const
  WordChars: set of Char=['0'..'9', 'A'..'Z', '_', 'a'..'z',#$A1..#$F4];
  InsStr:array [False..True] of string[4]=('改写','插入');
  ClipViewer:PViewer=nil;


Constructor TInsStatus.Init;
begin
  Inherited Init;
  AssignRect(Broad,GetMaxx-49,GetMaxy-22,GetMaxx,GetMaxy);
  InsertMode:=(GetShiftState and kbInsState)<>0;
  OldInsertMode:=InsertMode;
end;

Procedure TInsStatus.Paint;
begin
  HideMouse;
  SignBroad(Broad.a.x,Broad.a.y,Broad.b.x,Broad.b.y,1);
  SignBroad(Broad.a.x+4,Broad.a.y+2,Broad.b.x-4,Broad.b.y-2,0);
  WritecMap(Broad.a.x+9,Broad.a.y+3,InsStr[InsertMode],0,10);
  ShowMouse;
end;

Procedure TInsStatus.UpDate;
begin
  InsertMode:=(GetShiftState and kbInsState)<>0;
  if InsertMode<>OldInsertMode then
  begin
    Paint;
    OldInsertMode:=InsertMode;
  end;
end;

Constructor TViewerPos.Init;
begin
  Inherited Init;
  Size.X:=90;
  Size.Y:=17;
  MoveTo(X,Y);
  PosX:=PX;
  PosY:=PY;
end;

Procedure TViewerPos.Paint;
begin
  HideMouse;
  SignBroadc(Broad.A.X,Broad.A.Y,Broad.B.X,Broad.B.Y,0,$0A);
  Draw;
end;

Procedure TViewerPos.Draw;
var
  Str:string[12];
begin
  HideMouse;
  Str:=IntStr(PosX);
  InsSpaceFront(Str,5);
  Str:=Str+':'+IntStr(PosY);
  InsSpace(Str,10);
  if ModifyFlag then Str[10]:='*';
  Writec16(Origin.X div 8 +1,Origin.Y+1,Str,$A4);
  ShowMouse;
end;

Procedure TViewerPos.Modify;
begin
  if (PX=PosX)and(PY=PosY)and(ModifyFlag=M) then Exit;
  PosX:=PX;
  PosY:=PY;
  ModifyFlag:=M;
  Draw;
end;


Constructor TViewer.Init;
var
  T:TRect;
begin
  Inherited Init;
  GrowMode:=gfGrowHiX or gfGrowHiY;
  Style:=St;
  Size.X:=R.b.x*8;
  Size.Y:=R.b.y*16;
  HScrollBar:=nil;
  VScrollBar:=nil;
  ViewPos:=nil;
  XmsHandle:=0;
  Progress:=New(PProgressBar,Init(R.A.X,R.A.Y+Size.Y+2,90,17,pbBroad+pbSaveBack));
  if (Style and edViewerPos)<>0 then
    ViewPos:=New(PViewerPos,Init(R.A.X,R.A.Y+Size.Y+2,1,1));
  if (Style and edViewerPos)<>0 then
    AssignRect(T,R.a.x+100,R.a.y+Size.Y+2,Size.X-100,15)
  else
    AssignRect(T,R.a.x,R.a.y+Size.Y+2,Size.X,15);
  if ((Style and edHScroll)<>0) and (HScrollBar=nil) then
    HScrollBar:=New(PScrollBar,Init(sbHor,T,0));
  AssignRect(T,R.a.x+Size.X+2,R.a.y,15,Size.Y);
  if ((Style and edVScroll)<>0) and (VScrollBar=nil) then
    VScrollBar:=New(PScrollBar,Init(sbVer,T,0));
  MoveTo(R.a.x,R.a.y);
  Width:=R.b.x;
  Height:=R.b.y;
  GetMem(View,SizeOf(ViewType)*Height);
  FileName:='';
  TColor:=edTxtColor;
  SColor:=edSigColor;
  MColor:=edMakColor;
  InitBuf;
  ModifyFlag:=False;
  CtrlkFlag:=False;
  CurPos:=1;
  EndPos:=0;
  FindMode:=fiSearch;
end;

Destructor TViewer.Done;
begin
  FreeBuf;
  FreeMem(View,SizeOf(ViewType)*Height);
  DeleteScroll;
  if ViewPos<>nil then Dispose(ViewPos,Done);
  Dispose(Progress,Done);
  Inherited Done;
end;

Procedure TViewer.InsertScroll;
begin
  DeleteScroll;
  HScrollBar:=H;
  VScrollBar:=V;
end;

Procedure TViewer.DeleteScroll;
begin
  if HScrollBar<>nil then Dispose(HScrollBar,Done);
  if VScrollBar<>nil then Dispose(VScrollBar,Done);
  HScrollBar:=nil;
  VScrollBar:=nil;
end;

Procedure TViewer.MoveTo;
begin
  X:=X div 8 *8;
  Inherited MoveTo(X,Y);
  if HScrollBar<>nil then
  begin
    if (Style and edViewerPos)<>0 then
      HScrollBar^.MoveTo(X+100,Y+Size.Y+2)
    else
      HScrollBar^.MoveTo(X,Y+Size.Y+2);
  end;
  if VScrollBar<>nil then VScrollBar^.MoveTo(X+Size.X+2,Y);
  if ViewPos<>nil then ViewPos^.MoveTo(X,Y+Size.Y+2);
  Progress^.MoveTo(X,Y+Size.Y+2);
end;

Procedure TViewer.ChangeBroad;
var
  TW,TH:Integer;
begin
  Inherited ChangeBroad(X,Y);
  if (Size.X=Width*8)and(Size.Y=Height*16) then Exit;
  FreeMem(View,SizeOf(ViewType)*Height);
  TW:=Width;TH:=Height;
  Width:=Size.X div 8;
  Height:=Size.Y div 16;
  Size.X:=Width*8;
  Size.Y:=Height*16;
  if HScrollBar<>nil then HScrollBar^.ChangeBroad((Width-TW)*8,(Height-TH)*16);
  if VScrollBar<>nil then VScrollBar^.ChangeBroad((Width-TW)*8,(Height-TH)*16);
  MoveTo(Origin.X,Origin.Y);
  GetMem(View,SizeOf(ViewType)*Height);
  if Mark.X>Width then Mark.X:=Width;
  if Mark.Y>Height then Mark.Y:=Height;
end;

Procedure TViewer.Paint;
begin
  HideMouse;
  if (Style and edBroad)<>0 then
    SignBroad(Broad.A.X-1,Broad.A.Y-1,Broad.B.X,Broad.B.Y,0);
  if HScrollBar<>nil then HScrollBar^.Paint;
  if VScrollBar<>nil then VScrollBar^.Paint;
  if ViewPos<>nil then ViewPos^.Paint;
  HideMouse;
  Draw;
end;

Procedure TViewer.Draw;
var
  Str:string;
  i:Integer;
begin
  SetView;
  if MouIn(Broad) then HideMouse;
  for i:=1 to Height do
  begin
    Str:=View^[i].Str;
    if HangTailFlag then
    begin
      View^[i].Col[Length(Str)+1]:=$97;
      if Pos.Y+i<LineNum then
        Str:=Str+#17
      else if Pos.Y+i=LineNum then
        Str:=Str+#10;
    end;
    InsSpace(Str,StrLong);
    CWrite16(Origin.X div 8,Origin.Y+(i-1)*16,Pos.x+1,Width,Str,View^[i].Col);
  end;
  DrawMark;
  SetScroll;
  ShowMouse;
  ClearKbBuf;
end;

Procedure TViewer.DrawLine;
var
  Str:string;
begin
  SetViewLine(Num);
  HideMouse;
  Str:=View^[Num].Str;
  if HangTailFlag then
  begin
    View^[Num].Col[Length(Str)+1]:=$97;
    if Pos.Y+Num<LineNum then
      Str:=Str+#17
    else if Pos.Y+Num=LineNum then
      Str:=Str+#10;
  end;
  InsSpace(Str,StrLong);
  CWrite16(Origin.X div 8,Origin.Y+(Num-1)*16,Pos.x+1,Width,Str,View^[Num].Col);
  if Mark.Y=Num then DrawMark;
  if ViewPos<>nil then
    ViewPos^.Modify(ModifyFlag,StaLine+Pos.Y+Mark.Y,Pos.X+Mark.X);
  ShowMouse;
end;

Procedure TViewer.DrawMark;
begin
  HideMouse;
  SetWriteMode(1);
  SetColor(MColor);
  SetLineStyle(0,0,1);
  PutPixel(0,0,0);
  Line(Origin.X+(Mark.X-1)*8,Origin.Y+Mark.Y*16-2,
       Origin.X+Mark.X*8-1,Origin.Y+Mark.Y*16-2);
  Line(Origin.X+(Mark.X-1)*8,Origin.Y+Mark.Y*16-1,
       Origin.X+Mark.X*8-1,Origin.Y+Mark.Y*16-1);
  SetWriteMode(0);
  ShowMouse;
end;

Procedure TViewer.SetView;
var
  Temp:PLineItem;
  i:Integer;
begin
  Temp:=Head;
  for i:=1 to Pos.y do
  Temp:=Temp^.Next;
  for i:=1 to Height do
  begin
    if Temp=nil then
      View^[i].Str:=''
    else
    begin
      View^[i].Str:=Temp^.Str;
      Temp:=Temp^.Next;
    end;
    SetViewColor(i);
  end;
end;

Procedure TViewer.SetViewLine;
var
  Temp:PLineItem;
  i:Integer;
begin
  Temp:=Head;
  for i:=1 to Pos.y+Num-1 do
  if Temp<>nil then
    Temp:=Temp^.Next;
  if Temp=nil then
    View^[Num].Str:=''
  else
    View^[Num].Str:=Temp^.Str;
  SetViewColor(Num);
end;

Procedure TViewer.SetViewColor;
var
  Temp1,Temp2:Integer;
begin
  FillChar(View^[Num].Col[1],StrLong,TColor);
  if (Pos.Y+Num<SPos.Y)or(Pos.Y+Num>EPos.Y) then Exit;
  if Pos.Y+Num>SPos.Y then
    Temp1:=1
  else
    Temp1:=SPos.X;
  if Pos.Y+Num<EPos.Y then
    Temp2:=StrLong+1
  else if EPos.X<=Length(View^[Num].Str) then
    Temp2:=EPos.X
  else
    Temp2:=Length(View^[Num].Str)+1;
  Dec(Temp2,Temp1);
  if Temp2<0 then Temp2:=0;
  FillChar(View^[Num].Col[Temp1],Temp2,SColor);
end;

Procedure TViewer.SetScroll;
begin
  if HScrollBar<>nil then
    HScrollBar^.NewPos(Pos.X/(StrLong-Width));
  if VScrollBar<>nil then
  begin
    if TotLine>Height then
      VScrollBar^.NewPos((StaLine+Pos.Y)/(TotLine-Height))
    else VScrollBar^.NewPos(0);
  end;
  if ViewPos<>nil then
    ViewPos^.Modify(ModifyFlag,StaLine+Pos.Y+Mark.Y,Pos.X+Mark.X);
end;

Function TViewer.MoveMark;
var
  TempY1,TempY2:Integer;
begin
  MoveMark:=False;
  if (X=Mark.X) and (Y=Mark.Y) then Exit;
  if (X<1)or(X>Width)or(Y<1)or(Y>Height) then Exit;
  MoveMark:=True;
  DrawMark;
  TempY1:=SPos.Y;
  TempY2:=EPos.Y;
  if ProShift(Shift,Pos.X+X,Pos.Y+Y) then
  begin
    Mark.X:=X;
    if (Mark.Y=Y)and(TempY1=SPos.Y)and(TempY2=EPos.Y) then
      DrawLine(Mark.Y)
    else begin
      Mark.Y:=Y;
      Draw;
    end;
  end else
  begin
    Mark.X:=X;
    Mark.Y:=Y;
    DrawMark;
  end;
  if ViewPos<>nil then
    ViewPos^.Modify(ModifyFlag,StaLine+Pos.Y+Mark.Y,Pos.X+Mark.X);
end;

Function TViewer.MoveView;
var
  TPos,TMark:TPoint;
  Temp:Integer;
begin
  MoveView:=False;
  TPos:=Pos;
  TMark:=Mark;
  if (Y<0)and(StaLine>0) then
  begin
    StoreToXms;
    Temp:=BufLine div 2 -Y;
    if StaLine<Temp then Temp:=StaLine;
    Dec(StaLine,Temp);
    LoadFromXms;
    Pos:=TPos;Mark:=TMark;
    Dec(Pos.Y,Temp);
    Inc(Y,Temp);
  end else
  if (Y>LineNum-Height)and(StaLine+LineNum<TotLine) then
  begin
    if Y+StaLine>=TotLine then Y:=TotLine-StaLine-1;
    StoreToXms;
    Temp:=Y-LineNum+Height+BufLine div 2;
    if TotLine-StaLine<Temp then Temp:=TotLine-StaLine;
    Inc(StaLine,Temp);
    LoadFromXms;
    Pos:=TPos;Mark:=TMark;
    Inc(Pos.Y,Temp);
    Dec(Y,Temp);
  end else
  if LineNum>MaxBufLine then
  begin
    StoreToXms;
    Temp:=Y-BufLine div 2;
    if StaLine+Temp<0 then Temp:=-StaLine;
    Inc(StaLine,Temp);
    LoadFromXms;
    Pos:=TPos;Mark:=TMark;
    Dec(Pos.Y,Temp);
    Dec(Y,Temp);
  end;
  if Chk then
  begin
    if (X=Pos.X) and (Y=Pos.Y) then Exit;
    if (X<0) or (Y<0) or (X>StrLong-Width) then Exit;
    if (LineNum>=Height)and(Y>LineNum-Height)and(Y>Pos.Y) then Exit;
    if (LineNum<Height)and(Y<>0)and(Y>Pos.Y) then Exit;
    ProShift(Shift,X+Mark.X,Y+Mark.Y);
  end;
  Pos.X:=X;
  Pos.Y:=Y;
  Draw;
  MoveView:=True;
end;

Procedure TViewer.HandleMouse;
begin
  repeat
    ClearEvent(Event);
    GetEvent(Event);
    if (Event.Buttons=mbLeftButton) and
       ((Event.What=evMouseMove) or (Event.What=evMouseAuto)) then
    begin
      if IsIn(Event.Where,Broad) then
        MoveMark(True,(Event.Where.X-Broad.A.X) div 8+1,(Event.Where.Y-Broad.A.Y) div 16+1)
      else if Event.Where.Y<Broad.A.Y then
      begin
        if not MoveMark(True,Mark.X,Mark.Y-1) then
          MoveView(True,True,Pos.X,Pos.Y-1);
      end else if Event.Where.Y>Broad.B.Y then
      begin
        if not MoveMark(True,Mark.X,Mark.Y+1) then
          MoveView(True,True,Pos.X,Pos.Y+1);
      end else if Event.Where.X<Broad.A.X then
      begin
        if not MoveMark(True,Mark.X-1,Mark.Y) then
          MoveView(True,True,Pos.X-1,Pos.Y);
      end else if Event.Where.X>Broad.B.X then
      begin
        if not MoveMark(True,Mark.X+1,Mark.Y) then
          MoveView(True,True,Pos.X+1,Pos.Y);
      end;
    end;
  until (Event.What=evMouseUp);
end;

Procedure TViewer.HandleEvent;
begin
  if HScrollBar<>nil then HScrollBar^.HandleEvent(Event);
  if VScrollBar<>nil then VScrollBar^.HandleEvent(Event);
  case Event.What of
  evCommand:if (not (Event.Command in [cmGotoLine,cmSearch,cmSearchAgain]))
               and (Event.InfoPtr<>HScrollBar) and (Event.InfoPtr<>VScrollBar)
               and (Event.Index<>HScrollBar) and (Event.Index<>VScrollBar) then
              Exit
            else
            case Event.Command of
            cmLeft: if not MoveMark(False,Mark.X-1,Mark.Y) then
                      MoveView(False,True,Pos.X-1,Pos.Y);
            cmRight:if not MoveMark(False,Mark.X+1,Mark.Y) then
                      MoveView(False,True,Pos.X+1,Pos.Y);
            cmUp:   if not MoveMark(False,Mark.X,Mark.Y-1) then
                      MoveView(False,True,Pos.X,Pos.Y-1);
            cmDown: if not MoveMark(False,Mark.X,Mark.Y+1) then
                      MoveView(False,True,Pos.X,Pos.Y+1);
            cmInterHor:MoveView(False,True,Round(Event.InfoReal*(StrLong-Width)),Pos.Y);
            cmInterVer:MoveView(False,True,Pos.X,Round(Event.InfoReal*(TotLine-Height))-StaLine);
            cmHome:begin
                     MoveMark(False,1,Mark.Y);
                     MoveView(False,True,0,Pos.Y);
                   end;
            cmEnd: if not MoveMark(False,Length(View^[Mark.y].Str)+1,Mark.Y) then
                   begin
                     MoveMark(False,Width,Mark.Y);
                     if Length(View^[Mark.y].Str)=StrLong then
                       MoveView(False,True,StrLong-Width,Pos.Y)
                     else
                       MoveView(False,True,Length(View^[Mark.y].Str)-Width+1,Pos.Y);
                   end;
            cmPgUp:if not MoveView(False,True,Pos.X,Pos.Y-Height+1) then
                     MoveView(False,True,Pos.X,0);
            cmPgDn:if not MoveView(False,True,Pos.X,Pos.Y+Height-1) then
                     MoveView(False,True,Pos.X,LineNum-Height);
            cmCtrlPgUp:begin
                         MoveMark(False,1,1);
                         MoveView(False,True,0,-StaLine);
                       end;
            cmCtrlPgDn:begin
                         MoveView(False,True,Pos.X,TotLine-StaLine-Height);
                         if Mark.Y<Height then
                           MoveMark(False,Mark.X,LineNum-Pos.Y);
                       end;
            cmGotoLine:begin
                         MoveView(False,True,Pos.X,Integer(Event.InfoPtr^)-StaLine-1);
                         MoveMark(False,Mark.X,1);
                       end;
            cmSearch:if RunView(FindWin,Event) then Find(fiSearch);
            cmSearchAgain:SearchAgain;
            else Exit;
            end;
  evKeyDown:case Event.KeyCode of
            kbCtrlK:if not CtrlkFlag then
                      CtrlkFlag:=True
                    else
                      ProCtrlKK;
            kbCtrlH:if CtrlkFlag then
                    begin
                      EPos:=SPos;
                      CtrlkFlag:=False;
                      Draw;
                    end;
            kbCtrlB:if CtrlkFlag then ProCtrlKB;
            else Exit;
            end;
  evMouseDown:if (Event.Buttons=mbLeftButton) and IsIn(Event.Where,Broad) then
              begin
                if MoveMark(False,(Event.Where.X-Broad.A.X) div 8+1,(Event.Where.Y-Broad.A.Y) div 16+1) then
                begin
                  SPos.X:=Pos.X+Mark.X;
                  SPos.Y:=Pos.Y+Mark.Y;
                  EPos:=SPos;
                  MoveView(False,False,Pos.X,Pos.Y);
                end;
              end else Exit;
  evMouseMove:if (Event.Buttons=mbLeftButton) and IsIn(Event.Where,Broad) then
                HandleMouse(Event)
              else Exit;
  else Exit;
  end;
  ClearEvent(Event);
end;

Procedure TViewer.InitBuf;
begin
  InitLine;
  XmsHandle:=0;
  StaLine:=0;
  TotLine:=0;
end;

Procedure TViewer.InitLine;
begin
  Head:=nil;
  LineNum:=0;
  OldLineNum:=0;
  Pos.X:=0;
  Pos.Y:=0;
  Mark.X:=1;
  Mark.Y:=1;
  SPos.X:=1;
  SPos.Y:=1;
  EPos.X:=1;
  EPos.Y:=1;
end;

Procedure TViewer.FreeBuf;
begin
  if XmsHandle<>0 then
    FreeXms(XmsHandle);
  FreeLine;
  InitBuf;
end;

Procedure TViewer.FreeLine;
var
  Temp:PLineItem;
begin
  if Head=nil then Exit;
  Temp:=Head;
  while Temp<>nil do
  begin
    Head:=Temp^.Next;
    Dispose(Temp);
    Temp:=Head;
  end;
  InitLine;
end;

Function TViewer.InsertLine;
var
  Temp,Temp1,Temp2:PLineItem;
  i:Integer;
begin
  InsertLine:=False;
  if (Num>1)and(Num>LineNum) then Exit;
  New(Temp);
  if Temp=nil then Exit;
  InsertLine:=True;
  Temp^.Str:=Str;
  Temp^.Next:=nil;
  Inc(LineNum);
  Inc(TotLine);
  if Head=nil then
  begin
    Head:=Temp;
    Exit;
  end;
  if Num=0 then
  begin
    Temp^.Next:=Head;
    Head:=Temp;
    Exit;
  end;
  Temp1:=Head;
  for i:=1 to Num-1 do
  if Temp1<>nil then
    Temp1:=Temp1^.Next;
  Temp2:=Temp1^.Next;
  Temp1^.Next:=Temp;
  Temp^.Next:=Temp2;
  ModifyFlag:=True;
end;

Function TViewer.DeleteLine;
var
  Temp,Temp1:PLineItem;
  i:Integer;
begin
  DeleteLine:=True;
  if (Head=nil)or(Num>LineNum) then Exit;
  DeleteLine:=True;
  Dec(LineNum);
  Dec(TotLine);
  Temp:=Head;
  if Num=1 then
  begin
    Head:=Head^.Next;
    Dispose(Temp);
    Exit;
  end;
  for i:=1 to Num-2 do
  Temp:=Temp^.Next;
  Temp1:=Temp^.Next;
  Temp^.Next:=Temp1^.Next;
  Dispose(Temp1);
  ModifyFlag:=True;
end;

Function TViewer.Insert;
begin
  Insert:=InsertLine(LineNum,Str);
end;

Function TViewer.GetLine;
var
  Temp:PLineItem;
  i:Integer;
begin
  GetLine:='';
  if (Head=nil)or(Num>LineNum) then Exit;
  Temp:=Head;
  for i:=1 to Num-1 do
  if Temp<>nil then
    Temp:=Temp^.Next;
  if Temp<>nil then
    GetLine:=Temp^.Str;
end;

Procedure TViewer.ModifyLine;
var
  Temp:PLineItem;
  i:Integer;
begin
  if (Head=nil)or(Num>LineNum) then Exit;
  Temp:=Head;
  for i:=1 to Num-1 do
  Temp:=Temp^.Next;
  Temp^.Str:=Str;
  ModifyFlag:=True;
end;

Procedure TViewer.DeleteBlock;
var
  Str1,Str2:string;
  i:Integer;
begin
  if (SPos.Y>EPos.Y) or ((SPos.Y=EPos.Y)and(SPos.X>=EPos.X)) then Exit;
  Str1:=GetLine(SPos.Y);
  Str1:=System.Copy(Str1,1,SPos.X-1);
  Str2:=GetLine(EPos.Y);
  System.Delete(Str2,1,EPos.X-1);
  Str1:=Str1+Str2;
  for i:=SPos.Y to EPos.Y do
  DeleteLine(SPos.Y);
  InsertLine(SPos.Y-1,Str1);
  EPos:=SPos;
  if (SPos.Y>Pos.Y)and(SPos.Y<=Pos.Y+Height) then
    Mark.Y:=SPos.Y-Pos.Y
  else begin
    Pos.Y:=SPos.Y - Height div 2;
    if Pos.Y<0 then Pos.Y:=0;
    Mark.Y:=SPos.Y-Pos.Y;
  end;
  Mark.X:=SPos.X-Pos.X;
  if Mark.X<1 then
  begin
    Pos.X:=0;
    Mark.X:=SPos.X;
    if Mark.X>Width then Mark.X:=1;
  end else
  if Mark.X>Width then Mark.X:=1;
  MoveView(False,False,Pos.X,Pos.Y);
  CtrlkFlag:=False;
end;

Procedure TViewer.LoadFromXms;
var
  Str:string;
  i,Num,TempTot:Integer;
  TempModify:Boolean;
begin
  if XmsHandle=0 then Exit;
  Num:=BufLine;
  if TotLine-StaLine<BufLine then
    Num:=TotLine-StaLine;
  TempModify:=ModifyFlag;
  TempTot:=TotLine;
  FreeLine;
  for i:=1 to Num do
  begin
    MoveXms(@Str[0],0,Pointer(Longint(StaLine+i-1)*Longint(StrLong+1)),XmsHandle,StrLong+1);
    Insert(Str);
  end;
  TotLine:=TempTot;
  OldLineNum:=LineNum;
  ModifyFlag:=TempModify;
end;

Procedure TViewer.StoreToXms;
var
  Str:string;
  i:Integer;
begin
  if (XmsHandle=0)or(Head=nil) then Exit;
  if OldLineNum>LineNum then
    MoveXms(Pointer(Longint(StaLine+LineNum)*Longint(StrLong+1)),XmsHandle,
            Pointer(Longint(StaLine+OldLineNum)*Longint(StrLong+1)),XmsHandle,
            Longint(TotLine-StaLine-LineNum)*Longint(StrLong+1))
  else if OldLineNum<LineNum then
    for i:=TotLine-1 downto StaLine+LineNum do
    MoveXms(Pointer(Longint(i)*Longint(StrLong+1)),XmsHandle,
            Pointer(Longint(i-LineNum+OldLineNum)*Longint(StrLong+1)),XmsHandle,StrLong+1);
  for i:=1 to LineNum do
  begin
    Str:=GetLine(i);
    MoveXms(Pointer(Longint(StaLine+i-1)*Longint(StrLong+1)),XmsHandle,@Str[0],0,StrLong+1);
  end;
end;

Procedure TViewer.LoadFromFile;
var
  Fp1:File;
  Fp:Text;
  Str,St:string;
  i,Result,XSize:Integer;
  NoErr:Boolean;
begin
  if not Exist_Fi(Name) then Exit;
  Result:=IOResult;
  Assign(Fp1,Name);
  Reset(Fp1,1);
  XSize:=FileSize(Fp1) div 350;
  Result:=IOResult;
  Assign(Fp,Name);
  Reset(Fp);
  NoErr:=True;
  if IOResult<>0 then NoErr:=False;
  Inc(XSize,NormalXmsSize);
  if GetXmsSize<XSize then Exit;
  FreeBuf;
  if (Style and edUseXms)<>0 then
    XmsHandle:=MallocXms(XSize);
  if (Style and edProgress)<>0 then
  begin
    Progress^.Loc:=0;
    Progress^.Paint;
  end;
  while (not Eof(Fp)) and NoErr and (TotLine<MaxLine) do
  begin
    Readln(Fp,Str);
    St:='';
    for i:=1 to Length(Str) do
    if Str[i]=#9 then
      InsSpace(St,Length(St)+8-(Length(St) mod 8))
    else
      St:=St+Str[i];
    if (Style and edUseXms)<>0 then
    begin
      MoveXms(Pointer(Longint(TotLine)*Longint(StrLong+1)),XmsHandle,@St[0],0,StrLong+1);
      Inc(TotLine);
    end else
      NoErr:=Insert(Copy(St,1,StrLong));
    if (Style and edProgress)<>0 then
      Progress^.Modify(TotLine/8/(XSize-NormalXmsSize+1));
  end;
  Close(Fp);
  FileName:=Name;
  LoadFromXms;
  ModifyFlag:=False;
  if (Style and edProgress)<>0 then Progress^.Hide;
end;

Procedure TViewer.ConvTab;
var
  Po:Integer;
begin
  while System.Pos('        ',S)>0 do
  begin
    Po:=System.Pos('        ',S);
    System.Delete(S,Po,7);
    S[Po]:=#9;
  end;
end;

Procedure TViewer.SaveFile;
begin
  SaveToFile(FileName);
end;

Procedure TViewer.SaveToFile;
var
  Fp:Text;
  Temp:PLineItem;
  Str:string;
  i,Result:Integer;
begin
  if Name='' then Exit;
  if BackFile then
    ReNameFile(Name,Ch_Name(Name,'BAK'));
  Result:=IOResult;
  Assign(Fp,Name);
  ReWrite(Fp);
  if IOResult<>0 then Exit;
  StoreToXms;
  if (Style and edProgress)<>0 then
  begin
    Progress^.Loc:=0;
    Progress^.Paint;
  end;
  if XmsHandle<>0 then
  begin
    for i:=0 to TotLine-1 do
    begin
      MoveXms(@Str[0],0,Pointer(Longint(i)*Longint(StrLong+1)),XmsHandle,StrLong+1);
      if ConvertTab then ConvTab(Str);
      Writeln(Fp,Str);
      if (Style and edProgress)<>0 then
        Progress^.Modify((i+1)/TotLine);
    end;
  end else
  begin
    i:=0;
    Temp:=Head;
    while Temp<>nil do
    begin
      Str:=Temp^.Str;
      if DelTailSpace then DelSpaceTail(Str);
      if ConvertTab then ConvTab(Str);
      Writeln(Fp,Str);
      Temp:=Temp^.Next;
      Inc(i);
      if (Style and edProgress)<>0 then
        Progress^.Modify(i/LineNum);
    end;
  end;
  Close(Fp);
  FileName:=Name;
  ModifyFlag:=False;
  if (Style and edProgress)<>0 then Progress^.Hide;
end;

Procedure TViewer.ProCtrlKB;
begin
  SPos.X:=Pos.X+Mark.X;
  SPos.Y:=Pos.Y+Mark.Y;
  Draw;
  CtrlkFlag:=False;
end;

Procedure TViewer.ProCtrlKK;
begin
  EPos.X:=Pos.X+Mark.X;
  EPos.Y:=Pos.Y+Mark.Y;
  Draw;
  CtrlkFlag:=False;
end;

Function TViewer.ProShift;
var
  TempX,TempY:Integer;
begin
  ProShift:=False;
  if (not Shift) and (not ShiftPush) then Exit;
  if Y>LineNum then Y:=LineNum;
  TempX:=Pos.X+Mark.X;
  TempY:=Pos.Y+Mark.Y;
  if TempY>LineNum then TempY:=LineNum;
  if (SPos.X=TempX)and(SPos.Y=TempY) then
  begin
    SPos.X:=X;
    SPos.Y:=Y;
  end else
  if (EPos.X=TempX)and(EPos.Y=TempY) then
  begin
    EPos.X:=X;
    EPos.Y:=Y;
  end else
  begin
    SPos.X:=X;
    SPos.Y:=Y;
    EPos.X:=TempX;
    EPos.Y:=TempY;
  end;
  if (SPos.Y>EPos.Y) or ((SPos.Y=EPos.Y)and(SPos.X>EPos.X)) then
  begin
    SwapInt(SPos.X,EPos.X);
    SwapInt(SPos.Y,EPos.Y);
  end;
  ProShift:=True;
end;

Procedure TViewer.CopyToClip;
var
  R:TRect;
  Str1,Str2:string;
  i:Integer;
begin
  if (SPos.Y>EPos.Y) or ((SPos.Y=EPos.Y)and(SPos.X>=EPos.X)) then Exit;
  AssignRect(R,0,0,0,0);
  if P=nil then P:=New(PViewer,Init(R,0));
  P^.FreeLine;
  Str1:=GetLine(SPos.Y);
  System.Delete(Str1,1,SPos.X-1);
  Str2:=GetLine(EPos.Y);
  Str2:=System.Copy(Str2,1,EPos.X-1);
  if SPos.Y=EPos.Y then
    P^.Insert(System.Copy(Str1,1,EPos.X-SPos.X))
  else
  for i:=SPos.Y to EPos.Y do
  begin
    if i=SPos.Y then
      P^.Insert(Str1)
    else if i=EPos.Y then
      P^.Insert(Str2)
    else
      P^.Insert(GetLine(i));
  end;
end;

Procedure TViewer.PasteFromClip;
var
  Str1,Str2:string;
  i:Integer;
begin
  if (P=nil)or(P^.LineNum=0) then Exit;
  if Pos.Y+Mark.Y>LineNum then
  begin
    for i:=LineNum+1 to Pos.Y+Mark.Y do
    Insert('');
  end;
  Str1:=GetLine(Pos.Y+Mark.Y);
  Str1:=System.Copy(Str1,1,Pos.X+Mark.X-1);
  InsSpace(Str1,Pos.X+Mark.X-1);
  Str2:=GetLine(Pos.Y+Mark.Y);
  System.Delete(Str2,1,Pos.X+Mark.X-1);
  if P^.LineNum=1 then
    ModifyLine(Pos.Y+Mark.Y,Str1+P^.GetLine(1)+Str2)
  else
  for i:=1 to P^.LineNum do
  begin
    if i=1 then
      ModifyLine(Pos.Y+Mark.Y,Str1+P^.GetLine(i))
    else if i=P^.LineNum then
      InsertLine(Pos.Y+Mark.Y+i-2,P^.GetLine(i)+Str2)
    else
      InsertLine(Pos.Y+Mark.Y+i-2,P^.GetLine(i));
  end;
  SPos.X:=Pos.X+Mark.X;
  SPos.Y:=Pos.Y+Mark.Y;
  EPos.Y:=SPos.Y+P^.LineNum-1;
  if SPos.Y=EPos.Y then
    EPos.X:=SPos.X+Length(P^.GetLine(1))
  else
    EPos.X:=Length(P^.GetLine(P^.LineNum))+1;
end;

Function TViewer.MsgDlg;
var
  Dlg:PMsgDialog;
begin
  Dlg:=New(PMsgDialog,Init(T,S,Sty));
  Dlg^.Owner:=@Self;
  Dlg^.Paint;
  Dlg^.Run(Event);
  Dispose(Dlg,Done);
  MsgDlg:=(Event.Command=cmYes) or (Event.Command=cmOk);
  ReplaceFlag:=True;
  if Event.Command=cmCancel then
    ReplaceFlag:=False;
end;

Function TViewer.RunView;
begin
  RunView:=False;
  V^.Owner:=@Self;
  V^.Paint;
  V^.Run(Event);
  Dispose(V,Done);
  if (Event.Command<>cmOk) and (Event.Command<>cmYes) then Exit;
  RunView:=True;
  ReplaceFlag:=False;
  if Event.Command=cmYes then
    ReplaceFlag:=True;
end;

Function TViewer.Search;
var
  i,P,Dlt:Integer;
  Str,Str1:string;
  Dlg:PMsgDialog;
begin
  Search:=False;
  i:=CurPos;
  repeat
    if CtrlBreakHit then Exit;
    MoveXms(@Str[0],0,Pointer(Longint(i-1)*Longint(StrLong+1)),XmsHandle,StrLong+1);
    Str1:=Str;
    System.Delete(Str,1,CurMark);
    if fiSensitive then
      P:=System.Pos(FindStr,Str)
    else
      P:=System.Pos(Upcases(FindStr),Upcases(Str));
    if P<>0 then
    begin
      if (not fiWholeWord) or
         not (((P>1) and (Str[P-1] in WordChars)) or
              ((P+System.Length(FindStr)<=System.Length(Str)) and
               (Str[P+System.Length(FindStr)] in WordChars))) then
      begin
        Search:=True;
        CurPos:=i;
        Dlt:=Height div 2;
        if TotLine-CurPos<=Dlt then Dlt:=TotLine-CurPos+1;
        if CurPos<Dlt then Dlt:=CurPos;
        if (CurPos-StaLine-Pos.Y<1)or(CurPos-StaLine-Pos.Y>Height) then
          MoveView(False,True,Pos.X,CurPos-StaLine-Dlt);
        SPos.X:=CurMark+P;SPos.Y:=CurPos-StaLine;
        EPos.X:=CurMark+P+Length(FindStr);EPos.Y:=SPos.Y;
        Pos.X:=0;
        if CurMark+P+Length(FindStr)>Width then
          Pos.X:=CurMark+P+Length(FindStr)-Width;
        Mark.X:=SPos.X-Pos.X;
        if Mark.X<1 then Mark.X:=1;
        Mark.Y:=CurPos-StaLine-Pos.Y;
        MoveView(False,False,Pos.X,Pos.Y);
        if Mode=fiReplace then
        begin
          if fiPrompt and (not MsgDlg('替换字串','  是否替换此字串?  ',
             mbYesNo+mbQuestion)) then
          begin
            Inc(CurMark,P+Length(FindStr)-1);
            if not ReplaceFlag then
              CtrlBreakHit:=True;
            Exit;
          end;
          System.Delete(Str1,CurMark+P,System.Length(FindStr));
          System.Insert(ReplaceStr,Str1,CurMark+P);
          ModifyLine(Pos.Y+Mark.Y,Str1);
          DrawLine(Mark.Y);
        end;
        Inc(CurMark,P+Length(FindStr)-1);
        Exit;
      end;
    end;
    CurMark:=0;
    case fiDirection of
    fiForward:Inc(i);
    fiBackWard:Dec(i);
    end;
  until ((fiDirection=fiForward)and(i>=EndPos)) or
        ((fiDirection=fiBackward)and(i<=EndPos));
end;

Function TViewer.Find;
begin
  Find:=False;
  if (TotLine=0) or (FindStr='') then Exit;
  StoreToXms;
  case fiOrigin of
  fiCursor:begin CurPos:=StaLine+Pos.Y+Mark.Y;CurMark:=Pos.X+Mark.X-1; end;
  fiEntire:begin CurPos:=1;CurMark:=0; end;
  end;
  EndPos:=TotLine;
  if fiScope then
  begin
    CurPos:=StaLine+SPos.Y;
    EndPos:=StaLine+EPos.Y;
  end;
  if CurPos>EndPos then Exit;
  if fiDirection=fiBackward then SwapInt(CurPos,EndPos);
  Find:=Search(Mode);
  FindMode:=Mode;
end;

Function TViewer.SearchAgain;
begin
  SearchAgain:=False;
  if (TotLine=0) or (FindStr='') then Exit;
  if ((fiDirection=fiForward)and(CurPos>EndPos)) or
     ((fiDirection=fiBackward)and(CurPos<EndPos)) then Exit;
  if Search(FindMode) then
    SearchAgain:=True
  else
    MsgDlg('错误','已无可匹配字串!',mbOkOnly+mbInformation);
end;

Procedure TViewer.ReplaceAll;
begin
  Find(fiReplace);
  while (not CtrlBreakHit) and SearchAgain do;
  StoreToXms;
  CtrlBreakHit:=False;
end;


Constructor TEditor.Init;
begin
  Inherited Init(R,St);
  CanEdit:=True;
end;

Procedure TEditor.CloseSelf;
var
  P:PView;
begin
  if ModifyFlag then
  begin
    P:=New(PMsgDialog,Init('保存文件',
       '文件"'+FileName+'"已改动'+#13',是否要保存?',mbYesNo));
    P^.Owner:=@Self;
    P^.Paint;
    P^.Run(Event);
    Dispose(P,Done);
    if Event.Command=cmYes then
      SaveFile
    else if Event.Command=cmCancel then
      SureToCloseWin:=False;
  end;
end;

Procedure TEditor.HandleEvent;
begin
  Inherited HandleEvent(Event);
  if not CanEdit then Exit;
  case Event.What of
  evCommand:case Event.Command of
            cmCopy:CopyToClip(ClipViewer);
            cmPaste:ProPaste;
            cmClear:DeleteBlock;
            cmCut:ProCut;
            cmReplace:if RunView(ReplaceWin,Event) then
                      begin
                        if ReplaceFlag then
                          ReplaceAll
                        else
                          Find(fiReplace);
                      end;
            else Exit;
            end;
  evKeyDown:if Event.CMark then
            begin
              ProChar(Char(Hi(Event.KeyCode)));
              ProChar(Char(Lo(Event.KeyCode)));
            end else
            case Event.KeyCode of
            kbEnter:begin
                      ProEnter;
                      Event.What:=evCommand;
                      Event.Command:=cmEnterPress;
                      Exit;
                    end;
            kbDel:ProDel;
            kbBack:ProBackSpace;
            kbCtrlC:if CtrlkFlag then ProCtrlKC;
            kbCtrlV:if CtrlkFlag then ProCtrlKV;
            kbCtrlY:if not CtrlkFlag then
                    begin
                      if DeleteLine(Pos.Y+Mark.Y) then
                      begin
                        Mark.X:=1;
                        MoveView(False,False,0,Pos.Y);
                      end;
                    end else
                      DeleteBlock;
            else case Event.CharCode of
                 #32..#255:ProChar(Event.CharCode);
                 else Exit;
                 end;
            end;
  else Exit;
  end;
  ClearEvent(Event);
end;

Procedure TEditor.ProChar;
var
  Str:string;
  Dlt:Integer;
  i:Integer;
begin
  if Pos.X+Mark.X>=StrLong then Exit;
  if Pos.Y+Mark.Y>LineNum then
  begin
    for i:=LineNum+1 to Pos.Y+Mark.Y do
    Insert('');
  end;
  Str:=GetLine(Pos.Y+Mark.Y);
  if Length(Str)>=StrLong then Exit;
  if Pos.X+Mark.X>Length(Str) then
  begin
    InsSpace(Str,Pos.X+Mark.X-1);
    Str:=Str+Ch;
  end else
  begin
    if InsertMode then
      System.Insert(Ch,Str,Pos.X+Mark.X)
    else
      Str[Pos.X+Mark.X]:=Ch;
  end;
  ModifyLine(Pos.Y+Mark.Y,Str);
  if Mark.X=Width then
  begin
    Dlt:=10;
    if StrLong-Width-Pos.X<Dlt then
      Dlt:=StrLong-Width-Pos.X;
    Dec(Mark.X,Dlt-1);
    MoveView(False,True,Pos.X+Dlt,Pos.Y);
  end else
  begin
    Inc(Mark.X);
    DrawLine(Mark.Y);
  end;
end;

Procedure TEditor.ProEnter;
var
  Str,Str1:string;
  TempPos:TPoint;
  i:Integer;
begin
  if Pos.Y+Mark.Y>LineNum then
  begin
    for i:=LineNum+1 to Pos.Y+Mark.Y do
    Insert('');
    Exit;
  end;
  Str:=GetLine(Pos.Y+Mark.Y);
  Str1:=Copy(Str,Pos.X+Mark.X,Length(Str)-Pos.X-Mark.X+1);
  if AutoIndent then
  begin
    i:=0;
    while (i<Length(Str)) and (Str[i+1]=' ') do Inc(i);
    InsSpaceFront(Str1,i+Length(Str1));
  end;
  ModifyLine(Pos.Y+Mark.Y,Copy(Str,1,Pos.X+Mark.X-1));
  InsertLine(Pos.Y+Mark.Y,Str1);
  TempPos.X:=0;
  TempPos.Y:=Pos.Y;
  if i>=Width then TempPos.X:=i-Width+10;
  if Mark.Y=Height then TempPos.Y:=Pos.Y+1;
  Mark.X:=i+1-TempPos.X;
  Inc(Mark.Y);
  if Mark.Y>Height then Mark.Y:=Height;
  MoveView(False,False,TempPos.X,TempPos.Y);
end;

Procedure TEditor.ProDel;
var
  Str,Str1:string;
begin
  if Pos.Y+Mark.Y>LineNum then Exit;
  Str:=GetLine(Pos.Y+Mark.Y);
  if Pos.X+Mark.X<=Length(Str) then
  begin
    System.Delete(Str,Pos.x+Mark.X,1);
    ModifyLine(Pos.Y+Mark.Y,Str);
    DrawLine(Mark.Y);
  end else
  if Pos.Y+Mark.Y<LineNum then
  begin
    Str1:=GetLine(Pos.Y+Mark.Y+1);
    InsSpace(Str,Pos.X+Mark.X-1);
    Str:=Str+Str1;
    ModifyLine(Pos.Y+Mark.Y,Str);
    DeleteLine(Pos.Y+Mark.Y+1);
    MoveView(False,False,Pos.X,Pos.Y);
  end;
end;

Procedure TEditor.ProBackSpace;
var
  Str,Str1:string;
  Temp:Integer;
begin
  if Pos.Y+Mark.Y>LineNum then Exit;
  Str:=GetLine(Pos.Y+Mark.Y);
  if Pos.X+Mark.X>Length(Str)+1 then
  begin
    if not MoveMark(False,Mark.X-1,Mark.Y) then
      MoveView(False,True,Pos.X-1,Pos.Y);
    Exit;
  end else
  if Pos.X+Mark.X>1 then
  begin
    System.Delete(Str,Pos.X+Mark.X-1,1);
    ModifyLine(Pos.Y+Mark.Y,Str);
    if Mark.X>1 then
    begin
      Dec(Mark.X);
      DrawLine(Mark.Y);
    end else
    begin
      Temp:=Pos.X-10;
      if Temp<0 then Temp:=0;
      Mark.X:=Pos.X+Mark.X-Temp-1;
      MoveView(False,True,Temp,Pos.Y);
    end;
  end else
  if Pos.Y+Mark.Y>1 then
  begin
    Str1:=GetLine(Pos.Y+Mark.Y-1);
    Temp:=Length(Str1);
    Str1:=Str1+Str;
    ModifyLine(Pos.Y+Mark.Y-1,Str1);
    DeleteLine(Pos.Y+Mark.Y);
    if Mark.Y>1 then
      Dec(Mark.Y)
    else
      Dec(Pos.Y);
    if Temp<Width then
      Pos.X:=0
    else
      Pos.X:=Temp-Width+1;
    Mark.X:=Temp-Pos.X+1;
    MoveView(False,False,Pos.X,Pos.Y);
  end;
end;

Procedure TEditor.ProCtrlKC;
begin
  CopyToClip(ClipViewer);
  PasteFromClip(ClipViewer);
  MoveView(False,False,Pos.X,Pos.Y);
  CtrlkFlag:=False;
end;

Procedure TEditor.ProCtrlKV;
begin
  CopyToClip(ClipViewer);
  DeleteBlock;
  PasteFromClip(ClipViewer);
  MoveView(False,False,Pos.X,Pos.Y);
  CtrlkFlag:=False;
end;

Procedure TEditor.ProPaste;
begin
  PasteFromClip(ClipViewer);
  MoveView(False,False,Pos.X,Pos.Y);
end;

Procedure TEditor.ProCut;
begin
  CopyToClip(ClipViewer);
  DeleteBlock;
end;



Constructor TFileViewer.Init;
var
  T:TRect;
begin
  R.A.X:=R.A.X div 8 * 8;
  T.A:=R.A;
  T.B.X:=T.A.X+R.B.X*8+31;
  T.B.Y:=T.A.Y+R.B.Y*16+53;
  Inherited Init(T,Name,True);
  Option:=Option or opAligen8 or opResize;
  GrowDlt.X:=8;
  GrowDlt.Y:=16;
  Inc(R.A.X,8);
  Inc(R.A.Y,29);
  Viewer:=New(PViewer,Init(R,edHScroll+edVScroll+edBroad
                      +edViewerPos+edProgress+edUseXms));
  Viewer^.LoadFromFile(Name);
  Insert(Viewer);
end;

Procedure TFileViewer.LoadFromFile;
begin
  if not Exist_Fi(Name) then Exit;
  ModifyTitle(Name);
  Viewer^.LoadFromFile(Name);
  ModifyTitle(Viewer^.FileName);
  Viewer^.Draw;
end;


Constructor TFileEditor.Init;
var
  T:TRect;
begin
  R.A.X:=R.A.X div 8 * 8;
  T.A:=R.A;
  T.B.X:=T.A.X+R.B.X*8+31;
  T.B.Y:=T.A.Y+R.B.Y*16+53;
  Inherited Init(T,Name,True);
  Option:=Option or opAligen8 or opResize;
  GrowDlt.X:=8;
  GrowDlt.Y:=16;
  Inc(R.A.X,8);
  Inc(R.A.Y,29);
  Editor:=New(PEditor,Init(R,edHScroll+edVScroll+edBroad
                      +edViewerPos+edProgress+edUseXms));
  Editor^.LoadFromFile(Name);
  Insert(Editor);
end;

Procedure TFileEditor.SaveToFile;
begin
  Editor^.SaveToFile(Name);
  ModifyTitle(Editor^.FileName);
end;

Procedure TFileEditor.SaveFile;
begin
  Editor^.SaveFile;
end;

Procedure TFileEditor.LoadFromFile;
begin
  if not Exist_Fi(Name) then Exit;
  ModifyTitle(Name);
  Editor^.LoadFromFile(Name);
  ModifyTitle(Editor^.FileName);
  Editor^.Draw;
end;

{----------------------------------------------}
Function FindWin:PWindow;
var
  R:TRect;
  P:PWindow;
  Inp:PInput;
  Chk:PCheckBox;
  Rad:PRadioButton;
begin
  AssignRect(R, 0, 0, 350, 180);
  P:=New(PWindow,Init(R,'查找字符串',True));
  P^.Insert(New(PStaticText,Init(stNormal,20,30,'待查字串:',0)));
  Inp:=New(PInput,init(100,30,FindStr,28,ipBroad));
  P^.Insert(Inp);
  Chk:=New(PCheckBox,Init(20,60,160,140,'设置:'));
  Chk^.Insert('分辨大小写',fiSensitive);
  Chk^.Insert('整个字串匹配',fiWholeword);
  Chk^.Insert('查找选择区',fiScope);
  P^.Insert(Chk);
  Rad:=New(PRadioButton,Init(170,60,330,95,'方向:',fiDirection));
  Rad^.Insert('顺序');
  Rad^.Insert('倒序');
  P^.Insert(Rad);
  Rad:=New(PRadioButton,Init(170,105,330,140,'起点:',fiOrigin));
  Rad^.Insert('光标');
  Rad^.Insert('文件头');
  P^.Insert(Rad);
  P^.Insert(New(PButton,Init(130 ,150,190,170,'确定',kbAlto,cmOk)));
  P^.Insert(New(PButton,Init(200 ,150,260,170,'放弃',kbAltc,cmCancel)));
  P^.Insert(New(PButton,Init(270 ,150,330,170,'帮助',kbF1,cmHelp)));
  P^.Next;
  P^.Next;
  P^.Center;
  FindWin:=P;
end;

Function ReplaceWin:PWindow;
var
  R:TRect;
  P:PWindow;
  Inp:PInput;
  Chk:PCheckBox;
  Rad:PRadioButton;
begin
  AssignRect(R, 0, 0, 350, 215);
  P:=New(PWindow,Init(R,'替换字符串',True));
  P^.Insert(New(PStaticText,Init(stNormal,20,30,'原字串:',0)));
  Inp:=New(PInput,init(90,30,FindStr,30,ipBroad));
  P^.Insert(Inp);
  P^.Insert(New(PStaticText,Init(stNormal,20,55,'新字串:',0)));
  Inp:=New(PInput,init(90,55,ReplaceStr,30,ipBroad));
  P^.Insert(Inp);
  Chk:=New(PCheckBox,Init(20,85,160,175,'设置:'));
  Chk^.Insert('分辨大小写',fiSensitive);
  Chk^.Insert('整个字串匹配',fiWholeword);
  Chk^.Insert('替换时提示',fiPrompt);
  Chk^.Insert('查找选择区',fiScope);
  P^.Insert(Chk);
  Rad:=New(PRadioButton,Init(170,85,330,120,'方向:',fiDirection));
  Rad^.Insert('顺序');
  Rad^.Insert('倒序');
  P^.Insert(Rad);
  Rad:=New(PRadioButton,Init(170,140,330,175,'起点:',fiOrigin));
  Rad^.Insert('光标');
  Rad^.Insert('文件头');
  P^.Insert(Rad);
  P^.Insert(New(PButton,Init(30 ,185,120,205,'替换全部',kbAltA,cmYes)));
  P^.Insert(New(PButton,Init(130 ,185,190,205,'确定',kbAltO,cmOk)));
  P^.Insert(New(PButton,Init(200 ,185,260,205,'放弃',kbAltC,cmCancel)));
  P^.Insert(New(PButton,Init(270 ,185,330,205,'帮助',kbF1,cmHelp)));
  P^.Next;
  P^.Next;
  P^.Center;
  ReplaceWin:=P;
end;

Function GotoLineWin(var L:Integer):PWindow;
var
  R:TRect;
  P:PWindow;
begin
  AssignRect(R, 0, 0, 260, 100);
  P:=New(PWindow,Init(R,'跳转至特定行',True));
  P^.Insert(New(PStaticText,Init(stNormal,20,45,'行号:',4)));
  P^.Insert(New(PDigInput,Init(65,45,@L,12,ipBroad+ipDigital,dtInteger)));
  P^.Insert(New(PButton,Init(180, 40,240, 60,'确定',kbAltO,cmOk)));
  P^.Insert(New(PButton,Init(180, 70,240, 90,'放弃',kbAltC,cmCancel)));
  P^.Next;
  P^.Next;
  P^.Center;
  GotoLineWin:=P;
end;

Function SetupEditEnv:PWindow;
var
  R:TRect;
  P:PWindow;
  Q:PCheckBox;
begin
  AssignRect(R,0,0,340,180);
  P:=New(PWindow,Init(R,'设置编辑器环境',True));
  Q:=New(PCheckBox,Init(20,40,320,110,'编辑器选项:'));
  Q^.Insert('创建后备文件',BackFile);
  Q^.Insert('自动缩进模式',AutoIndent);
  Q^.Insert('删除行尾空格',DelTailSpace);
  Q^.Insert('显示行尾标志',HangTailFlag);
  Q^.Insert('生成制表符',ConvertTab);
  P^.Insert(Q);
  P^.Insert(New(PButton,Init(120,140,180,160,'确定',0,cmOk)));
  P^.Insert(New(PButton,Init(190,140,250,160,'放弃',0,cmCancel)));
  P^.Insert(New(PButton,Init(260,140,320,160,'帮助',kbF1,cmHelp)));
  P^.Next;
  P^.Center;
  SetupEditEnv:=P;
end;

Function SetEditColor:PWindow;
var
  P:PSetColorWin;
begin
  P:=New(PSetColorWin,Init('设置颜色',10));
  P^.InsertColor('正常文字颜色',edTxtColor,scFront+scBack);
  P^.InsertColor('选择文字颜色',edSigColor,scFront+scBack);
  P^.InsertColor('光标颜色',edMakColor,scFront);
  SetEditColor:=P;
end;

end.