unit TStdDlg;

{$F+,O+,S-,V-,X+}

interface

uses Objects, Drivers, Views, Dialogs, TDos;

const

  cmFileOpen    = 1010;
  cmFileReplace = 1011;
  cmFileClear   = 1012;
  cmFileInit    = 1013;
  cmChangeDir   = 1020;
  cmRevert      = 1021;


  cmFileFocused       = 102;
  cmFileDoubleClicked = 103;

type

  TSearchRec = record
    Attr: Byte;
    Time: Longint;
    Size: Longint;
    Name: string[12];
  end;

type

  PFileInputLine = ^TFileInputLine;
  TFileInputLine = object(TInputLine)
    constructor Init(var Bounds: TRect; AMaxLen: Integer);
    procedure HandleEvent(var Event: TEvent); virtual;
  end;

  PFileCollection = ^TFileCollection;
  TFileCollection = object(TSortedCollection)
    function Compare(Key1, Key2: Pointer): Integer; virtual;
    procedure FreeItem(Item: Pointer); virtual;
    function GetItem(var S: TStream): Pointer; virtual;
    procedure PutItem(var S: TStream; Item: Pointer); virtual;
  end;

  PSortedListBox = ^TSortedListBox;
  TSortedListBox = object(TListBox)
    SearchPos: Word;
    ShiftState: Byte;
    constructor Init(var Bounds: TRect; ANumCols: Word;
      AScrollBar: PScrollBar);
    procedure HandleEvent(var Event: TEvent); virtual;
    function GetKey(var S: String): Pointer; virtual;
    procedure NewList(AList: PCollection); virtual;
  end;

  PFileList = ^TFileList;
  TFileList = object(TSortedListBox)
    constructor Init(var Bounds: TRect; AWildCard: PathStr;
      AScrollBar: PScrollBar);
    destructor Done; virtual;
    function DataSize: Word; virtual;
    procedure FocusItem(Item: Integer); virtual;
    procedure GetData(var Rec); virtual;
    function GetText(Item: Integer; MaxLen: Integer): String; virtual;
    function GetKey(var S: String): Pointer; virtual;
    procedure HandleEvent(var Event: TEvent); virtual;
    procedure ReadDirectory(AWildCard: PathStr);
    procedure SetData(var Rec); virtual;
  end;

  PFileInfoPane = ^TFileInfoPane;
  TFileInfoPane = object(TView)
    S: TSearchRec;
    constructor Init(var Bounds: TRect);
    procedure Draw; virtual;
    function GetPalette: PPalette; virtual;
    procedure HandleEvent(var Event: TEvent); virtual;
  end;

  TWildStr = PathStr;

const

  fdOkButton      = $0001;
  fdOpenButton    = $0002;
  fdReplaceButton = $0004;
  fdClearButton   = $0008;

type

  PFileDialog = ^TFileDialog;
  TFileDialog = object(TDialog)
    FileName: PFileInputLine;
    FileList: PFileList;
    WildCard: TWildStr;
    Directory: PString;
    constructor Init(AWildCard: TWildStr; ATitle: String;
      InputName: String; AOptions: Word; HistoryId: Byte; AHelpCtx: Word);
    constructor Load(var S: TStream);
    destructor Done; virtual;
    procedure GetData(var Rec); virtual;
    procedure GetFileName(var S: PathStr);
    procedure HandleEvent(var Event: TEvent); virtual;
    procedure SetData(var Rec); virtual;
    procedure Store(var S: TStream);
    function Valid(Command: Word): Boolean; virtual;
  end;

  PDirListBox = ^TDirListBox;
  TDirListBox = object(TListBox)
    Dir: DirStr;
    Cur: Word;
    constructor Init(var Bounds: TRect; AScrollBar: PScrollBar);
    destructor Done; virtual;
    function GetText(Item: Integer; MaxLen: Integer): String; virtual;
    procedure HandleEvent(var Event: TEvent); virtual;
    function IsSelected(Item: Integer): Boolean; virtual;
    procedure NewDirectory(var ADir: DirStr);
    procedure SetState(AState: Word; Enable: Boolean); virtual;
  end;

type

  PChDirDialog = ^TChDirDialog;
  TChDirDialog = object(TDialog)
    DirInput: PInputLine;
    DirList: PDirListBox;
    OkButton: PButton;
    ChDirButton: PButton;
    constructor Init(HistoryId: Word);
    constructor Load(var S: TStream);
    function DataSize: Word; virtual;
    procedure GetData(var Rec); virtual;
    procedure HandleEvent(var Event: TEvent); virtual;
    procedure SetData(var Rec); virtual;
    procedure Store(var S: TStream);
    function Valid(Command: Word): Boolean; virtual;
  end;

PSecretCopyright = ^TSecretCopyright;
TSecretCopyright = object(TStaticText)
  constructor Init(var Bounds: TRect; AText: String);
  procedure HandleEvent(var Event: TEvent); virtual;
end;

PMouseDialog = ^TMouseDialog;
TMouseDialog = object(TDialog)
  ScrollBar: PscrollBar;
  DoubleDel: Word;
  constructor Init;
  constructor Load(var S: TStream);
  procedure HandleEvent(var Event: TEvent); virtual;
  procedure Store(var S: TStream);
end;

PHelpDialog = ^THelpDialog;
THelpDialog = object(TDialog)
  HelpView: PView;
  constructor Load(var S: TStream);
  function GetPalette: PPalette; virtual;
  procedure HandleEvent(var Event: TEvent); virtual;
  procedure Store(var S: TStream);
end;

PReplaceDialog = ^TReplaceDialog;
TReplaceDialog = object(TDialog)
  constructor Init;
  procedure HandleEvent(var Event: TEvent); virtual;
end;

PSizesDialog = ^TSizesDialog;
TSizesDialog = object(TDialog)
  LowHeap: PView;
  HighHeap: PView;
  constructor Init;
  constructor Load(var S: TStream);
  function Valid(Command: Word): Boolean; virtual;
  procedure Store(var S: TStream);
end;

const

  CInfoPane   = #30;
  CHelpDialog = #32#33#34#35#36#37#38#39#40#41#42#43#44#45#46#47 +
	        #48#49#50#51#52#53#54#55#56#57#58#59#60#61#62#63 +
	        #85#86#87#88#89#90#91#92;

  RFileInputLine: TStreamRec = (
     ObjType: 3001;
     VmtLink: Ofs(TypeOf(TFileInputLine)^);
     Load:    @TFileInputLine.Load;
     Store:   @TFileInputLine.Store
  );
  RFileCollection: TStreamRec = (
     ObjType: 3002;
     VmtLink: Ofs(TypeOf(TFileCollection)^);
     Load:    @TFileCollection.Load;
     Store:   @TFileCollection.Store
  );
  RFileList: TStreamRec = (
     ObjType: 3003;
     VmtLink: Ofs(TypeOf(TFileList)^);
     Load:    @TFileList.Load;
     Store:   @TFileList.Store
  );
  RFileInfoPane: TStreamRec = (
     ObjType: 3004;
     VmtLink: Ofs(TypeOf(TFileInfoPane)^);
     Load:    @TFileInfoPane.Load;
     Store:   @TFileInfoPane.Store
  );
  RFileDialog: TStreamRec = (
     ObjType: 3005;
     VmtLink: Ofs(TypeOf(TFileDialog)^);
     Load:    @TFileDialog.Load;
     Store:   @TFileDialog.Store
  );
  RDirListBox: TStreamRec = (
     ObjType: 3006;
     VmtLink: Ofs(TypeOf(TDirListBox)^);
     Load:    @TDirListBox.Load;
     Store:   @TDirListBox.Store
  );
  RChDirDialog: TStreamRec = (
     ObjType: 3007;
     VmtLink: Ofs(TypeOf(TChDirDialog)^);
     Load:    @TChDirDialog.Load;
     Store:   @TChDirDialog.Store
  );
  RSecretCopyright: TStreamRec = (
    ObjType: 3008;
    VmtLink: Ofs(TypeOf(TSecretCopyright)^);
    Load:    @TSecretCopyright.Load;
    Store:   @TSecretCopyright.Store
  );
  RMouseDialog: TStreamRec = (
    ObjType: 3090;
    VmtLink: Ofs(TypeOf(TMouseDialog)^);
    Load:    @TMouseDialog.Load;
    Store:   @TMouseDialog.Store
  );
  RHelpDialog: TStreamRec = (
    ObjType: 3091;
    VmtLink: Ofs(TypeOf(THelpDialog)^);
    Load:    @THelpDialog.Load;
    Store:   @THelpDialog.Store
  );
  RReplaceDialog: TStreamRec = (
    ObjType: 3092;
    VmtLink: Ofs(TypeOf(TReplaceDialog)^);
    Load:    @TReplaceDialog.Load;
    Store:   @TReplaceDialog.Store
  );
  RSizesDialog: TStreamRec = (
    ObjType: 3093;
    VmtLink: Ofs(TypeOf(TSizesDialog)^);
    Load:    @TSizesDialog.Load;
    Store:   @TSizesDialog.Store
  );

function  FindDialog: PDialog;
function  GotoLineDialog: PDialog;
function  FindProcDialog: PDialog;
function  FindErrorDialog: PDialog;
function  ParamsDialog: PDialog;
function  CompilerOptionsDialog: PDialog;
function  LinkerDialog: PDialog;
function  DebuggingDialog: PDialog;
function  DirectoriesDialog: PDialog;
function  PreferencesDialog: PDialog;
function  EditorOptionsDialog: PDialog;
function  StartupOptionsDialog: PDialog;
function  AboutDialog: PDialog;
function  GetInfoDialog: PDialog;

procedure RegisterTStdDlg;

implementation

uses Memory, HistList, App, Utils, TVars, Controls, Context, StrNames;

type
  PSearchRec = ^TSearchRec;

function IsWild(var S: String): Boolean;
begin
  IsWild := (Pos('?', S) > 0) or (Pos('*', S) > 0);
end;

function IsDir(var S: String): Boolean;
var
  SR: SearchRec;
begin
  if FindFirst(S, Directory, SR) = 0 then
    IsDir := SR.Attr and Directory <> 0
  else
    IsDir := False;
end;

function GetCurDir: DirStr;
var
  CurDir: DirStr;
begin
  CurDir := TDos.GetCurDir(#0);
  if Length(CurDir) <> 3 then
  asm
        LEA     DI,CurDir
        INC     BYTE PTR [DI]
        XOR     BX,BX
        MOV     BL,[DI]
        MOV     BYTE PTR [BX+DI],'\'
  end;
  GetCurDir := CurDir;
end;

constructor TFileInputLine.Init(var Bounds: TRect; AMaxLen: Integer);
begin
  TInputLine.Init(Bounds, AMaxLen);
  EventMask := EventMask or evBroadcast;
end;

procedure TFileInputLine.HandleEvent(var Event: TEvent);
var
  Dir: DirStr;
  Name: NameStr;
  Ext: ExtStr;
begin
  TInputLine.HandleEvent(Event);
  if (Event.What = evBroadcast) and (Event.Command = cmFileFocused) and
    (State and sfSelected = 0) then
  begin
     if PSearchRec(Event.InfoPtr)^.Attr and Directory <> 0 then
	Data^ := PSearchRec(Event.InfoPtr)^.Name + '\' +
	  PFileDialog(Owner)^.WildCard
     else
       Data^ := PSearchRec(Event.InfoPtr)^.Name;
     DrawView;
  end;
end;

function TFileCollection.Compare(Key1, Key2: Pointer): Integer;
begin
  if PSearchRec(Key1)^.Name = PSearchRec(Key2)^.Name then
    Compare := 0
  else if PSearchRec(Key1)^.Name = '..' then
    Compare := 1
  else if PSearchRec(Key2)^.Name = '..' then
    Compare := -1
  else if (PSearchRec(Key1)^.Attr and Directory <> 0) and
    (PSearchRec(Key2)^.Attr and Directory = 0) then
    Compare := 1
  else if (PSearchRec(Key2)^.Attr and Directory <> 0) and
    (PSearchRec(Key1)^.Attr and Directory = 0) then
    Compare := -1
  else if PSearchRec(Key1)^.Name > PSearchRec(Key2)^.Name then
    Compare := 1
  else
    Compare := -1;
end;

procedure TFileCollection.FreeItem(Item: Pointer);
begin
  Dispose(PSearchRec(Item));
end;

function TFileCollection.GetItem(var S: TStream): Pointer;
var
  Item: PSearchRec;
begin
  New(Item);
  S.Read(Item^, SizeOf(TSearchRec));
  GetItem := Item;
end;

procedure TFileCollection.PutItem(var S: TStream; Item: Pointer);
begin
  S.Write(Item^, SizeOf(TSearchRec));
end;

constructor TSortedListBox.Init(var Bounds: TRect; ANumCols: Word;
  AScrollBar: PscrollBar);
begin
  TListBox.Init(Bounds, ANumCols, AScrollBar);
  SearchPos := 0;
  ShowCursor;
  SetCursor(1, 0);
end;

procedure TSortedListBox.HandleEvent(var Event: TEvent);
var
  ShiftKeys: Byte absolute $40:$17;
  CurString, NewString: String;
  K: Pointer;
  Value, OldPos, OldValue: Integer;
  T: Boolean;

function Equal(var S1: String; var S2: String; Count: Word): Boolean;
var
  I: Word;
begin
  Equal := False;
  if (Length(S1) < Count) or (Length(S2) < Count) then
    Exit;
  for I := 1 to Count do
    if UpCase(S1[I]) <> UpCase(S2[I]) then
      Exit;
  Equal := True;
end;

begin
  OldValue := Focused;
  TListBox.HandleEvent(Event);
  if OldValue <> Focused then
    SearchPos := 0;
  if Event.What = evKeyDown then
  begin
    if Event.CharCode <> #0 then
    begin
      Value := Focused;
      if Value < Range then
        CurString := GetText(Value, 255)
      else
        CurString := '';
      OldPos := SearchPos;
      if Event.KeyCode = kbBack then
      begin
	if SearchPos = 0 then
          Exit;
	Dec(SearchPos);
	if SearchPos = 0 then
          ShiftState := ShiftKeys;
	CurString[0] := Char(SearchPos);
      end
      else if (Event.CharCode = '.') then
        SearchPos := Pos('.',CurString)
      else
      begin
	Inc(SearchPos);
	if SearchPos = 1 then
          ShiftState := ShiftKeys;
	CurString[0] := Char(SearchPos);
	CurString[SearchPos] := Event.CharCode;
      end;
      K := GetKey(CurString);
      T := PSortedCollection(List)^.Search(K, Value);
      if Value < Range then
      begin
	if Value < Range then
          NewString := GetText(Value, 255)
	else
          NewString := '';
	if Equal(NewString, CurString, SearchPos) then
	begin
	  if Value <> OldValue then
	  begin
	    FocusItem(Value);
	    SetCursor(Cursor.X + SearchPos, Cursor.Y);
	  end
	  else SetCursor(Cursor.X + (SearchPos - OldPos), Cursor.Y);
	end
	else SearchPos := OldPos;
      end
      else SearchPos := OldPos;
      if (SearchPos <> OldPos) or (Event.CharCode in ['A'..'Z', 'a'..'z']) then
	ClearEvent(Event);
    end;
  end;
end;

function TSortedListBox.GetKey(var S: String): Pointer;
begin
  GetKey := @S;
end;

procedure TSortedListBox.NewList(AList: PCollection);
begin
  TListBox.NewList(AList);
  SearchPos := 0;
end;

constructor TFileList.Init(var Bounds: TRect; AWildCard: PathStr;
  AScrollBar: PscrollBar);
begin
  TSortedListBox.Init(Bounds, 2, AScrollBar);
end;

destructor TFileList.Done;
begin
  if List <> nil then
    Dispose(List, Done);
  TListBox.Done;
end;

function TFileList.DataSize: Word;
begin
  DataSize := 0;
end;

procedure TFileList.FocusItem(Item: Integer);
begin
  TSortedListBox.FocusItem(Item);
  Message(Owner, evBroadcast, cmFileFocused, List^.At(Item));
end;

procedure TFileList.GetData(var Rec);
begin
end;

function TFileList.GetKey(var S: String): Pointer;
const
  SR: TSearchRec = ();

procedure UpStr(var S: String);
var
  I: Integer;
begin
  for I := 1 to Length(S) do
    S[I] := UpCase(S[I]);
end;

begin
  if (ShiftState and (kbRightShift + kbLeftShift) <> 0) or
    ((S <> '') and (S[1] = '.')) then
    SR.Attr := Directory
  else
    SR.Attr := 0;
  SR.Name := S;
  UpStr(SR.Name);
  GetKey := @SR;
end;

function TFileList.GetText(Item: Integer; MaxLen: Integer): String;
var
  S: String;
  SR: PSearchRec;
begin
  SR := PSearchRec(List^.At(Item));
  S := SR^.Name;
  if SR^.Attr and Directory <> 0 then
  begin
    S[Length(S)+1] := '\';
    Inc(S[0]);
  end;
  GetText := S;
end;

procedure TFileList.HandleEvent(var Event: TEvent);
begin
  if (Event.What = evMouseDown) and (Event.Double) then
  begin
    Event.What := evCommand;
    Event.Command := cmOK;
    PutEvent(Event);
    ClearEvent(Event);
  end
  else TSortedListBox.HandleEvent(Event);
end;

procedure TFileList.ReadDirectory(AWildCard: PathStr);
const
  FindAttr = ReadOnly + Archive;
  AllFiles = '*.*';
  PrevDir  = '..';
var
  S: SearchRec;
  P: PSearchRec;
  FileList: PFileCollection;
  NumFiles: Word;
  CurPath: PathStr;
  Dir: DirStr;
  Name: NameStr;
  Ext: ExtStr;
  Event: TEvent;
  Tmp: PathStr;
  Flag: Integer;
begin
  NumFiles := 0;
  FExpand(AWildCard, AWildCard);
  FSplit(AWildCard, Dir, Name, Ext);
  FileList := New(PFileCollection, Init(5, 5));
  Flag := FindFirst(AWildCard, FindAttr, S);
  P := @P;
  while (P <> nil) and (Flag = 0) do
  begin
    if (S.Attr and Directory = 0) then
    begin
      P := MemAlloc(SizeOf(P^));
      if P <> nil then
      begin
	Move(S.Attr, P^, SizeOf(P^));
	FileList^.Insert(P);
      end;
    end;
    Flag := FindNext(S);
  end;
  Tmp := Dir + AllFiles;
  Flag := FindFirst(Tmp, Directory, S);
  while (P <> nil) and (Flag = 0) do
  begin
    if (S.Attr and Directory <> 0) and (S.Name[1] <> '.') then
    begin
      P := MemAlloc(SizeOf(P^));
      if P <> nil then
      begin
	Move(S.Attr, P^, SizeOf(P^));
	FileList^.Insert(PObject(P));
      end;
    end;
    Flag := FindNext(S);
  end;
  if Length(Dir) > 4 then
  begin
    P := MemAlloc(SizeOf(P^));
    if P <> nil then
    begin
      FindFirst(Tmp, Directory, S);
      if (FindNext(S) = 0) and (S.Name = PrevDir) then
	Move(S.Attr, P^, SizeOf(P^))
      else
      begin
	P^.Name := PrevDir;
	P^.Size := 0;
	P^.Time := $210000;
	P^.Attr := Directory;
      end;
      FileList^.Insert(PObject(P));
    end;
  end;
  if P = nil
    then MessageBox(sTooManyFiles, nil, mfWarning + mfOkButton);
  NewList(FileList);
  if List^.Count > 0 then
  begin
    Event.What := evBroadcast;
    Event.Command := cmFileFocused;
    Event.InfoPtr := List^.At(0);
    Owner^.HandleEvent(Event);
  end;
end;

procedure TFileList.SetData(var Rec);
begin
  with PFileDialog(Owner)^ do
    Self.ReadDirectory(Directory^ + WildCard);
end;

constructor TFileInfoPane.Init(var Bounds: TRect);
begin
  TView.Init(Bounds);
  EventMask := EventMask or evBroadcast;
end;

procedure TFileInfoPane.Draw;
var
  B: TDrawBuffer;
  D: String[9];
  M: String[3];
  PM: Boolean;
  Color: Word;
  Time: DateTime;
  Path: PathStr;
  FmtId: Integer;
  Params: array[0..7] of LongInt;
  Str: String[80];
begin
  FExpand(PFileDialog(Owner)^.Directory^ + PFileDialog(Owner)^.WildCard, Path);
  Color := GetColor($01);
  MoveChar(B, ' ', Color, Size.X);
  MoveStr(B[1], Path, Color);
  WriteLine(0, 0, Size.X, 1, B);
  Params[0] := LongInt(@S.Name);
  MoveChar(B, ' ', Color, Size.X);
  Params[0] := LongInt(@S.Name);
  if S.Attr and Directory <> 0 then
  begin
    FmtId := sFileLine;
    D := Strings^.Get(sDirectory);
    Params[1] := LongInt(@D);
  end else
  begin
    FmtId := sDirectoryLine;
    Params[1] := S.Size;
  end;
  UnpackTime(S.Time, Time);
  M := Strings^.Get(Time.Month + sMonthBase);
  Params[2] := LongInt(@M);
  Params[3] := Time.Day;
  Params[4] := Time.Year;
  PM := Time.Hour >= 12;
  Time.Hour := Time.Hour mod 12;
  if Time.Hour = 0 then
    Time.Hour := 12;
  Params[5] := Time.Hour;
  Params[6] := Time.Min;
  if PM then
    Params[7] := Byte('p')
  else
    Params[7] := Byte('a');
  FormatStr(Str, Strings^.Get(FmtId), Params);
  MoveStr(B, Str, Color);
  WriteLine(0, 1, Size.X, 1, B);
  MoveChar(B, ' ', Color, Size.X);
  WriteLine(0, 2, Size.X, Size.Y - 2, B);
end;

function TFileInfoPane.GetPalette: PPalette;
const
  P: String[Length(CInfoPane)] = CInfoPane;
begin
  GetPalette := @P;
end;

procedure TFileInfoPane.HandleEvent(var Event: TEvent);
begin
  TView.HandleEvent(Event);
  if (Event.What = evBroadcast) and (Event.Command = cmFileFocused) then
  begin
    S := PSearchRec(Event.InfoPtr)^;
    DrawView;
  end;
end;

constructor TFileDialog.Init(AWildCard: TWildStr; ATitle: String;
  InputName: String; AOptions: Word; HistoryId: Byte; AHelpCtx: Word);
var
  Control: PView;
  R: TRect;
  S: String;
  Opt: Word;
  ACurDir: PathStr;
  Y: Integer;
begin
  R.Assign(15, 1, 64, 20);
  TDialog.Init(R, ATitle);
  Options := Options or ofCentered;
  WildCard := AWildCard;
  R.Assign(3, 3, 31, 4);
  FileName := PFileInputLine(SetHelp(
    New(PFileInputLine, Init(R, 79)), AHelpCtx));
  FileName^.Data^ := WildCard;
  Inc(AHelpCtx);
  Insert(FileName);
  Insert(StandardLabel(InputName, FileName, lfTop));
  Insert(StandardHistory(FileName, HistoryId));
  R.Assign(3, 14, 34, 15);
  Control := New(PScrollBar, Init(R));
  Insert(Control);
  R.Assign(3, 6, 34, 14);
  FileList := PFileList(SetHelp(
    New(PFileList, Init(R, WildCard, PScrollBar(Control))), AHelpCtx));
  Inc(AHelpCtx);
  Insert(FileList);
  Insert(StandardLabel('~F~iles', FileList, lfTop));
  Opt := bfDefault;
  Y := 3;
  if AOptions and fdOpenButton <> 0 then
  begin
    Insert(NewButton(35, Y, 11, '~O~pen', cmFileOpen, Opt, AHelpCtx));
    Inc(AHelpCtx);
    Opt := bfNormal;
    Inc(Y, 3);
  end;
  if AOptions and fdOkButton <> 0 then
  begin
    Insert(NewButton(35, Y, 11, 'O~K~', cmOK, Opt, hcOkButton));
    Opt := bfNormal;
    Inc(Y, 3);
  end;
  if AOptions and fdReplaceButton <> 0 then
  begin
    Insert(NewButton(35, Y, 11, '~R~eplace', cmFileReplace, Opt, AHelpCtx));
    Inc(AHelpCtx);
    Opt := bfNormal;
    Inc(Y, 3);
  end;
  if AOptions and fdClearButton <> 0 then
  begin
    Insert(NewButton(35, Y, 11, '~C~lear', cmFileClear, Opt, AHelpCtx));
    Inc(AHelpCtx);
  end;
  Insert(NewButton(35, 11, 11, 'Cancel', cmCancel, bfNormal, hcCnlButton));
  Insert(NewButton(35, 14, 11, 'Help', cmHelp, bfNormal, AHelpCtx));
  R.Assign(1, 16, 48, 18);
  Insert(New(PFileInfoPane, Init(R)));
  SelectNext(False);
end;

constructor TFileDialog.Load(var S: TStream);
var
  ACurDir: DirStr;
  ViewId: Word;
begin
  TDialog.Load(S);
  S.Read(WildCard, SizeOf(TWildStr));
  ACurDir := GetCurDir;
  Directory := NewStr(ACurDir);
  GetSubViewPtr(S, FileName);
  GetSubViewPtr(S, FileList);
end;

destructor TFileDialog.Done;
begin
  DisposeStr(Directory);
  TDialog.Done;
end;

procedure TFileDialog.GetData(var Rec);
begin
  GetFilename(PathStr(Rec));
end;

procedure TFileDialog.GetFileName(var S: PathStr);
var
  Path: PathStr;
  Name: NameStr;
  Ext: ExtStr;
  TPath: PathStr;
  TName: NameStr;
  TExt: NameStr;

function LTrim(S: String): String;
var
  I: Integer;
begin
  I := 1;
  while (I < Length(S)) and (S[I] = ' ') do
    Inc(I);
  LTrim := Copy(S, I, 255);
end;

function RTrim(S: String): String;
var
  I: Integer;
begin
  while S[Length(S)] = ' ' do
    Dec(S[0]);
  RTrim := S;
end;

function RelativePath(var S: PathStr): Boolean;
var
  I, J: Integer;
  P: PathStr;
begin
  S := LTrim(RTrim(S));
  if (S <> '') and ((S[1] = '\') or (S[2] = ':')) then
    RelativePath := False
  else
    RelativePath := True;
end;

function NoWildChars(var S: String): String; assembler;
asm
	PUSH    DS
	LDS     SI,S
	XOR     AX,AX
	LODSB
	XCHG    AX,CX
	LES     DI,@Result
	INC     DI
@@1:    LODSB
	CMP     AL,'?'
	JE      @@2
	CMP     AL,'*'
	JE      @@2
	STOSB
@@2:    LOOP    @@1
	XCHG    AX,DI
	MOV     DI,WORD PTR @Result
	SUB     AX,DI
	DEC     AX
	STOSB
	POP     DS
end;

begin
  S := FileName^.Data^;
  if RelativePath(S) then
    FExpand(Directory^ + S, S)
  else
    FExpand(S, S);
  FSplit(S, Path, Name, Ext);
  if ((Name = '') or (Ext = '')) and not IsDir(S) then
  begin
    FSplit(WildCard, TPath, TName, TExt);
    if (Name = '') and (Ext = '') then
      S := Path + TName + TExt
    else if Name = '' then
      S := Path + TName + Ext
    else if Ext = '' then
      if IsWild(Name) then
        S := Path + Name + TExt
      else
        S := Path + Name + NoWildChars(TExt);
  end;
end;

procedure TFileDialog.HandleEvent(var Event: TEvent);
begin
  TDialog.HandleEvent(Event);
  if Event.What = evCommand then
    case Event.Command of
      cmFileOpen, cmFileReplace, cmFileClear:
	begin
	  EndModal(Event.Command);
	  ClearEvent(Event);
	end;
    end;
end;

procedure TFileDialog.SetData(var Rec);
begin
  TDialog.SetData(Rec);
  if (PathStr(Rec) <> '') and (IsWild(TWildStr(Rec))) then
  begin
    Valid(cmFileInit);
    FileName^.Select;
  end;
end;

procedure TFileDialog.Store(var S: TStream);
begin
  TDialog.Store(S);
  S.Write(WildCard, SizeOf(TWildStr));
  PutSubViewPtr(S, FileName);
  PutSubViewPtr(S, FileList);
end;

function TFileDialog.Valid(Command: Word): Boolean;
var
  T: Boolean;
  FName: PathStr;
  Dir: DirStr;
  Name: NameStr;
  Ext: ExtStr;

function CheckDirectory(var S: PathStr): Boolean;
begin
  if not DirExists(S) then
  begin
    MessageBox(sInvalidDir, nil, mfError + mfOkButton);
    FileName^.Select;
    CheckDirectory := False;
  end else CheckDirectory := True;
end;

begin
  if Command = cmValid then
  begin
    Valid := True;
    Exit;
  end else
    Valid := False;
  if TDialog.Valid(Command) then
  begin
    GetFileName(FName);
    if (Command <> cmCancel) and (Command <> cmFileClear) then
    begin
      if IsWild(FName) then
      begin
	FSplit(FName, Dir, Name, Ext);
	if CheckDirectory(Dir) then
	begin
	  DisposeStr(Directory);
	  Directory := NewStr(Dir);
	  WildCard := Name + Ext;
	  if Command <> cmFileInit then
            FileList^.Select;
	  FileList^.ReadDirectory(Directory^ + WildCard);
	end
      end
      else if IsDir(FName) then
      begin
	if CheckDirectory(FName) then
	begin
	  DisposeStr(Directory);
	  Directory := NewSTr(FName+'\');
	  if Command <> cmFileInit then
            FileList^.Select;
	  FileList^.ReadDirectory(Directory^ + WildCard);
	end
      end else if ValidFileName(FName) then
        Valid := True
      else
      begin
	MessageBox(sInvalidFileName, nil, mfError + mfOkButton);
	Valid := False;
      end
    end
    else
      Valid := True;
  end;
end;

type

  PDirEntry = ^TDirEntry;
  TDirEntry = record
    DisplayText: PString;
    Directory: PString;
  end;

  PDirCollection = ^TDirCollection;
  TDirCollection = object(TCollection)
    procedure FreeItem(Item: Pointer); virtual;
  end;

procedure TDirCollection.FreeItem(Item: Pointer);
var
  DirItem: PDirEntry absolute Item;
begin
  DisposeStr(DirItem^.DisplayText);
  DisposeStr(DirItem^.Directory);
  Dispose(DirItem);
end;

const
  DrivesS: String[6] = 'Drives';
  Drives: PString = @DrivesS;

constructor TDirListBox.Init(var Bounds: TRect; AScrollBar:
  PscrollBar);
begin
  TListBox.Init(Bounds, 1, AScrollBar);
  Dir := '';
end;

destructor TDirListBox.Done;
begin
  if List <> nil then Dispose(List, Done);
  TListBox.Done;
end;

function TDirListBox.GetText(Item: Integer; MaxLen: Integer): String;
begin
  GetText := PDirEntry(List^.At(Item))^.DisplayText^;
end;

procedure TDirListBox.HandleEvent(var Event: TEvent);
begin
  if (Event.What = evMouseDown) and (Event.Double) then
  begin
    Event.What := evCommand;
    Event.Command := cmChangeDir;
    PutEvent(Event);
    ClearEvent(Event);
  end
  else TListBox.HandleEvent(Event);
end;

function TDirListBox.IsSelected(Item: Integer): Boolean;
begin
  IsSelected := Item = Cur;
end;

procedure TDirListBox.NewDirectory(var ADir: DirStr);
const
  PathDir            = 'ÀÄÂ';
  FirstDir           =   'ÀÂÄ';
  MiddleDir          =   ' ÃÄ';
  LastDir            =   ' ÀÄ';
  IndentSize         = '  ';
var
  AList: PCollection;
  NewDir, Dirct: DirStr;
  C, OldC: Char;
  S, Indent: String[80];
  P: PString;
  IsFirst: Boolean;
  Flag: Integer;
  SR: SearchRec;
  I: Integer;
  DirEntry: PDirEntry;

function NewDirEntry(DisplayText, Directory: String): PDirEntry; near;
var
  DirEntry: PDirEntry;
begin
  New(DirEntry);
  DirEntry^.DisplayText := NewStr(DisplayText);
  DirEntry^.Directory := NewStr(Directory);
  NewDirEntry := DirEntry;
end;

begin
  Dir := ADir;
  AList := New(PDirCollection, Init(5,5));
  AList^.Insert(NewDirEntry(Drives^, Drives^));
  if Dir = Drives^ then
  begin
    IsFirst := True;
    OldC := ' ';
    for C := 'A' to 'Z' do
    begin
      if (C < 'C') or DriveValid(C) then
      begin
	if OldC <> ' ' then
	begin
	  if IsFirst then
	  begin
	    S := FirstDir + OldC;
	    IsFirst := False;
	  end
	  else S := MiddleDir + OldC;
	  AList^.Insert(NewDirEntry(S, OldC + ':\'));
	end;
	if C = GetCurDrive then Cur := AList^.Count;
	OldC := C;
      end;
    end;
    if OldC <> ' ' then
      AList^.Insert(NewDirEntry(LastDir + OldC, OldC + ':\'));
  end else
  begin
    Indent := IndentSize;
    NewDir := Dir;
    Dirct := Copy(NewDir, 1, 3);
    AList^.Insert(NewDirEntry(PathDir + Dirct, Dirct));
    NewDir := Copy(NewDir, 4, 255);
    while NewDir <> '' do
    begin
      I := Pos('\', NewDir);
      if I <> 0 then
      begin
	S := Copy(NewDir, 1, I - 1);
	Dirct := Dirct + S;
	AList^.Insert(NewDirEntry(Indent + PathDir + S, Dirct));
	NewDir := Copy(NewDir, I + 1, 255);
      end else
      begin
	Dirct := Dirct + NewDir;
	AList^.Insert(NewDirEntry(Indent + PathDir + NewDir, Dirct));
	NewDir := '';
      end;
      Indent := Indent + IndentSize;
      Dirct := Dirct + '\';
    end;
    Cur := AList^.Count - 1;
    IsFirst := True;
    NewDir := Dirct + '*.*';
    Flag := FindFirst(NewDir, Directory, SR);
    while Flag = 0 do
    begin
      if (SR.Attr and Directory <> 0) and (SR.Name[1] <> '.') then
      begin
	if IsFirst then
	begin
	  S := FirstDir;
	  IsFirst := False;
	end else
          S := MiddleDir;
	AList^.Insert(NewDirEntry(Indent + S + SR.Name, Dirct + SR.Name));
      end;
      Flag := FindNext(SR);
    end;
    P := PDirEntry(AList^.At(AList^.Count - 1))^.DisplayText;
    I := Pos('À', P^);
    if I = 0 then
    begin
      I := Pos('Ã', P^);
      if I <> 0 then
        P^[I] := 'À';
    end else
    begin
      P^[I+1] := 'Ä';
      P^[I+2] := 'Ä';
    end;
  end;
  NewList(AList);
  FocusItem(Cur);
end;

procedure TDirListBox.SetState(AState: Word; Enable: Boolean);
begin
  TListBox.SetState(AState, Enable);
  if AState and sfFocused <> 0 then
    PChDirDialog(Owner)^.ChDirButton^.MakeDefault(Enable);
end;

constructor TChDirDialog.Init(HistoryId: Word);
var
  R: TRect;
  Control: PView;
  CurDir: DirStr;
begin
  R.Assign(16, 2, 64, 19);
  TDialog.Init(R, 'Change Directory');
  Options := Options or ofCentered;
  R.Assign(3, 3, 30, 4);
  DirInput := PInputLine(SetHelp(
    New(PInputLine, Init(R, 68)), hcDirectoryName));
  Insert(DirInput);
  Insert(StandardLabel('Directory ~n~ame', DirInput, lfTop));
  Insert(StandardHistory(DirInput, HistoryId));
  R.Assign(32, 6, 33, 15);
  Control := New(PScrollBar, Init(R));
  Insert(Control);
  R.Assign(3, 6, 32, 15);
  DirList := PDirListBox(SetHelp(
    New(PDirListBox, Init(R, PScrollBar(Control))), hcDirectoryTree));
  Insert(DirList);
  Insert(StandardLabel('Directory ~t~ree', DirList, lfTop));
  OkButton := Controls.OkButton(35, 5);
  Insert(OkButton);
  ChDirButton := NewButton(35, 8, 10, '~C~hdir', cmChangeDir, bfNormal, hcChDirButton);
  Insert(ChDirButton);
  Insert(NewButton(35, 11, 10, '~R~evert', cmRevert, bfNormal, hcRevertButton));
  Insert(NewButton(35, 14, 10, '~H~elp', cmHelp, bfNormal, hcChDirDialog));
  SelectNext(False);
end;

constructor TChDirDialog.Load(var S: TStream);
var
  CurDir: DirStr;
begin
  TDialog.Load(S);
  GetSubViewPtr(S, DirList);
  GetSubViewPtr(S, DirInput);
  GetSubViewPtr(S, OkButton);
  GetSubViewPtr(S, ChDirbutton);
  if DirList <> nil then
  begin
    CurDir := GetCurDir;
    DirList^.NewDirectory(CurDir);
    if (Length(CurDir) > 3) and (CurDir[Length(CurDir)] = '\') then
      CurDir := Copy(CurDir, 1, Length(CurDir) - 1);
    if DirInput <> nil then
    begin
      DirInput^.Data^ := CurDir;
      DirInput^.DrawView;
    end;
  end;
end;

function TChDirDialog.DataSize: Word;
begin
  DataSize := 0;
end;

procedure TChDirDialog.GetData(var Rec);
begin
end;

procedure TChDirDialog.HandleEvent(var Event: TEvent);
var
  CurDir: DirStr;
  P: PDirEntry;
begin
  TDialog.HandleEvent(Event);
  case Event.What of
    evCommand:
      begin
	case Event.Command of
	  cmRevert:
            CurDir := GetCurDir;
	  cmChangeDir:
	    begin
	      P := DirList^.List^.At(DirList^.Focused);
	      if (P^.Directory^ = Drives^) or DriveValid(P^.Directory^[1]) then
		CurDir := P^.Directory^
	      else
                Exit;
	    end;
	else
	  Exit;
	end;
	if (Length(CurDir) > 3) and (CurDir[Length(CurDir)] = '\') then
	  CurDir := Copy(CurDir, 1, Length(CurDir) - 1);
	DirList^.NewDirectory(CurDir);
	DirInput^.Data^ := CurDir;
	DirInput^.DrawView;
	DirList^.Select;
	ClearEvent(Event);
      end;
  end;
end;

procedure TChDirDialog.SetData(var Rec);
begin
end;

procedure TChDirDialog.Store(var S: TStream);
begin
  TDialog.Store(S);
  PutSubViewPtr(S, DirList);
  PutSubViewPtr(S, DirInput);
  PutSubViewPtr(S, OkButton);
  PutSubViewPtr(S, ChDirButton);
end;

function TChDirDialog.Valid(Command: Word): Boolean;
var
  P: PathStr;
  CurDrive: Char;
begin
  Valid := True;
  if Command = cmOK then
  begin
    FExpand(DirInput^.Data^, P);
    if (Length(P) > 3) and (P[Length(P)] = '\') then
      Dec(P[0]);
    CurDrive := GetCurDrive;
    if DriveValid(P[1]) and (ChDir(P) = 0) then
      SetCurDrive(P[1])
    else
    begin
      MessageBox(sInvalidDir, nil, mfError + mfOkButton);
      Valid := False;
    end;
  end;
end;

constructor TSecretCopyright.Init(var Bounds: TRect; AText: String);
begin
  TStaticText.Init(Bounds, AText);
  Hide;
  Options := Options or ofPreProcess;
end;

procedure TSecretCopyright.HandleEvent(var Event: TEvent);
begin
  TStaticText.HandleEvent(Event);
  if (Event.What = evKeyDown) and (Event.KeyCode = kbAltI) then
  begin
    Show;
    ClearEvent(Event);
  end;
end;

constructor TMouseDialog.Init;
var
  R: TRect;
  Control: PView;
begin
  R.Assign(13, 3, 67, 16);
  TDialog.Init(R, 'Mouse options');
  Options := Options or ofCentered;
  R.Assign(3, 3, 21, 9);
  Control := SetHelp(New(PRadioButtons, Init(R,
    NewSItem('~N~othing',
    NewSItem('~T~opic search',
    NewSItem('~G~o to cursor',
    NewSItem('~B~reakpoint',
    NewSItem('~E~valuate',
    NewSItem('~A~dd watch', nil)))))))), hcRightMouseButton);
  Insert(Control);
  Insert(StandardLabel('~R~ight mouse button', Control, lfTop));
  R.Assign(24, 4, 50, 5);
  ScrollBar := PScrollBar(SetHelp(New(PScrollBar, Init(R)), hcMouseDoubleClick));
  ScrollBar^.Options := ScrollBar^.Options or ofSelectable;
  ScrollBar^.SetParams(1, 1, 20, 20, 1);
  Insert(ScrollBar);
  R.Assign(23, 2, 42, 3);
  Insert(New(PLabel, Init(R, '~M~ouse double click', ScrollBar)));
  R.Assign(24, 3, 50, 4);
  Insert(New(PDoubleTest, Init(R, 'Fast      Medium      Slow')));
  R.Assign(24, 7, 51, 8);
  Insert(SetHelp(New(PCheckBoxes, Init(R,
    NewSItem('~R~everse mouse buttons', nil))), hcReverseMouseButtons));
  Insert(OkButton(17, 10));
  Insert(CnlButton(29, 10));
  Insert(HelpButton(41, 10, hcMouseOptionsDialog));
  SelectNext(False);
end;

constructor TMouseDialog.Load(var S: TStream);
begin
  TDialog.Load(S);
  GetSubViewPtr(S, ScrollBar);
  DoubleDel := DoubleDelay;
  ScrollBar^.SetValue(DoubleDelay);
end;

procedure TMouseDialog.HandleEvent(var Event: TEvent);
begin
  TDialog.HandleEvent(Event);
  case Event.What of
    evCommand:
      if Event.Command = cmCancel then
        DoubleDelay := DoubleDel;
    evBroadcast:
      if Event.Command = cmScrollBarChanged then
      begin
        DoubleDelay := ScrollBar^.Value;
        ClearEvent(Event);
      end;
  end;
end;

procedure TMouseDialog.Store(var S: TStream);
begin
  TDialog.Store(S);
  PutSubViewPtr(S, ScrollBar);
end;

constructor THelpDialog.Load(var S: TStream);
begin
  TDialog.Load(S);
  GetSubViewPtr(S, HelpView);
end;

function THelpDialog.GetPalette: PPalette;
const
  P: string[Length(CHelpDialog)] = CHelpDialog;
begin
  GetPalette := @P;
end;

procedure THelpDialog.HandleEvent(var Event: TEvent);
begin
  if (Event.What = evCommand) and (HelpView <> nil) then
    HelpView^.Select;
  TDialog.HandleEvent(Event);
end;

procedure THelpDialog.Store(var S: TStream);
begin
  TDialog.Store(S);
  PutSubViewPtr(S, HelpView);
end;

function FindDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(13, 1, 68, 17);
  Dialog := New(PDialog, Init(R, 'Find'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(16, 2, 49, 3);
    Control := SetHelp(New(PCtrlPLine, Init(R, 80)), hcTextToFind);
    Insert(Control);
    Insert(StandardLabel('~T~ext to find', Control, lfLeft));
    Insert(StandardHistory(PCtrlPLine(Control), hlFind));
    R.Assign(3, 5, 27, 8);
    Control := SetHelp(New(PCheckBoxes, Init(R,
      NewSItem('~C~ase sensitive',
      NewSItem('~W~hole words only',
      NewSItem('~R~egular expression', nil))))), hcFindOptions);
    Insert(Control);
    Insert(StandardLabel('Options', Control, lfTop));
    R.Assign(30, 5, 52, 7);
    Control := SetHelp(New(PRadioButtons, Init(R,
      NewSItem('Forwar~d~',
      NewSItem('~B~ackward', nil)))), hcFindDirection);
    Insert(Control);
    Insert(StandardLabel('Direction', Control, lfTop));
    R.Assign(3, 10, 27, 12);
    Control := SetHelp(New(PRadioButtons, Init(R,
      NewSItem('~G~lobal',
      NewSItem('~S~elected text', nil)))), hcFindScope);
    Insert(Control);
    Insert(StandardLabel('Scope', Control, lfTop));
    R.Assign(30, 10, 52, 12);
    Control := SetHelp(New(PRadioButtons, Init(R,
      NewSItem('~F~rom cursor',
      NewSItem('~E~ntire scope',nil)))), hcFindOrigin);
    Insert(Control);
    Insert(StandardLabel('Origin', Control, lfTop));
    Insert(OkButton(18, 13));
    Insert(CnlButton(30, 13));
    Insert(HelpButton(42, 13, hcFindDialog));
    SelectNext(False);
  end;
  FindDialog := Dialog;
end;

constructor TReplaceDialog.Init;
var
  R: TRect;
  Control: PView;
begin
  R.Assign(13, 1, 68, 20);
  TDialog.Init(R, 'Replace');
  Options := Options or ofCentered;
  R.Assign(16, 2, 49, 3);
  Control := SetHelp(New(PCtrlPLine, Init(R, 80)), hcTextToFind);
  Insert(Control);
  Insert(StandardLabel('~T~ext to find', Control, lfLeft));
  Insert(StandardHistory(PCtrlPLine(Control), hlFind));
  R.Assign(16, 4, 49, 5);
  Control := SetHelp(New(PCtrlPLine, Init(R, 80)), hcNewText);
  Insert(Control);
  Insert(StandardLabel('~N~ew text', Control, lfLeft));
  Insert(StandardHistory(PCtrlPLine(Control), hlReplace));
  R.Assign(3, 7, 27, 11);
  Control := SetHelp(New(PCheckBoxes, Init(R,
    NewSItem('~C~ase sensitive',
    NewSItem('~W~hole words only',
    NewSItem('~R~egular expression',
    NewSItem('~P~rompt on replace', nil)))))), hcFindOptions);
  Insert(Control);
  Insert(StandardLabel('Options', Control, lfTop));
  R.Assign(30, 7, 52, 9);
  Control := SetHelp(New(PRadioButtons,Init(R,
    NewSItem('Forwar~d~',
    NewSItem('~B~ackward', nil)))), hcFindDirection);
  Insert(Control);
  Insert(StandardLabel('Direction', Control, lfTop));
  R.Assign(3, 13, 27, 15);
  Control := SetHelp(New(PRadioButtons, Init(R,
    NewSItem('~G~lobal',
    NewSItem('~S~elected text', nil)))), hcFindScope);
  Insert(Control);
  Insert(StandardLabel('Scope', Control, lfTop));
  R.Assign(30, 13, 52, 15);
  Control := SetHelp(New(PRadioButtons, Init(R,
    NewSItem('~F~rom cursor',
    NewSItem('~E~ntire scope    ', nil)))), hcFindOrigin);
  Insert(Control);
  Insert(StandardLabel('Origin', Control, lfTop));
  Insert(OkButton(2, 16));
  Insert(NewButton(14, 16, 14, 'Change ~a~ll', cmChangeAll, bfNormal,
    hcChangeAllButton));
  Insert(CnlButton(30, 16));
  Insert(HelpButton(42, 16, hcReplaceDialog));
  SelectNext(False);
end;

procedure TReplaceDialog.HandleEvent(var Event: TEvent);
begin
  TDialog.HandleEvent(Event);
  if (Event.What = evCommand) and (Event.Command = cmChangeAll) then
  begin
    EndModal(cmChangeAll);
    ClearEvent(Event);
  end;
end;

function GotoLineDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(20, 7, 59, 14);
  Dialog := New(PDialog,Init(R, 'Go to Line Number'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(25, 2, 33, 3);
    Control := SetHelp(New(PIntField, Init(R, 5, 1, 65535)), hcNewLineNumber);
    Insert(Control);
    Insert(StandardLabel('~E~nter new line number', Control, lfLeft));
    Insert(StandardHistory(PIntField(Control), hlGotoLine));
    Insert(OkButton(2, 4));
    Insert(CnlButton(14, 4));
    Insert(HelpButton(26, 4, hcGotoLineDialog));
    SelectNext(False);
  end;
  GotoLineDialog := Dialog;
end;

function FindProcDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(22, 7, 58, 15);
  Dialog := New(PDialog, Init(R, 'Find Procedure'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(3, 3, 30, 4);
    Control := SetHelp(New(PEditLine, Init(R, 80)), hcProcedureName);
    Insert(Control);
    Insert(StandardLabel('~P~rocedure name', Control, lfTop));
    Insert(StandardHistory(PEditLine(Control), hlFindProcedure));
    Insert(OkButton(2, 5));
    Insert(CnlButton(13, 5));
    Insert(HelpButton(24, 5, hcFindProcedureDialog));
    SelectNext(False);
  end;
  FindProcDialog := Dialog;
end;

function FindErrorDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(22, 7, 58, 14);
  Dialog := New(PDialog, Init(R, 'Find Error'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(17, 2, 30, 3);
    Control := SetHelp(New(PAddressField, Init(R, 11)), hcErrorAddress);
    Insert(Control);
    Insert(StandardLabel('~E~rror address', Control, lfLeft));
    Insert(StandardHistory(PAddressField(Control), hlFindError));
    Insert(OkButton(2, 4));
    Insert(CnlButton(13, 4));
    Insert(HelpButton(24, 4, hcFindErrorDialog));
    SelectNext(False);
  end;
  FindErrorDialog := Dialog;
end;

function ParamsDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(12, 6, 68, 13);
  Dialog := New(PDialog, Init(R, 'Program Parameters'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(14, 2, 49, 3);
    Control := SetHelp(New(PInputLine, Init(R, 128)), hcParameters);
    Insert(Control);
    R.Assign(2, 2, 12, 3);
    Insert(New(PLabel, Init(R, '~P~arameters', Control)));
    Insert(StandardHistory(PInputLine(Control), hlParameters));
    Insert(OkButton(21, 4));
    Insert(CnlButton(32, 4));
    Insert(HelpButton(43, 4, hcParametersDialog));
    SelectNext(False);
  end;
  ParamsDialog := Dialog;
end;

function CompilerOptionsDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(0, 0, 59, 21);
  Dialog := New(PDialog, Init(R, 'Compiler Options'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(3, 3, 56, 5);
    Control := SetHelp(New(PCheckBoxes, Init(R,
      NewSItem('~F~orce far calls',
      NewSItem('~O~verlays allowed  ',
      NewSItem('~W~ord align data',
      NewSItem('~2~86 instructions', nil)))))), hcCodeGeneration);
    Insert(Control);
    Insert(StandardLabel('Code generation', Control, lfTop));
    R.Assign(3, 7, 26, 10);
    Control := SetHelp(New(PCheckBoxes, Init(R,
      NewSItem('~R~ange checking',
      NewSItem('~S~tack checking',
      NewSItem('~I~/O checking', nil))))), hcRuntimeErrors);
    Insert(Control);
    Insert(StandardLabel('Runtime errors', Control, lfTop));
    R.Assign(29, 7, 56, 10);
    Control := SetHelp(New(PCheckBoxes, Init(R,
      NewSItem('Strict ~v~ar-strings',
      NewSItem('Complete ~b~oolean eval',
      NewSItem('E~x~tended syntax', nil))))), hcSyntaxOptions);
    Insert(Control);
    Insert(StandardLabel('Syntax options', Control, lfTop));
    R.Assign(3, 12, 26, 14);
    Control := SetHelp(New(PCheckBoxes, Init(R,
      NewSItem('~8~087/80287',
      NewSItem('~E~mulation', nil)))), hcNumericProcessing);
    Insert(Control);
    Insert(StandardLabel('Numeric processing', Control, lfTop));
    R.Assign(29, 12, 56, 14);
    Control := SetHelp(New(PCheckBoxes, Init(R,
      NewSItem('~D~ebug information',
      NewSItem('~L~ocal symbols', nil)))), hcDebuggingOptions);
    Insert(Control);
    Insert(StandardLabel('Debugging', Control, lfTop));
    R.Assign(3, 16, 56, 17);
    Control := SetHelp(New(PInputLine, Init(R, 128)), hcConditionalDefines);
    Insert(Control);
    Insert(StandardLabel('~C~onditional defines', Control, lfTop));
    Insert(OkButton(25, 18));
    Insert(CnlButton(36, 18));
    Insert(HelpButton(47, 18, hcCompilerOptionsDialog));
    SelectNext(False);
  end;
  CompilerOptionsDialog := Dialog;
end;

constructor TSizesDialog.Init;
var
  R: TRect;
  Control: PView;
begin
  R.Assign(18, 4, 54, 15);
  TDialog.Init(R, 'Memory sizes');
  Options := Options or ofCentered;
  R.Assign(24, 2, 33, 3);
  Control := SetHelp(New(PIntField, Init(R, 5, 1024, 65520)), hcStackSize);
  Insert(Control);
  Insert(StandardLabel('~S~tack size', Control, lfLeft + 2));
  R.Move(0, 2);
  LowHeap := SetHelp(New(PIntField, Init(R, 6, 0, 655360)), hcLowHeapLimit);
  Insert(LowHeap);
  Insert(StandardLabel('~L~ow heap limit', LowHeap, lfLeft + 2));
  R.Move(0, 2);
  HighHeap := SetHelp(New(PIntField, Init(R, 6, 0, 655360)), hcHighHeapLimit);
  Insert(HighHeap);
  Insert(StandardLabel('~H~igh heap limit', HighHeap, lfLeft + 2));
  Insert(OkButton(2, 8));
  Insert(CnlButton(13, 8));
  Insert(HelpButton(24, 8, hcMemorySizesDialog));
  SelectNext(False);
end;

constructor TSizesDialog.Load(var S: TStream);
begin
  TDialog.Load(S);
  GetSubViewPtr(S, LowHeap);
  GetSubViewPtr(S, HighHeap);
end;

function TSizesDialog.Valid(Command: Word): Boolean;
var
  IsValid: Boolean;
  LowHeapLimit, HighHeapLimit: Longint;
begin
  IsValid := TDialog.Valid(Command);
  if IsValid and (Command <> cmValid) and (Command <> cmCancel) then
  begin
    LowHeap^.GetData(LowHeapLimit);
    HighHeap^.GetData(HighHeapLimit);
    if LowHeapLimit > HighHeapLimit then
    begin
      IsValid := False;
      messagebox(sInvalidHeapLimits, nil, mfError + mfOkButton);
      LowHeap^.Select;
    end;
  end;
  Valid := IsValid;
end;

procedure TSizesDialog.Store(var S: TStream);
begin
  TDialog.Store(S);
  PutSubViewPtr(S, LowHeap);
  PutSubViewPtr(S, HighHeap);
end;

function LinkerDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(21, 5, 57, 16);
  Dialog := New(PDialog, Init(R, 'Linker'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(3, 3, 17, 7);
    Control := SetHelp(New(PRadioButtons, Init(R,
      NewSItem('~O~ff',
      NewSItem('~S~egments',
      NewSItem('~P~ublic',
      NewSItem('~D~etailed', nil)))))), hcMapFile);
    Insert(Control);
    Insert(StandardLabel('Map file', Control, lfTop));
    R.Assign(21, 3, 33, 5);
    Control := SetHelp(New(PRadioButtons, Init(R,
      NewSItem('~M~emory',
      NewSItem('D~i~sk', nil)))), hcLinkBuffer);
    Insert(Control);
    Insert(StandardLabel('Link buffer', Control, lfTop));
    Insert(OkButton(2, 8));
    Insert(CnlButton(13, 8));
    Insert(HelpButton(24, 8, hcLinkerDialog));
    SelectNext(False);
  end;
  LinkerDialog := Dialog;
end;

function DebuggingDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(19, 5, 59, 15);
  Dialog := New(PDialog, Init(R, 'Debugger'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(3, 3, 19, 5);
    Control := SetHelp(New(PCheckBoxes, Init(R,
      NewSItem('~I~ntegrated',
      NewSItem('~S~tandalone', nil)))), hcDebuggingMode);
    Insert(Control);
    Insert(StandardLabel('Debugging', Control, lfTop));
    R.Assign(21, 3, 37, 6);
    Control := SetHelp(New(PRadioButtons, Init(R,
      NewSItem('~N~one',
      NewSItem('S~m~art',
      NewSItem('~A~lways', nil))))), hcDisplaySwapping);
    Insert(Control);
    Insert(StandardLabel('Display swapping', Control, lfTop));
    Insert(OkButton(6, 7));
    Insert(CnlButton(17, 7));
    Insert(HelpButton(28, 7, hcDebuggingDialog));
    SelectNext(False);
  end;
  DebuggingDialog := Dialog;
end;

function DirectoriesDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(10, 3, 70, 16);
  Dialog := New(PDialog, Init(R, 'Directories'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(23, 2, 57, 3);
    Control := SetHelp(New(PInputLine, Init(R, 80)), hcExeTpuDirectory);
    Insert(Control);
    Insert(StandardLabel('~E~XE & TPU directory', Control, lfLeft + 2));
    R.Move(0, 2);
    Control := SetHelp(New(PInputLine, Init(R, 128)), hcIncludeDirectories);
    Insert(Control);
    Insert(StandardLabel('~I~nclude directories', Control, lfLeft + 2));
    R.Move(0, 2);
    Control := SetHelp(New(PInputLine, Init(R, 128)), hcUnitDirectories);
    Insert(Control);
    Insert(StandardLabel('~U~nit directories', Control, lfLeft + 2));
    R.Move(0, 2);
    Control := SetHelp(New(PInputLine, Init(R, 128)), hcObjectDirectories);
    Insert(Control);
    Insert(StandardLabel('~O~bject directories', Control, lfLeft + 2));
    Insert(OkButton(24, 10));
    Insert(CnlButton(36, 10));
    Insert(HelpButton(48, 10, hcDirectoriesDialog));
    SelectNext(False);
  end;
  DirectoriesDialog := Dialog;
end;

function PreferencesDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(17, 3, 70, 17);
  Dialog := New(PDialog, Init(R, 'Preferences'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(3, 3, 21, 5);
    Control := SetHelp(New(PRadioButtons, Init(R,
      NewSItem('~2~5 lines',
      NewSItem('~4~3/50 lines', nil)))), hcScreenSizes);
    Insert(Control);
    Insert(StandardLabel('Screen sizes', Control, lfTop));
    R.Assign(23, 3, 50, 5);
    Control := SetHelp(New(PRadioButtons, Init(R,
      NewSItem('~N~ew window',
      NewSItem('~C~urrent window', nil)))), hcSourceTracking);
    Insert(Control);
    R.Assign(22, 2, 41, 3);
    Insert(New(PLabel, Init(R, 'Source tracking', Control)));
    R.Assign(3, 7, 21, 10);
    Control := SetHelp(New(PCheckBoxes, Init(R,
      NewSItem('Editor ~f~iles',
      NewSItem('~E~nvironment',
      NewSItem('~D~esktop', nil))))), hcAutoSave);
    Insert(Control);
    Insert(StandardLabel('Auto save', Control, lfTop));
    R.Assign(23, 7, 50, 10);
    Control := SetHelp(New(PRadioButtons, Init(R,
      NewSItem('N~o~ne',
      NewSItem('C~u~rrent directory',
      NewSItem('Conf~i~g file directory', nil))))), hcDesktopFile);
    Insert(Control);
    R.Assign(22, 6, 37, 7);
    Insert(New(PLabel, Init(R, 'Desktop file', Control)));
    Insert(OkButton(17, 11));
    Insert(CnlButton(29, 11));
    Insert(HelpButton(41, 11, hcPreferencesDialog));
    SelectNext(False);
  end;
  PreferencesDialog := Dialog;
end;

function EditorOptionsDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(19, 3, 61, 17);
  Dialog := New(PDialog, Init(R, 'Editor options'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(3, 3, 28, 10);
    Control := SetHelp(New(PCheckBoxes, Init(R,
      NewSItem('Create backup ~f~iles',
      NewSItem('~I~nsert mode',
      NewSItem('~A~utoindent mode',
      NewSItem('~U~se tab characters',
      NewSItem('~O~ptimal fill',
      NewSItem('~B~ackspace unindents',
      NewSItem('~C~ursor through tabs', nil))))))))), hcEditorOptions);
    Insert(Control);
    Insert(StandardLabel('Editor options', Control, lfTop));
    R.Assign(12, 11, 16, 12);
    Control := SetHelp(New(PIntField, Init(R, 2, 2, 16)), hcTabSize);
    Insert(Control);
    Insert(StandardLabel('~T~ab size', Control, lfLeft));
    Insert(OkButton(29, 5));
    Insert(CnlButton(29, 8));
    Insert(HelpButton(29, 11, hcEditorOptionsDialog));
    SelectNext(False);
  end;
  EditorOptionsDialog := Dialog;
end;

function StartupOptionsDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(0, 0, 59, 15);
  Dialog := New(PDialog, Init(R, 'Startup options'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(3, 2, 29, 9);
    Control := SetHelp(New(PCheckBoxes, Init(R,
      NewSItem('~D~ual monitor support',
      NewSItem('~G~raphics screen save',
      NewSItem('EGA/VGA ~p~alette save',
      NewSItem('CGA s~n~ow checking',
      NewSItem('~L~CD color set',
      NewSItem('Use e~x~panded memory',
      NewSItem('Load ~T~URBO.TPL', nil))))))))), hcStartupOptions);
    Insert(Control);
    R.Assign(50, 3, 56, 4);
    Control := SetHelp(New(PIntField, Init(R, 3, 24, 64)), hcWindowHeapSize);
    Insert(Control);
    R.Assign(31, 3, 49, 4);
    Insert(New(PLabel, Init(R, '~W~indow heap size', Control)));
    R.Assign(50, 5, 56, 6);
    Control := SetHelp(New(PIntField, Init(R, 3, 28, 128)), hcEditorHeapSize);
    Insert(Control);
    R.Assign(31, 5, 49, 6);
    Insert(New(PLabel, Init(R, '~E~ditor heap size', Control)));
    R.Assign(50, 7, 56, 8);
    Control := SetHelp(New(PIntField, Init(R, 3, 64, 256)), hcOverlayHeapSize);
    Insert(Control);
    Insert(StandardLabel('~O~verlay heap size', Control, lfLeft + 31));
    R.Assign(23, 10, 56, 11);
    Control := SetHelp(New(PInputLine, Init(R, 67)), hcSwapFileDirectory);
    Insert(Control);
    Insert(StandardLabel('~S~wap file directory', Control, lfLeft));
    Insert(OkButton(22, 12));
    Insert(CnlButton(34, 12));
    Insert(HelpButton(46, 12, hcStartupOptionsDialog));
    SelectNext(False);
  end;
  StartupOptionsDialog := Dialog;
end;

function AboutDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
begin
  R.Assign(21, 3, 58, 16);
  Dialog := New(PDialog, Init(R, 'About'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(12, 2, 24, 3);
    Insert(New(PStaticText, Init(R, 'Turbo Pascal')));
    R.Assign(12, 4, 24, 5);
    Insert(New(PStaticText, Init(R, 'Version 6.0')));
    R.Assign(6, 6, 30, 7);
    Insert(New(PStaticText, Init(R, 'Copyright (c) 1983,90 by')));
    R.Assign(2, 4, 35, 7);
    Insert(New(PSecretCopyright, Init(R,
      ^C'By  AH, AS, CF, CJ, DL, DT, DW, ' +
	'EW, GW, JR, KM, LG, NF, PK, RN, ' +
	'RP, SB, SD, SJ, SM, TS and TT.')));
    R.Assign(5, 8, 32, 9);
    Insert(New(PStaticText, Init(R, 'Borland International, Inc.')));
    Insert(NewButton(13, 10, 10, 'O~K~', cmOK, bfNormal, hcAboutDialog));
  end;
  AboutDialog := Dialog;
end;

function GetInfoDialog: PDialog;
var
  R: TRect;
  Dialog: PDialog;
  Control: PView;
begin
  R.Assign(0, 0, 56, 16);
  Dialog := New(PDialog, Init(R, 'Information'));
  with Dialog^ do
  begin
    Options := Options or ofCentered;
    R.Assign(3, 2, 35, 9);
    Insert(New(PParamText, Init(R,
      'ÄÄÄÄÄÄÄÄÄÄÄ Program ÄÄÄÄÄÄÄÄÄÄÄÄ'^M +
      'Source compiled:   %7d lines'^M +
      'Code size:         %7d bytes'^M +
      'Data size:         %7d bytes'^M +
      'Stack size:        %7d bytes'^M +
      'Minimum heap size: %7d bytes'^M +
      'Maximum heap size: %7d bytes', 6)));
    R.Assign(3, 10, 36, 12);
    Insert(New(PParamText, Init(R, 'Status: %s.', 1)));
    R.Assign(38, 2, 53, 8);
    Insert(New(PParamText, Init(R,
      'ÄÄÄ Memory ÄÄÄÄ'^M +
      'DOS:     %5dK'^M +
      'TURBO:   %5dK'^M +
      'Symbols: %5dK'^M +
      'Program: %5dK'^M +
      'Free:    %5dK', 5)));
    R.Assign(38, 8, 53, 13);
    Insert(New(PParamText, Init(R,
      'ÄÄÄÄÄ EMS ÄÄÄÄÄ'^M +
      'TURBO:   %5dK'^M +
      'Other:   %5dK'^M +
      'Free:    %5dK', 4)));
    Insert(NewButton(23, 13, 10, 'O~K~', cmOK, bfNormal, hcGetInfoDialog));
  end;
  GetInfoDialog := Dialog;
end;

procedure RegisterTStdDlg;
begin
  RegisterType(RFileInputLine);
  RegisterType(RFileCollection);
  RegisterType(RFileList);
  RegisterType(RFileInfoPane);
  RegisterType(RFileDialog);
  RegisterType(RDirListBox);
  RegisterType(RChDirDialog);
  RegisterType(RSecretCopyright);
  RegisterType(RMouseDialog);
  RegisterType(RHelpDialog);
  RegisterType(RReplaceDialog);
  RegisterType(RSizesDialog);
end;

end.
