unit Form_TextEditDialog;

{$I _crw_sysdef}

{$IFDEF FPC}{$mode Delphi}{$ENDIF}{$H+}

{$WARN 5023 off : Unit "$1" not used in $2}

interface

uses
 _crw_sharemem, // NB: THIS UNIT MUST BE FIRST !!!
 {$IFDEF UNIX} cthreads, dl, {$ENDIF}
 {$IFDEF WINDOWS} windows, {$ENDIF}
 sysutils, classes, math, lclintf, lcltype, lmessages,
 graphics, controls, forms, dialogs, stdctrls, buttons, extctrls,
 comctrls, clipbrd,
 _crw_alloc, _crw_rtc, _crw_ef, _crw_str, _crw_eldraw, _crw_fio,
 _crw_colors, _crw_appforms, _crw_apputils, _crw_apptools;

type

  { TFormTextEditDialog }

  TFormTextEditDialog = class(TMasterForm)
    PanelButtons: TPanel;
    BitBtnOk: TBitBtn;
    BitBtnCancel: TBitBtn;
    BitBtnCut: TBitBtn;
    BitBtnCopy: TBitBtn;
    BitBtnPaste: TBitBtn;
    BitBtnUndo: TBitBtn;
    BitBtnRefresh: TBitBtn;
    BitBtnFont: TBitBtn;
    FontDialog: TFontDialog;
    PanelEditor: TPanel;
    GroupBoxEditor: TGroupBox;
    Editor: TMemo;
    BitBtnSelectAll: TBitBtn;
    BitBtnSelectNone: TBitBtn;
    BitBtnGoToStart: TBitBtn;
    BitBtnGoToEnd: TBitBtn;
    procedure EditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure EditorKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure EditorMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure EditorMouseLeave(Sender: TObject);
    procedure EditorMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure BitBtnCutClick(Sender: TObject);
    procedure BitBtnCopyClick(Sender: TObject);
    procedure BitBtnPasteClick(Sender: TObject);
    procedure BitBtnUndoClick(Sender: TObject);
    procedure EditorChange(Sender: TObject);
    procedure EditorSelectionChange(Sender: TObject);
    procedure BitBtnRefreshClick(Sender: TObject);
    procedure BitBtnFontClick(Sender: TObject);
    procedure BitBtnSelectAllClick(Sender: TObject);
    procedure BitBtnSelectNoneClick(Sender: TObject);
    procedure BitBtnGoToStartClick(Sender: TObject);
    procedure BitBtnGoToEndClick(Sender: TObject);
  private
    { Private declarations }
    apFlags : Integer;
    procedure UpdateState;
  public
    { Public declarations }
    procedure ResetParams;
    function  ApplyParams(const Params:LongString):Integer;
  end;

function TextEditDialog(const aCaption    : LongString;
                        const aTitle      : LongString;
                        const aTextToEdit : TText;
                        const aParams     : LongString=''):TModalResult; overload;
function TextEditDialog(const aCaption    : LongString;
                        const aTitle      : LongString;
                        const aTextToEdit : LongString;
                        const aParams     : LongString='';
                              aResult     : PInteger=nil):LongString; overload;

const
  FormTextEditDialog : TFormTextEditDialog = nil;

implementation

{$R *.lfm}

const                 // ApplyParams flags:
 apFormL = $00000001; // Applied Form.Left
 apFormT = $00000002; // Applied Form.Top
 apFormW = $00000004; // Applied Form.Width
 apFormH = $00000008; // Applied Form.Height
 apFonts = $00000010; // Applied Panel.Font

function TextEditDialog(const aCaption    : LongString;
                        const aTitle      : LongString;
                        const aTextToEdit : TText;
                        const aParams     : LongString=''):TModalResult; overload;
var Temp:LongString;
begin
 Result:=mrCancel;
 if CanShowModal(FormTextEditDialog) then
 try
  if (FormTextEditDialog=nil) then begin
   Application.CreateForm(TFormTextEditDialog, FormTextEditDialog);
   FormTextEditDialog.Master:=@FormTextEditDialog;
   FormTextEditDialog.Show;
   FormTextEditDialog.Hide;
  end;
  if (FormTextEditDialog<>nil) then
  with FormTextEditDialog do
  try
   ResetParams;
   apFlags:=ApplyParams(aParams);
   if not HasFlags(apFlags,apFormL+apFormT) then LocateFormToCenterOfScreen(FormTextEditDialog);
   Caption:=aCaption;
   SmartUpdate(GroupBoxEditor,aTitle);
   Temp:=CreateTempFile('###.TMP');
   if FileExists(Temp) and (aTextToEdit.WriteFile(Temp)=0) then begin
    Editor.Lines.Clear;
    {$IFDEF SKIP_DRAFT}
    Editor.PlainText:=true;
    {$ENDIF ~SKIP_DRAFT}
    Editor.Lines.LoadFromFile(Temp);
    Editor.Modified:=false;
    Editor.SelStart:=0;
    Editor.SelLength:=0;
    BitBtnRefreshClick(FormTextEditDialog);
    {$IFDEF SKIP_DRAFT}
    Editor.ClearUndo;
    {$ENDIF ~SKIP_DRAFT}
    UpdateState;
    ValidateFormPosition(FormTextEditDialog);
    if (mrVoice(ShowModal)=mrOk) then
    if Editor.Modified then begin
     Result:=mrOk;
     Editor.Lines.SaveToFile(Temp);
     aTextToEdit.ReadFile(Temp);
    end;
    FileErase(Temp);
   end else begin
    Error(RusEng('Не могу редактировать текст, ошибка создания/записи временного файла!',
                 'Could not edit, temporary file create/write error!'));
   end;
   Editor.Lines.Clear;
  finally
   ResetParams;
  end;
 except
  on E:Exception do BugReport(E,nil,'TextEditDialog');
 end;
end;

function TextEditDialog(const aCaption    : LongString;
                        const aTitle      : LongString;
                        const aTextToEdit : LongString;
                        const aParams     : LongString='';
                              aResult     : PInteger=nil):LongString; overload;
var p:TText; res:Integer;
begin
 try
  p:=NewText;
  try
   p.Text:=aTextToEdit;
   res:=TextEditDialog(aCaption,aTitle,p,aParams);
   if (res=mrOk)
   then Result:=p.Text
   else Result:=aTextToEdit;
   if Assigned(aResult) then aResult^:=res;
  finally
   Kill(p);
  end;
 except
  on E:Exception do BugReport(E,nil,'TextEditDialog');
 end;
end;

procedure TFormTextEditDialog.FormCreate(Sender: TObject);
begin
 SetStandardFont(Self);
 BitBtnRefreshClick(Self);
 Editor.Font.Assign(Self.Font);
 SetAllButtonsCursor(Self,crHandPoint);
 SmartUpdate(BitBtnOk,mrCaption(mrOk));
 SmartUpdate(BitBtnCancel,mrCaption(mrCancel));
 BitBtnCut.Hint:=RusEng('Вырезка','Cut');
 BitBtnCopy.Hint:=RusEng('Копия','Copy');
 BitBtnPaste.Hint:=RusEng('Вставка','Paste');
 BitBtnUndo.Hint:=RusEng('Назад','Undo');
 BitBtnRefresh.Hint:=RusEng('Обновить','Refresh');
 BitBtnFont.Hint:=RusEng('Фонты','Fonts');
 BitBtnSelectAll.Hint:=RusEng('Выделить все','Select all');
 BitBtnSelectNone.Hint:=RusEng('Отменить выделение','Select none');
 BitBtnGoToStart.Hint:=RusEng('Перейти к началу','Go to start');
 BitBtnGoToEnd.Hint:=RusEng('Перейти к концу','Go to end');
 {$IFDEF SKIP_DRAFT}
 Editor.ClearUndo;
 {$ENDIF ~SKIP_DRAFT}
end;

procedure TFormTextEditDialog.ResetParams;
begin
 SetStandardFont(Self);
 PanelEditor.ParentFont:=true;
 Editor.ParentFont:=true;
 apFlags:=0;
end;

 // @set Panel.Font   Name:PT_Mono\Size:10\Color:Black\Style:[Regular]
 // @set Editor.Font  Name:PT_Mono\Size:10\Color:Black\Style:[Regular]
 // @set Form.Left    400  relative WindowName  ComponentName
 // @set Form.Top     400  relative WindowName  ComponentName
 // @set Form.Width   400
 // @set Form.Height  300
 // @set Form.Width   80  relative Screen
 // @set Form.Height  50  relative Desktop
function TFormTextEditDialog.ApplyParams(const Params:LongString):Integer;
var pars:TText; i,w,h,l,t:Integer; line:LongString; FontPars:TFontParams; p:TPoint;
begin
 Result:=0;
 if (Self<>nil) then
 if UseEditSettings then
 if (SysUtils.Trim(Params)<>'') then
 try
  pars:=NewText;
  try
   SafeFillChar(FontPars,SizeOf(FontPars),0);
   pars.Text:=SysUtils.Trim(Params);
   for i:=0 to pars.Count-1 do begin
    line:=Trim(pars[i]);
    if (StrFetch(line,1)='@') then begin
     if SameText(ExtractWord(1,line,ScanSpaces),'@set') then begin
      if SameText(ExtractWord(2,line,ScanSpaces),'Panel.Font') then begin
       if ReadBufferedFont(FontPars,ExtractWord(3,line,ScanSpaces),true,StandardFont)
       then RestoreFont(PanelEditor.Font,FontPars);
       Result:=Result or apFonts;
      end;
      if SameText(ExtractWord(2,line,ScanSpaces),'Editor.Font') then begin
       if ReadBufferedFont(FontPars,ExtractWord(3,line,ScanSpaces),true,StandardFont)
       then RestoreFont(Editor.Font,FontPars);
       Result:=Result or apFonts;
      end;
      if SameText(ExtractWord(2,line,ScanSpaces),'Form.Width') then begin
       if Str2Int(ExtractWord(3,line,ScanSpaces),w) then begin
        if SameText(ExtractWord(4,line,ScanSpaces),'relative')
        then w:=FindRelativeSize(Point(w,0),ExtractWord(5,line,ScanSpaces),ExtractWord(6,line,ScanSpaces)).x;
        Width:=w;
        Result:=Result or apFormW;
       end;
      end;
      if SameText(ExtractWord(2,line,ScanSpaces),'Form.Height') then begin
       if Str2Int(ExtractWord(3,line,ScanSpaces),h) then begin
        if SameText(ExtractWord(4,line,ScanSpaces),'relative')
        then h:=FindRelativeSize(Point(0,h),ExtractWord(5,line,ScanSpaces),ExtractWord(6,line,ScanSpaces)).y;
        Height:=h;
        Result:=Result or apFormH;
       end;
      end;
      if SameText(ExtractWord(2,line,ScanSpaces),'Form.Left') then begin
       if Str2Int(ExtractWord(3,line,ScanSpaces),l) then begin
        p:=Point(l,0);
        if SameText(ExtractWord(4,line,ScanSpaces),'relative')
        then p:=FindRelativePos(p,ExtractWord(5,line,ScanSpaces),ExtractWord(6,line,ScanSpaces));
        Left:=p.x;
        Result:=Result or apFormL;
       end;
      end;
      if SameText(ExtractWord(2,line,ScanSpaces),'Form.Top') then begin
       if Str2Int(ExtractWord(3,line,ScanSpaces),t) then begin
        p:=Point(0,t);
        if SameText(ExtractWord(4,line,ScanSpaces),'relative')
        then p:=FindRelativePos(p,ExtractWord(5,line,ScanSpaces),ExtractWord(6,line,ScanSpaces));
        Top:=p.y;
        Result:=Result or apFormT;
       end;
      end;
     end;
    end;
   end;
  finally
   Kill(pars);
  end;
 except
  on E:Exception do BugReport(E,Self,'ApplyParams');
 end;
end;

procedure TFormTextEditDialog.FormActivate(Sender: TObject);
begin
 UpdateState;
end;

procedure TFormTextEditDialog.UpdateState;
begin
 try
  BitBtnCut.Enabled:=(Editor.SelLength>0);
  BitBtnCopy.Enabled:=(Editor.SelLength>0);
  BitBtnPaste.Enabled:=Clipboard.HasFormat(CF_TEXT);
  BitBtnUndo.Enabled:=Editor.CanUndo;
  ActiveControl:=Editor;
 except
  on E:Exception do BugReport(E,Self,'UpdateState');
 end;
end;

procedure TFormTextEditDialog.BitBtnCutClick(Sender: TObject);
begin
 Editor.CutToClipboard;
 UpdateState;
end;

procedure TFormTextEditDialog.BitBtnCopyClick(Sender: TObject);
begin
 Editor.CopyToClipboard;
 UpdateState;
end;

procedure TFormTextEditDialog.BitBtnPasteClick(Sender: TObject);
begin
 Editor.PasteFromClipboard;
 UpdateState;
end;

procedure TFormTextEditDialog.BitBtnUndoClick(Sender: TObject);
begin
 if Editor.CanUndo then Editor.Undo;
 UpdateState;
 {$IFDEF SKIP_DRAFT}
 // TODO: TMemo.Undo not supported
 {$ENDIF ~SKIP_DRAFT}
end;

procedure TFormTextEditDialog.EditorChange(Sender: TObject);
begin
 // if Editor.Modified then UpdateState;
 UpdateState;
end;

procedure TFormTextEditDialog.EditorSelectionChange(Sender: TObject);
begin
 UpdateState;
 {$IFDEF SKIP_DRAFT}
 // TODO
 {$ENDIF ~SKIP_DRAFT}
end;

procedure TFormTextEditDialog.BitBtnRefreshClick(Sender: TObject);
var aModified:Boolean;
begin
 try
  aModified:=Editor.Modified;
  {$IFDEF SKIP_DRAFT}
  Editor.DefAttributes.Assign(Editor.Font);
  Editor.SelAttributes.Assign(Editor.Font);
  RefreshEditAttributes(Editor,true,SCF_ALL);
  {$ENDIF ~SKIP_DRAFT}
  Editor.Modified:=aModified;
  UpdateState;
 except
  on E:Exception do BugReport(E,Self,'BitBtnRefreshClick');
 end;
end;

procedure TFormTextEditDialog.BitBtnFontClick(Sender: TObject);
var aModified:Boolean;
begin
 try
  FontDialog.Font.Assign(Editor.Font);
  if FontDialog.Execute then begin
   aModified:=Editor.Modified;
   Editor.Font.Assign(FontDialog.Font);
   BitBtnRefreshClick(Sender);
   Editor.Modified:=aModified;
  end;
  UpdateState;
 except
  on E:Exception do BugReport(E,Self,'BitBtnFontClick');
 end;
end;

procedure TFormTextEditDialog.BitBtnSelectAllClick(Sender: TObject);
begin
 Editor.SelectAll;
 UpdateState;
end;

procedure TFormTextEditDialog.BitBtnSelectNoneClick(Sender: TObject);
begin
 Editor.SelLength:=0;
 UpdateState;
end;

procedure TFormTextEditDialog.BitBtnGoToStartClick(Sender: TObject);
begin
 Editor.SelLength:=0;
 Editor.SelStart:=0;
 UpdateState;
end;

procedure TFormTextEditDialog.BitBtnGoToEndClick(Sender: TObject);
begin
 Editor.SelLength:=0;
 Editor.SelStart:=MaxInt;
 UpdateState;
end;

procedure TFormTextEditDialog.EditorKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
 UpdateState;
end;

procedure TFormTextEditDialog.EditorKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
 UpdateState;
end;

procedure TFormTextEditDialog.EditorMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
 UpdateState;
end;

procedure TFormTextEditDialog.EditorMouseLeave(Sender: TObject);
begin
 UpdateState;
end;

procedure TFormTextEditDialog.EditorMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
 UpdateState;
end;

end.

