DEADSOFTWARE

GUI: keybindings menu now contains two keysets on one screen
[d2df-sdl.git] / src / game / g_gui.pas
index 2f9bc08380d79cf1ba7447ce1800a727463e3ec4..f1d86ae37244c61a559e996d4b124a7efb93ba0b 100644 (file)
@@ -1,9 +1,25 @@
+(* Copyright (C)  DooM 2D:Forever Developers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *)
+{$MODE DELPHI}
 unit g_gui;
 
 interface
 
 uses
-  e_graphics, e_input, g_playermodel, g_basic, MAPSTRUCT, WADEDITOR;
+  e_graphics, e_input, e_log, g_playermodel, g_basic, MAPSTRUCT, wadreader;
 
 const
   MAINMENU_HEADER_COLOR: TRGB = (R:255; G:255; B:255);
@@ -82,31 +98,34 @@ type
   end;
 
   TGUIControl = class;
+  TGUIWindow = class;
 
   TOnKeyDownEvent = procedure(Key: Byte);
+  TOnKeyDownEventEx = procedure(win: TGUIWindow; Key: Byte);
   TOnCloseEvent = procedure;
   TOnShowEvent = procedure;
   TOnClickEvent = procedure;
   TOnChangeEvent = procedure(Sender: TGUIControl);
   TOnEnterEvent = procedure(Sender: TGUIControl);
 
-  TGUIWindow = class;
-
   TGUIControl = class
   private
     FX, FY: Integer;
     FEnabled: Boolean;
     FWindow : TGUIWindow;
     FName: string;
+    FUserData: Pointer;
   public
     constructor Create;
     procedure OnMessage(var Msg: TMessage); virtual;
     procedure Update; virtual;
     procedure Draw; virtual;
+    function WantActivationKey (key: LongInt): Boolean; virtual;
     property X: Integer read FX write FX;
     property Y: Integer read FY write FY;
     property Enabled: Boolean read FEnabled write FEnabled;
     property Name: string read FName write FName;
+    property UserData: Pointer read FUserData write FUserData;
   end;
 
   TGUIWindow = class
@@ -118,8 +137,10 @@ type
     FBackTexture: string;
     FMainWindow: Boolean;
     FOnKeyDown: TOnKeyDownEvent;
+    FOnKeyDownEx: TOnKeyDownEventEx;
     FOnCloseEvent: TOnCloseEvent;
     FOnShowEvent: TOnShowEvent;
+    FUserData: Pointer;
   public
     Childs: array of TGUIControl;
     constructor Create(Name: string);
@@ -131,12 +152,14 @@ type
     procedure SetActive(Control: TGUIControl);
     function GetControl(Name: string): TGUIControl;
     property OnKeyDown: TOnKeyDownEvent read FOnKeyDown write FOnKeyDown;
+    property OnKeyDownEx: TOnKeyDownEventEx read FOnKeyDownEx write FOnKeyDownEx;
     property OnClose: TOnCloseEvent read FOnCloseEvent write FOnCloseEvent;
     property OnShow: TOnShowEvent read FOnShowEvent write FOnShowEvent;
     property Name: string read FName;
     property DefControl: string read FDefControl write FDefControl;
     property BackTexture: string read FBackTexture write FBackTexture;
     property MainWindow: Boolean read FMainWindow write FMainWindow;
+    property UserData: Pointer read FUserData write FUserData;
   end;
 
   TGUITextButton = class(TGUIControl)
@@ -148,6 +171,7 @@ type
     FShowWindow: string;
   public
     Proc: procedure;
+    ProcEx: procedure (sender: TGUITextButton);
     constructor Create(Proc: Pointer; FontID: DWORD; Text: string);
     destructor Destroy(); override;
     procedure OnMessage(var Msg: TMessage); override;
@@ -266,11 +290,34 @@ type
     procedure OnMessage(var Msg: TMessage); override;
     procedure Draw; override;
     function GetWidth(): Word;
+    function WantActivationKey (key: LongInt): Boolean; override;
     property Key: Word read FKey write FKey;
     property Color: TRGB read FColor write FColor;
     property Font: TFont read FFont write FFont;
   end;
 
+  // can hold two keys
+  TGUIKeyRead2 = class(TGUIControl)
+  private
+    FFont: TFont;
+    FFontID: DWORD;
+    FColor: TRGB;
+    FKey0, FKey1: Word; // this should be an array. sorry.
+    FKeyIdx: Integer;
+    FIsQuery: Boolean;
+    FMaxKeyNameWdt: Integer;
+  public
+    constructor Create(FontID: DWORD);
+    procedure OnMessage(var Msg: TMessage); override;
+    procedure Draw; override;
+    function GetWidth(): Word;
+    function WantActivationKey (key: LongInt): Boolean; override;
+    property Key0: Word read FKey0 write FKey0;
+    property Key1: Word read FKey1 write FKey1;
+    property Color: TRGB read FColor write FColor;
+    property Font: TFont read FFont write FFont;
+  end;
+
   TGUIModelView = class(TGUIControl)
   private
     FModel: TPlayerModel;
@@ -447,6 +494,7 @@ type
     FCounter: Byte;
     FAlign: Boolean;
     FLeft: Integer;
+    FYesNo: Boolean;
     function NewItem(): Integer;
   public
     constructor Create(HeaderFont, ItemsFont: DWORD; Header: string);
@@ -461,6 +509,7 @@ type
     function AddSwitch(fText: string): TGUISwitch;
     function AddEdit(fText: string): TGUIEdit;
     function AddKeyRead(fText: string): TGUIKeyRead;
+    function AddKeyRead2(fText: string): TGUIKeyRead2;
     function AddList(fText: string; Width, Height: Word): TGUIListBox;
     function AddFileList(fText: string; Width, Height: Word): TGUIFileListBox;
     function AddMemo(fText: string; Width, Height: Word): TGUIMemo;
@@ -472,6 +521,7 @@ type
     procedure UpdateIndex();
     property Align: Boolean read FAlign write FAlign;
     property Left: Integer read FLeft write FLeft;
+    property YesNo: Boolean read FYesNo write FYesNo;
   end;
 
 var
@@ -713,6 +763,7 @@ begin
   FActiveControl := nil;
   FName := Name;
   FOnKeyDown := nil;
+  FOnKeyDownEx := nil;
   FOnCloseEvent := nil;
   FOnShowEvent := nil;
 end;
@@ -765,6 +816,7 @@ procedure TGUIWindow.OnMessage(var Msg: TMessage);
 begin
   if FActiveControl <> nil then FActiveControl.OnMessage(Msg);
   if @FOnKeyDown <> nil then FOnKeyDown(Msg.wParam);
+  if @FOnKeyDownEx <> nil then FOnKeyDownEx(self, Msg.wParam);
 
   if Msg.Msg = WM_KEYDOWN then
     if Msg.wParam = IK_ESCAPE then
@@ -815,25 +867,27 @@ end;
 
 procedure TGUIControl.Update();
 begin
-
 end;
 
 procedure TGUIControl.Draw();
 begin
+end;
 
+function TGUIControl.WantActivationKey (key: LongInt): Boolean;
+begin
+  result := false;
 end;
 
 { TGUITextButton }
 
 procedure TGUITextButton.Click(Silent: Boolean = False);
 begin
-  if (FSound <> '') and (not Silent) then
-    g_Sound_PlayEx(FSound);
+  if (FSound <> '') and (not Silent) then g_Sound_PlayEx(FSound);
+
+  if @Proc <> nil then Proc();
+  if @ProcEx <> nil then ProcEx(self);
 
-  if @Proc <> nil then
-    Proc();
-  if FShowWindow <> '' then
-    g_GUI_ShowWindow(FShowWindow);
+  if FShowWindow <> '' then g_GUI_ShowWindow(FShowWindow);
 end;
 
 constructor TGUITextButton.Create(Proc: Pointer; FontID: DWORD; Text: string);
@@ -841,6 +895,7 @@ begin
   inherited Create();
 
   Self.Proc := Proc;
+  ProcEx := nil;
 
   FFont := TFont.Create(FontID, FONT_CHAR);
 
@@ -1248,9 +1303,13 @@ begin
     with FItems[i] do
     begin
       Text := TGUILabel.Create(l[a], FFontID);
-      with Text do
+      if FYesNo then
+      begin
+        with Text do begin FColor := _RGB(255, 0, 0); end;
+      end
+      else
       begin
-        FColor := MENU_ITEMSTEXT_COLOR;
+        with Text do begin FColor := MENU_ITEMSTEXT_COLOR; end;
       end;
 
       Control := nil;
@@ -1283,6 +1342,7 @@ begin
   FFontID := ItemsFont;
   FCounter := MENU_MARKERDELAY;
   FAlign := True;
+  FYesNo := false;
 
   FHeader := TGUILabel.Create(Header, HeaderFont);
   with FHeader do
@@ -1412,6 +1472,14 @@ begin
 
   if not ok then Exit;
 
+  if (Msg.Msg = WM_KEYDOWN) and (FIndex <> -1) and (FItems[FIndex].Control <> nil) and
+     (FItems[FIndex].Control.WantActivationKey(Msg.wParam)) then
+  begin
+    FItems[FIndex].Control.OnMessage(Msg);
+    g_Sound_PlayEx(MENU_CLICKSOUND);
+    exit;
+  end;
+
   case Msg.Msg of
     WM_KEYDOWN:
     begin
@@ -1467,11 +1535,26 @@ begin
         IK_RETURN, IK_KPRETURN:
         begin
           if FIndex <> -1 then
-            if FItems[FIndex].Control <> nil then
-              FItems[FIndex].Control.OnMessage(Msg);
-
+          begin
+            if FItems[FIndex].Control <> nil then FItems[FIndex].Control.OnMessage(Msg);
+          end;
           g_Sound_PlayEx(MENU_CLICKSOUND);
         end;
+        // dirty hacks
+        IK_Y:
+          if FYesNo and (length(FItems) > 1) then
+          begin
+            Msg.wParam := IK_RETURN; // to register keypress
+            FIndex := High(FItems)-1;
+            if FItems[FIndex].Control <> nil then FItems[FIndex].Control.OnMessage(Msg);
+          end;
+        IK_N:
+          if FYesNo and (length(FItems) > 1) then
+          begin
+            Msg.wParam := IK_RETURN; // to register keypress
+            FIndex := High(FItems);
+            if FItems[FIndex].Control <> nil then FItems[FIndex].Control.OnMessage(Msg);
+          end;
       end;
     end;
   end;
@@ -1506,6 +1589,8 @@ begin
           w := w+(FItems[a].Control as TGUIEdit).GetWidth
         else if FItems[a].ControlType = TGUIKeyRead then
           w := w+(FItems[a].Control as TGUIKeyRead).GetWidth
+        else if FItems[a].ControlType = TGUIKeyRead2 then
+          w := w+(FItems[a].Control as TGUIKeyRead2).GetWidth
         else if (FItems[a].ControlType = TGUIListBox) then
           w := w+(FItems[a].Control as TGUIListBox).GetWidth
         else if (FItems[a].ControlType = TGUIFileListBox) then
@@ -1520,21 +1605,22 @@ begin
 
   cx := 0;
   for a := 0 to High(FItems) do
+  begin
     with FItems[a] do
     begin
       if (Text <> nil) and (Control = nil) then Continue;
-
       w := 0;
       if Text <> nil then w := tx+Text.GetWidth;
-
       if w > cx then cx := w;
     end;
+  end;
 
   cx := cx+MENU_HSPACE;
 
   h := FHeader.GetHeight*2+MENU_VSPACE*(Length(FItems)-1);
 
   for a := 0 to High(FItems) do
+  begin
     with FItems[a] do
     begin
       if (ControlType = TGUIListBox) or (ControlType = TGUIFileListBox) then
@@ -1542,6 +1628,7 @@ begin
       else
         h := h+e_CharFont_GetMaxHeight(FFontID);
     end;
+  end;
 
   h := (gScreenHeight div 2)-(h div 2);
 
@@ -1583,6 +1670,30 @@ begin
         else
           Inc(h, e_CharFont_GetMaxHeight(FFontID)+MENU_VSPACE);
     end;
+
+  // another ugly hack
+  if FYesNo and (length(FItems) > 1) then
+  begin
+    w := -1;
+    for a := High(FItems)-1 to High(FItems) do
+    begin
+      if (FItems[a].Control <> nil) and (FItems[a].ControlType = TGUITextButton) then
+      begin
+        cx := (FItems[a].Control as TGUITextButton).GetWidth;
+        if cx > w then w := cx;
+      end;
+    end;
+    if w > 0 then
+    begin
+      for a := High(FItems)-1 to High(FItems) do
+      begin
+        if (FItems[a].Control <> nil) and (FItems[a].ControlType = TGUITextButton) then
+        begin
+          FItems[a].Control.FX := (gScreenWidth-w) div 2;
+        end;
+      end;
+    end;
+  end;
 end;
 
 function TGUIMenu.AddScroll(fText: string): TGUIScroll;
@@ -1710,6 +1821,36 @@ begin
   ReAlign();
 end;
 
+function TGUIMenu.AddKeyRead2(fText: string): TGUIKeyRead2;
+var
+  i: Integer;
+begin
+  i := NewItem();
+  with FItems[i] do
+  begin
+    Control := TGUIKeyRead2.Create(FFontID);
+    with Control as TGUIKeyRead2 do
+    begin
+      FWindow := Self.FWindow;
+      FColor := MENU_ITEMSCTRL_COLOR;
+    end;
+
+    Text := TGUILabel.Create(fText, FFontID);
+    with Text do
+    begin
+      FColor := MENU_ITEMSTEXT_COLOR;
+    end;
+
+    ControlType := TGUIKeyRead2;
+
+    Result := (Control as TGUIKeyRead2);
+  end;
+
+  if FIndex = -1 then FIndex := i;
+
+  ReAlign();
+end;
+
 function TGUIMenu.AddList(fText: string; Width, Height: Word): TGUIListBox;
 var
   i: Integer;
@@ -2137,6 +2278,8 @@ end;
 constructor TGUIKeyRead.Create(FontID: DWORD);
 begin
   inherited Create();
+  FKey := 0;
+  FIsQuery := false;
 
   FFont := TFont.Create(FontID, FONT_CHAR);
 end;
@@ -2169,7 +2312,23 @@ begin
   if w > Result then Result := w;
 end;
 
+function TGUIKeyRead.WantActivationKey (key: LongInt): Boolean;
+begin
+  result :=
+    (key = IK_BACKSPACE) or
+    false; // oops
+end;
+
 procedure TGUIKeyRead.OnMessage(var Msg: TMessage);
+  procedure actDefCtl ();
+  begin
+    with FWindow do
+      if FDefControl <> '' then
+        SetActive(GetControl(FDefControl))
+      else
+        SetActive(nil);
+  end;
+
 begin
   inherited;
 
@@ -2182,13 +2341,7 @@ begin
         case wParam of
           IK_ESCAPE:
             begin
-              if FIsQuery then
-                with FWindow do
-                  if FDefControl <> '' then
-                    SetActive(GetControl(FDefControl))
-                  else
-                    SetActive(nil);
-
+              if FIsQuery then actDefCtl();
               FIsQuery := False;
             end;
           IK_RETURN, IK_KPRETURN:
@@ -2205,32 +2358,196 @@ begin
                 begin
                   FKey := IK_ENTER; // <Enter>
                   FIsQuery := False;
+                  actDefCtl();
+                end;
+            end;
+          IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
+            begin
+              if not FIsQuery then
+              begin
+                FKey := 0;
+                actDefCtl();
+              end;
+            end;
+        end;
+
+      MESSAGE_DIKEY:
+        begin
+          if not FIsQuery and (wParam = IK_BACKSPACE) then
+          begin
+            FKey := 0;
+            actDefCtl();
+          end
+          else if FIsQuery and (wParam <> IK_ENTER) and (wParam <> IK_KPRETURN) then // Not <Enter
+          begin
+            if e_KeyNames[wParam] <> '' then
+              FKey := wParam;
+            FIsQuery := False;
+            actDefCtl();
+          end;
+        end;
+    end;
+end;
+
+{ TGUIKeyRead2 }
+
+constructor TGUIKeyRead2.Create(FontID: DWORD);
+var
+  a: Byte;
+  w, h: Word;
+begin
+  inherited Create();
+
+  FKey0 := 0;
+  FKey1 := 0;
+  FKeyIdx := 0;
+  FIsQuery := False;
+
+  FFontID := FontID;
+  FFont := TFont.Create(FontID, FONT_CHAR);
+
+  FMaxKeyNameWdt := 0;
+  for a := 0 to 255 do
+  begin
+    FFont.GetTextSize(e_KeyNames[a], w, h);
+    FMaxKeyNameWdt := Max(FMaxKeyNameWdt, w);
+  end;
+
+  FFont.GetTextSize(KEYREAD_QUERY, w, h);
+  if w > FMaxKeyNameWdt then FMaxKeyNameWdt := w;
+
+  FFont.GetTextSize(KEYREAD_CLEAR, w, h);
+  if w > FMaxKeyNameWdt then FMaxKeyNameWdt := w;
+end;
+
+procedure TGUIKeyRead2.Draw;
+  procedure drawText (idx: Integer);
+  var
+    x, y: Integer;
+    r, g, b: Byte;
+    kk: DWORD;
+  begin
+    if idx = 0 then kk := FKey0 else kk := FKey1;
+    y := FY;
+    if idx = 0 then x := FX+8 else x := FX+8+FMaxKeyNameWdt+16;
+    r := 255;
+    g := 0;
+    b := 0;
+    if FKeyIdx = idx then g := 127;
+    if FIsQuery and (FKeyIdx = idx) then
+      FFont.Draw(x, y, KEYREAD_QUERY, r, g, b)
+    else
+      FFont.Draw(x, y, IfThen(kk <> 0, e_KeyNames[kk], KEYREAD_CLEAR), r, g, b);
+  end;
+
+begin
+  inherited;
+
+  //FFont.Draw(FX+8, FY, IfThen(FIsQuery and (FKeyIdx = 0), KEYREAD_QUERY, IfThen(FKey0 <> 0, e_KeyNames[FKey0], KEYREAD_CLEAR)), FColor.R, FColor.G, FColor.B);
+  //FFont.Draw(FX+8+FMaxKeyNameWdt+16, FY, IfThen(FIsQuery and (FKeyIdx = 1), KEYREAD_QUERY, IfThen(FKey1 <> 0, e_KeyNames[FKey1], KEYREAD_CLEAR)), FColor.R, FColor.G, FColor.B);
+  drawText(0);
+  drawText(1);
+end;
+
+function TGUIKeyRead2.GetWidth: Word;
+begin
+  Result := FMaxKeyNameWdt*2+8+8+16;
+end;
+
+function TGUIKeyRead2.WantActivationKey (key: LongInt): Boolean;
+begin
+  result :=
+    (key = IK_BACKSPACE) or
+    (key = IK_LEFT) or (key = IK_RIGHT) or
+    (key = IK_KPLEFT) or (key = IK_KPRIGHT) or
+    false; // oops
+end;
+
+procedure TGUIKeyRead2.OnMessage(var Msg: TMessage);
+  procedure actDefCtl ();
+  begin
+    with FWindow do
+      if FDefControl <> '' then
+        SetActive(GetControl(FDefControl))
+      else
+        SetActive(nil);
+  end;
 
+begin
+  inherited;
+
+  if not FEnabled then
+    Exit;
+
+  with Msg do
+    case Msg of
+      WM_KEYDOWN:
+        case wParam of
+          IK_ESCAPE:
+            begin
+              if FIsQuery then actDefCtl();
+              FIsQuery := False;
+            end;
+          IK_RETURN, IK_KPRETURN:
+            begin
+              if not FIsQuery then
+                begin
                   with FWindow do
-                    if FDefControl <> '' then
-                      SetActive(GetControl(FDefControl))
-                    else
-                      SetActive(nil);
+                    if FActiveControl <> Self then
+                      SetActive(Self);
+
+                  FIsQuery := True;
+                end
+              else
+                begin
+                  if (FKeyIdx = 0) then FKey0 := IK_ENTER else FKey1 := IK_ENTER; // <Enter>
+                  FIsQuery := False;
+                  actDefCtl();
                 end;
             end;
+          IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
+            begin
+              if not FIsQuery then
+              begin
+                if (FKeyIdx = 0) then FKey0 := 0 else FKey1 := 0;
+                actDefCtl();
+              end;
+            end;
+          IK_LEFT, IK_KPLEFT:
+            if not FIsQuery then
+            begin
+              FKeyIdx := 0;
+              actDefCtl();
+            end;
+          IK_RIGHT, IK_KPRIGHT:
+            if not FIsQuery then
+            begin
+              FKeyIdx := 1;
+              actDefCtl();
+            end;
         end;
 
       MESSAGE_DIKEY:
-        if FIsQuery and (wParam <> IK_ENTER) and (wParam <> IK_KPRETURN) then // Not <Enter
         begin
-          if e_KeyNames[wParam] <> '' then
-            FKey := wParam;
-          FIsQuery := False;
-
-          with FWindow do
-            if FDefControl <> '' then
-              SetActive(GetControl(FDefControl))
-            else
-              SetActive(nil);
+          if not FIsQuery and (wParam = IK_BACKSPACE) then
+          begin
+            if (FKeyIdx = 0) then FKey0 := 0 else FKey1 := 0;
+            actDefCtl();
+          end
+          else if FIsQuery and (wParam <> IK_ENTER) and (wParam <> IK_KPRETURN) then // Not <Enter
+          begin
+            if e_KeyNames[wParam] <> '' then
+            begin
+              if (FKeyIdx = 0) then FKey0 := wParam else FKey1 := wParam;
+            end;
+            FIsQuery := False;
+            actDefCtl();
+          end;
         end;
     end;
 end;
 
+
 { TGUIModelView }
 
 constructor TGUIModelView.Create;
@@ -2406,26 +2723,27 @@ end;
 
 procedure TGUIMapPreview.SetMap(Res: string);
 var
-  WAD: TWADEditor_1;
+  WAD: TWADFile;
   MapReader: TMapReader_1;
   panels: TPanelsRec1Array;
   header: TMapHeaderRec_1;
   a: Integer;
-  FileName, SectionName, ResName: string;
+  FileName: string;
   Data: Pointer;
   Len: Integer;
   rX, rY: Single;
 begin
-  g_ProcessResourceStr(Res, FileName, SectionName, ResName);
+  FileName := g_ExtractWadName(Res);
 
-  WAD := TWADEditor_1.Create();
+  WAD := TWADFile.Create();
   if not WAD.ReadFile(FileName) then
   begin
     WAD.Free();
     Exit;
   end;
 
-  if not WAD.GetResource('', ResName, Data, Len) then
+  //k8: ignores path again
+  if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then
   begin
     WAD.Free();
     Exit;
@@ -2844,13 +3162,14 @@ procedure TGUIFileListBox.OpenDir(path: String);
 var
   SR: TSearchRec;
   i: Integer;
+  sm, sc: string;
 begin
   Clear();
 
   path := IncludeTrailingPathDelimiter(path);
   path := ExpandFileName(path);
 
-// Êàòàëîãè:
+  // Êàòàëîãè:
   if FDirs then
   begin
     if FindFirst(path+'*', faDirectory, SR) = 0 then
@@ -2867,20 +3186,15 @@ begin
     FindClose(SR);
   end;
 
-// Ôàéëû:
-  if FindFirst(path+FFileMask, faAnyFile, SR) = 0 then
-    repeat
-      AddItem(SR.Name);
-    until FindNext(SR) <> 0;
-  FindClose(SR);
-
-  //FIXME: HACK!
-  if FFileMask = '*.wad' then
+  // Ôàéëû:
+  sm := FFileMask;
+  while sm <> '' do
   begin
-    if FindFirst(path+'*.pk3', faAnyFile, SR) = 0 then
-      repeat
-        AddItem(SR.Name);
-      until FindNext(SR) <> 0;
+    i := Pos('|', sm);
+    if i = 0 then i := length(sm)+1;
+    sc := Copy(sm, 1, i-1);
+    Delete(sm, 1, i);
+    if FindFirst(path+sc, faAnyFile, SR) = 0 then repeat AddItem(SR.Name); until FindNext(SR) <> 0;
     FindClose(SR);
   end;