DEADSOFTWARE

simple allocation counter for classes
[d2df-sdl.git] / src / game / g_gui.pas
index fbab591b37059bcbad512a6615e9f4f88067c78d..2ead3bbbb06a9e0bf0bd7c8cbae0b5eb2d626919 100644 (file)
  * 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}
+{$INCLUDE ../shared/a_modes.inc}
 unit g_gui;
 
 interface
 
 uses
-  e_graphics, e_input, e_log, g_playermodel, g_basic, MAPSTRUCT, wadreader;
+  mempool,
+  e_graphics, e_input, e_log, g_playermodel, g_basic, MAPDEF, wadreader;
 
 const
   MAINMENU_HEADER_COLOR: TRGB = (R:255; G:255; B:255);
@@ -84,7 +85,7 @@ type
 
   TFontType = (FONT_TEXTURE, FONT_CHAR);
 
-  TFont = class(TObject)
+  TFont = class(TPoolObject)
   private
     ID: DWORD;
     FScale: Single;
@@ -108,26 +109,32 @@ type
   TOnChangeEvent = procedure(Sender: TGUIControl);
   TOnEnterEvent = procedure(Sender: TGUIControl);
 
-  TGUIControl = class
+  TGUIControl = class(TPoolObject)
   private
     FX, FY: Integer;
     FEnabled: Boolean;
     FWindow : TGUIWindow;
     FName: string;
     FUserData: Pointer;
+    FRightAlign: Boolean; //HACK! this works only for "normal" menus, only for menu text labels, and generally sux. sorry.
+    FMaxWidth: Integer; //HACK! used for right-aligning labels
   public
     constructor Create;
     procedure OnMessage(var Msg: TMessage); virtual;
     procedure Update; virtual;
     procedure Draw; virtual;
+    function GetWidth(): Integer; virtual;
+    function GetHeight(): Integer; 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;
+    property RightAlign: Boolean read FRightAlign write FRightAlign; // for menu
   end;
 
-  TGUIWindow = class
+  TGUIWindow = class(TPoolObject)
   private
     FActiveControl: TGUIControl;
     FDefControl: string;
@@ -171,13 +178,13 @@ type
   public
     Proc: procedure;
     ProcEx: procedure (sender: TGUITextButton);
-    constructor Create(Proc: Pointer; FontID: DWORD; Text: string);
+    constructor Create(aProc: Pointer; FontID: DWORD; Text: string);
     destructor Destroy(); override;
     procedure OnMessage(var Msg: TMessage); override;
     procedure Update(); override;
     procedure Draw(); override;
-    function GetWidth(): Integer;
-    function GetHeight(): Integer;
+    function GetWidth(): Integer; override;
+    function GetHeight(): Integer; override;
     procedure Click(Silent: Boolean = False);
     property Caption: string read FText write FText;
     property Color: TRGB read FColor write FColor;
@@ -196,8 +203,8 @@ type
     constructor Create(Text: string; FontID: DWORD);
     procedure OnMessage(var Msg: TMessage); override;
     procedure Draw; override;
-    function GetWidth: Integer;
-    function GetHeight: Integer;
+    function GetWidth: Integer; override;
+    function GetHeight: Integer; override;
     property OnClick: TOnClickEvent read FOnClickEvent write FOnClickEvent;
     property FixedLength: Word read FFixedLen write FFixedLen;
     property Text: string read FText write FText;
@@ -220,7 +227,7 @@ type
     procedure OnMessage(var Msg: TMessage); override;
     procedure Update; override;
     procedure Draw; override;
-    function GetWidth(): Word;
+    function GetWidth(): Integer; override;
     property OnChange: TOnChangeEvent read FOnChangeEvent write FOnChangeEvent;
     property Max: Word read FMax write FMax;
     property Value: Integer read FValue write FSetValue;
@@ -239,7 +246,7 @@ type
     procedure AddItem(Item: string);
     procedure Update; override;
     procedure Draw; override;
-    function GetWidth(): Word;
+    function GetWidth(): Integer; override;
     function GetText: string;
     property ItemIndex: Integer read FIndex write FIndex;
     property Color: TRGB read FColor write FColor;
@@ -267,7 +274,7 @@ type
     procedure OnMessage(var Msg: TMessage); override;
     procedure Update; override;
     procedure Draw; override;
-    function GetWidth(): Word;
+    function GetWidth(): Integer; override;
     property OnChange: TOnChangeEvent read FOnChangeEvent write FOnChangeEvent;
     property OnEnter: TOnEnterEvent read FOnEnterEvent write FOnEnterEvent;
     property Width: Word read FWidth write FWidth;
@@ -288,12 +295,35 @@ type
     constructor Create(FontID: DWORD);
     procedure OnMessage(var Msg: TMessage); override;
     procedure Draw; override;
-    function GetWidth(): Word;
+    function GetWidth(): Integer; override;
+    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(): Integer; override;
+    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;
@@ -319,7 +349,7 @@ type
   TGUIMapPreview = class(TGUIControl)
   private
     FMapData: array of TPreviewPanel;
-    FMapSize: TPoint;
+    FMapSize: TDFPoint;
     FScale: Single;
   public
     constructor Create();
@@ -372,8 +402,8 @@ type
     procedure AddItem(Item: String);
     procedure SelectItem(Item: String);
     procedure Clear();
-    function  GetWidth(): Word;
-    function  GetHeight(): Word;
+    function  GetWidth(): Integer; override;
+    function  GetHeight(): Integer; override;
     function  SelectedItem(): String;
 
     property OnChange: TOnChangeEvent read FOnChangeEvent write FOnChangeEvent;
@@ -387,7 +417,7 @@ type
     property Font: TFont read FFont write FFont;
   end;
 
-  TGUIFileListBox = class (TGUIListBox)
+  TGUIFileListBox = class(TGUIListBox)
   private
     FBasePath: String;
     FPath: String;
@@ -422,8 +452,8 @@ type
     procedure OnMessage(var Msg: TMessage); override;
     procedure Draw; override;
     procedure Clear;
-    function GetWidth(): Word;
-    function GetHeight(): Word;
+    function GetWidth(): Integer; override;
+    function GetHeight(): Integer; override;
     procedure SetText(Text: string);
     property DrawBack: Boolean read FDrawBack write FDrawBack;
     property DrawScrollBar: Boolean read FDrawScroll write FDrawScroll;
@@ -445,8 +475,8 @@ type
     destructor Destroy; override;
     procedure OnMessage(var Msg: TMessage); override;
     function AddButton(fProc: Pointer; Caption: string; ShowWindow: string = ''): TGUITextButton;
-    function GetButton(Name: string): TGUITextButton;
-    procedure EnableButton(Name: string; e: Boolean);
+    function GetButton(aName: string): TGUITextButton;
+    procedure EnableButton(aName: string; e: Boolean);
     procedure AddSpace();
     procedure Update; override;
     procedure Draw; override;
@@ -485,12 +515,13 @@ 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;
     procedure ReAlign();
-    function GetControl(Name: string): TGUIControl;
-    function GetControlsText(Name: string): TGUILabel;
+    function GetControl(aName: string): TGUIControl;
+    function GetControlsText(aName: string): TGUILabel;
     procedure Draw; override;
     procedure Update; override;
     procedure UpdateIndex();
@@ -516,8 +547,8 @@ implementation
 
 uses
   GL, GLExt, g_textures, g_sound, SysUtils,
-  g_game, Math, StrUtils, g_player, g_options, MAPREADER,
-  g_map, MAPDEF, g_weapons;
+  g_game, Math, StrUtils, g_player, g_options,
+  g_map, g_weapons, xdynrec;
 
 var
   Box: Array [0..8] of DWORD;
@@ -832,6 +863,8 @@ begin
   FY := 0;
 
   FEnabled := True;
+  FRightAlign := false;
+  FMaxWidth := -1;
 end;
 
 procedure TGUIControl.OnMessage(var Msg: TMessage);
@@ -842,12 +875,25 @@ end;
 
 procedure TGUIControl.Update();
 begin
-
 end;
 
 procedure TGUIControl.Draw();
 begin
+end;
+
+function TGUIControl.WantActivationKey (key: LongInt): Boolean;
+begin
+  result := false;
+end;
+
+function TGUIControl.GetWidth(): Integer;
+begin
+  result := 0;
+end;
 
+function TGUIControl.GetHeight(): Integer;
+begin
+  result := 0;
 end;
 
 { TGUITextButton }
@@ -862,11 +908,11 @@ begin
   if FShowWindow <> '' then g_GUI_ShowWindow(FShowWindow);
 end;
 
-constructor TGUITextButton.Create(Proc: Pointer; FontID: DWORD; Text: string);
+constructor TGUITextButton.Create(aProc: Pointer; FontID: DWORD; Text: string);
 begin
   inherited Create();
 
-  Self.Proc := Proc;
+  Self.Proc := aProc;
   ProcEx := nil;
 
   FFont := TFont.Create(FontID, FONT_CHAR);
@@ -1068,14 +1114,14 @@ begin
   end;
 end;
 
-procedure TGUIMainMenu.EnableButton(Name: string; e: Boolean);
+procedure TGUIMainMenu.EnableButton(aName: string; e: Boolean);
 var
   a: Integer;
 begin
   if FButtons = nil then Exit;
 
   for a := 0 to High(FButtons) do
-    if (FButtons[a] <> nil) and (FButtons[a].Name = Name) then
+    if (FButtons[a] <> nil) and (FButtons[a].Name = aName) then
     begin
       if e then FButtons[a].FColor := MAINMENU_ITEMS_COLOR
       else FButtons[a].FColor := MAINMENU_UNACTIVEITEMS_COLOR;
@@ -1084,7 +1130,7 @@ begin
     end;
 end;
 
-function TGUIMainMenu.GetButton(Name: string): TGUITextButton;
+function TGUIMainMenu.GetButton(aName: string): TGUITextButton;
 var
   a: Integer;
 begin
@@ -1093,7 +1139,7 @@ begin
   if FButtons = nil then Exit;
 
   for a := 0 to High(FButtons) do
-    if (FButtons[a] <> nil) and (FButtons[a].Name = Name) then
+    if (FButtons[a] <> nil) and (FButtons[a].Name = aName) then
     begin
       Result := FButtons[a];
       Break;
@@ -1177,8 +1223,18 @@ begin
 end;
 
 procedure TGUILabel.Draw;
+var
+  w, h: Word;
 begin
-  FFont.Draw(FX, FY, FText, FColor.R, FColor.G, FColor.B);
+  if RightAlign then
+  begin
+    FFont.GetTextSize(FText, w, h);
+    FFont.Draw(FX+FMaxWidth-w, FY, FText, FColor.R, FColor.G, FColor.B);
+  end
+  else
+  begin
+    FFont.Draw(FX, FY, FText, FColor.R, FColor.G, FColor.B);
+  end;
 end;
 
 function TGUILabel.GetHeight: Integer;
@@ -1346,7 +1402,7 @@ end;
 
 procedure TGUIMenu.Draw;
 var
-  a, x, y: Integer;
+  a, locx, locy: Integer;
 begin
   inherited;
 
@@ -1361,27 +1417,32 @@ begin
 
   if (FIndex <> -1) and (FCounter > MENU_MARKERDELAY div 2) then
   begin
-    x := 0;
-    y := 0;
+    locx := 0;
+    locy := 0;
 
     if FItems[FIndex].Text <> nil then
     begin
-      x := FItems[FIndex].Text.FX;
-      y := FItems[FIndex].Text.FY;
+      locx := FItems[FIndex].Text.FX;
+      locy := FItems[FIndex].Text.FY;
+      //HACK!
+      if FItems[FIndex].Text.RightAlign then
+      begin
+        locx := locx+FItems[FIndex].Text.FMaxWidth-FItems[FIndex].Text.GetWidth;
+      end;
     end
     else if FItems[FIndex].Control <> nil then
     begin
-      x := FItems[FIndex].Control.FX;
-      y := FItems[FIndex].Control.FY;
+      locx := FItems[FIndex].Control.FX;
+      locy := FItems[FIndex].Control.FY;
     end;
 
-    x := x-e_CharFont_GetMaxWidth(FFontID);
+    locx := locx-e_CharFont_GetMaxWidth(FFontID);
 
-    e_CharFont_PrintEx(FFontID, x, y, #16, _RGB(255, 0, 0));
+    e_CharFont_PrintEx(FFontID, locx, locy, #16, _RGB(255, 0, 0));
   end;
 end;
 
-function TGUIMenu.GetControl(Name: String): TGUIControl;
+function TGUIMenu.GetControl(aName: String): TGUIControl;
 var
   a: Integer;
 begin
@@ -1390,16 +1451,16 @@ begin
   if FItems <> nil then
     for a := 0 to High(FItems) do
       if FItems[a].Control <> nil then
-        if LowerCase(FItems[a].Control.Name) = LowerCase(Name) then
+        if LowerCase(FItems[a].Control.Name) = LowerCase(aName) then
         begin
           Result := FItems[a].Control;
           Break;
         end;
 
-  Assert(Result <> nil, 'GUI control "'+Name+'" not found!');
+  Assert(Result <> nil, 'GUI control "'+aName+'" not found!');
 end;
 
-function TGUIMenu.GetControlsText(Name: String): TGUILabel;
+function TGUIMenu.GetControlsText(aName: String): TGUILabel;
 var
   a: Integer;
 begin
@@ -1408,13 +1469,13 @@ begin
   if FItems <> nil then
     for a := 0 to High(FItems) do
       if FItems[a].Control <> nil then
-        if LowerCase(FItems[a].Control.Name) = LowerCase(Name) then
+        if LowerCase(FItems[a].Control.Name) = LowerCase(aName) then
         begin
           Result := FItems[a].Text;
           Break;
         end;
 
-  Assert(Result <> nil, 'GUI control''s text "'+Name+'" not found!');
+  Assert(Result <> nil, 'GUI control''s text "'+aName+'" not found!');
 end;
 
 function TGUIMenu.NewItem: Integer;
@@ -1444,6 +1505,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
@@ -1496,7 +1565,7 @@ begin
             if FItems[FIndex].Control <> nil then
               FItems[FIndex].Control.OnMessage(Msg);
         end;
-        IK_RETURN, IK_KPRETURN, IK_BACKSPACE:
+        IK_RETURN, IK_KPRETURN:
         begin
           if FIndex <> -1 then
           begin
@@ -1527,10 +1596,27 @@ end;
 procedure TGUIMenu.ReAlign();
 var
   a, tx, cx, w, h: Integer;
+  cww: array of Integer; // cached widths
+  maxcww: Integer;
 begin
   if FItems = nil then Exit;
 
-  if not FAlign then tx := FLeft else
+  SetLength(cww, length(FItems));
+  maxcww := 0;
+  for a := 0 to High(FItems) do
+  begin
+    if FItems[a].Text <> nil then
+    begin
+      cww[a] := FItems[a].Text.GetWidth;
+      if maxcww < cww[a] then maxcww := cww[a];
+    end;
+  end;
+
+  if not FAlign then
+  begin
+    tx := FLeft;
+  end
+  else
   begin
     tx := gScreenWidth;
     for a := 0 to High(FItems) do
@@ -1540,27 +1626,17 @@ begin
       if FItems[a].Control <> nil then
       begin
         w := w+MENU_HSPACE;
-
-        if FItems[a].ControlType = TGUILabel then
-          w := w+(FItems[a].Control as TGUILabel).GetWidth
-        else if FItems[a].ControlType = TGUITextButton then
-          w := w+(FItems[a].Control as TGUITextButton).GetWidth
-        else if FItems[a].ControlType = TGUIScroll then
-          w := w+(FItems[a].Control as TGUIScroll).GetWidth
-        else if FItems[a].ControlType = TGUISwitch then
-          w := w+(FItems[a].Control as TGUISwitch).GetWidth
-        else if FItems[a].ControlType = TGUIEdit then
-          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 = TGUIListBox) then
-          w := w+(FItems[a].Control as TGUIListBox).GetWidth
-        else if (FItems[a].ControlType = TGUIFileListBox) then
-          w := w+(FItems[a].Control as TGUIFileListBox).GetWidth
-        else if FItems[a].ControlType = TGUIMemo then
-          w := w+(FItems[a].Control as TGUIMemo).GetWidth;
+             if FItems[a].ControlType = TGUILabel then w := w+(FItems[a].Control as TGUILabel).GetWidth
+        else if FItems[a].ControlType = TGUITextButton then w := w+(FItems[a].Control as TGUITextButton).GetWidth
+        else if FItems[a].ControlType = TGUIScroll then w := w+(FItems[a].Control as TGUIScroll).GetWidth
+        else if FItems[a].ControlType = TGUISwitch then w := w+(FItems[a].Control as TGUISwitch).GetWidth
+        else if FItems[a].ControlType = TGUIEdit then 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 w := w+(FItems[a].Control as TGUIFileListBox).GetWidth
+        else if FItems[a].ControlType = TGUIMemo then w := w+(FItems[a].Control as TGUIMemo).GetWidth;
       end;
-
       tx := Min(tx, (gScreenWidth div 2)-(w div 2));
     end;
   end;
@@ -1603,35 +1679,46 @@ begin
   end;
 
   for a := 0 to High(FItems) do
+  begin
     with FItems[a] do
     begin
       if Text <> nil then
+      begin
         with Text do
         begin
           FX := tx;
           FY := h;
         end;
+        //HACK!
+        if Text.RightAlign and (length(cww) > a) then
+        begin
+          //Text.FX := Text.FX+maxcww;
+          Text.FMaxWidth := maxcww;
+        end;
+      end;
 
-        if Control <> nil then
-          with Control do
-            if Text <> nil then
-            begin
-              FX := cx;
-              FY := h;
-            end
-            else
-            begin
-              FX := tx;
-              FY := h;
-            end;
+      if Control <> nil then
+      begin
+        with Control do
+        begin
+          if Text <> nil then
+          begin
+            FX := cx;
+            FY := h;
+          end
+          else
+          begin
+            FX := tx;
+            FY := h;
+          end;
+        end;
+      end;
 
-        if (ControlType = TGUIListBox) or (ControlType = TGUIFileListBox) then
-          Inc(h, (Control as TGUIListBox).GetHeight+MENU_VSPACE)
-        else if ControlType = TGUIMemo then
-          Inc(h, (Control as TGUIMemo).GetHeight+MENU_VSPACE)
-        else
-          Inc(h, e_CharFont_GetMaxHeight(FFontID)+MENU_VSPACE);
+           if (ControlType = TGUIListBox) or (ControlType = TGUIFileListBox) then Inc(h, (Control as TGUIListBox).GetHeight+MENU_VSPACE)
+      else if ControlType = TGUIMemo then Inc(h, (Control as TGUIMemo).GetHeight+MENU_VSPACE)
+      else Inc(h, e_CharFont_GetMaxHeight(FFontID)+MENU_VSPACE);
     end;
+  end;
 
   // another ugly hack
   if FYesNo and (length(FItems) > 1) then
@@ -1783,6 +1870,37 @@ 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_ITEMSCTRL_COLOR; //MENU_ITEMSTEXT_COLOR;
+      RightAlign := true;
+    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;
@@ -1961,7 +2079,7 @@ begin
   if a > FMax then FValue := FMax else FValue := a;
 end;
 
-function TGUIScroll.GetWidth: Word;
+function TGUIScroll.GetWidth: Integer;
 begin
   Result := 16+(FMax+1)*8;
 end;
@@ -2033,7 +2151,7 @@ begin
   else Result := '';
 end;
 
-function TGUISwitch.GetWidth: Word;
+function TGUISwitch.GetWidth: Integer;
 var
   a: Integer;
   w, h: Word;
@@ -2130,7 +2248,7 @@ begin
   end;
 end;
 
-function TGUIEdit.GetWidth: Word;
+function TGUIEdit.GetWidth: Integer;
 begin
   Result := 16+FWidth*16;
 end;
@@ -2210,6 +2328,8 @@ end;
 constructor TGUIKeyRead.Create(FontID: DWORD);
 begin
   inherited Create();
+  FKey := 0;
+  FIsQuery := false;
 
   FFont := TFont.Create(FontID, FONT_CHAR);
 end;
@@ -2222,7 +2342,7 @@ begin
              FColor.R, FColor.G, FColor.B);
 end;
 
-function TGUIKeyRead.GetWidth: Word;
+function TGUIKeyRead.GetWidth: Integer;
 var
   a: Byte;
   w, h: Word;
@@ -2242,6 +2362,13 @@ 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
@@ -2303,7 +2430,6 @@ begin
           end
           else if FIsQuery and (wParam <> IK_ENTER) and (wParam <> IK_KPRETURN) then // Not <Enter
           begin
-            e_WriteLog(Format('HIT! %s', ['3']), MSG_WARNING);
             if e_KeyNames[wParam] <> '' then
               FKey := wParam;
             FIsQuery := False;
@@ -2313,6 +2439,167 @@ begin
     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;
+
+  FMaxKeyNameWdt := FMaxKeyNameWdt-(FMaxKeyNameWdt div 3);
+
+  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 begin r := 255; g := 255; b := 255; end;
+    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: Integer;
+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 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:
+        begin
+          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;
@@ -2354,7 +2641,7 @@ begin
   if FModel = nil then
     Exit;
 
-  if FModel.Weapon < WEAPON_SUPERPULEMET then
+  if FModel.Weapon < WP_LAST then
     FModel.SetWeapon(FModel.Weapon+1)
   else
     FModel.SetWeapon(WEAPON_KASTET);
@@ -2489,15 +2776,20 @@ end;
 procedure TGUIMapPreview.SetMap(Res: string);
 var
   WAD: TWADFile;
-  MapReader: TMapReader_1;
-  panels: TPanelsRec1Array;
-  header: TMapHeaderRec_1;
-  a: Integer;
+  panlist: TDynField;
+  pan: TDynRecord;
+  //header: TMapHeaderRec_1;
   FileName: string;
   Data: Pointer;
   Len: Integer;
   rX, rY: Single;
+  map: TDynRecord = nil;
 begin
+  FMapSize.X := 0;
+  FMapSize.Y := 0;
+  FScale := 0.0;
+  FMapData := nil;
+
   FileName := g_ExtractWadName(Res);
 
   WAD := TWADFile.Create();
@@ -2516,68 +2808,71 @@ begin
 
   WAD.Free();
 
-  MapReader := TMapReader_1.Create();
-
-  if not MapReader.LoadMap(Data) then
-  begin
+  try
+    map := g_Map_ParseMap(Data, Len);
+  except
     FreeMem(Data);
-    MapReader.Free();
-    FMapSize.X := 0;
-    FMapSize.Y := 0;
-    FScale := 0.0;
-    FMapData := nil;
-    Exit;
+    map.Free();
+    //raise;
+    exit;
   end;
 
   FreeMem(Data);
 
-  panels := MapReader.GetPanels();
-  header := MapReader.GetMapHeader();
+  if (map = nil) then exit;
 
-  FMapSize.X := header.Width div 16;
-  FMapSize.Y := header.Height div 16;
+  try
+    panlist := map.field['panel'];
+    //header := GetMapHeader(map);
 
-  rX := Ceil(header.Width / (MAPPREVIEW_WIDTH*256.0));
-  rY := Ceil(header.Height / (MAPPREVIEW_HEIGHT*256.0));
-  FScale := max(rX, rY);
+    FMapSize.X := map.Width div 16;
+    FMapSize.Y := map.Height div 16;
 
-  FMapData := nil;
+    rX := Ceil(map.Width / (MAPPREVIEW_WIDTH*256.0));
+    rY := Ceil(map.Height / (MAPPREVIEW_HEIGHT*256.0));
+    FScale := max(rX, rY);
 
-  if panels <> nil then
-    for a := 0 to High(panels) do
-      if WordBool(panels[a].PanelType and (PANEL_WALL or PANEL_CLOSEDOOR or
-                                           PANEL_STEP or PANEL_WATER or
-                                           PANEL_ACID1 or PANEL_ACID2)) then
+    FMapData := nil;
+
+    if (panlist <> nil) then
+    begin
+      for pan in panlist do
       begin
-        SetLength(FMapData, Length(FMapData)+1);
-        with FMapData[High(FMapData)] do
+        if (pan.PanelType and (PANEL_WALL or PANEL_CLOSEDOOR or
+                                             PANEL_STEP or PANEL_WATER or
+                                             PANEL_ACID1 or PANEL_ACID2)) <> 0 then
         begin
-          X1 := panels[a].X div 16;
-          Y1 := panels[a].Y div 16;
+          SetLength(FMapData, Length(FMapData)+1);
+          with FMapData[High(FMapData)] do
+          begin
+            X1 := pan.X div 16;
+            Y1 := pan.Y div 16;
 
-          X2 := (panels[a].X + panels[a].Width) div 16;
-          Y2 := (panels[a].Y + panels[a].Height) div 16;
+            X2 := (pan.X + pan.Width) div 16;
+            Y2 := (pan.Y + pan.Height) div 16;
 
-          X1 := Trunc(X1/FScale + 0.5);
-          Y1 := Trunc(Y1/FScale + 0.5);
-          X2 := Trunc(X2/FScale + 0.5);
-          Y2 := Trunc(Y2/FScale + 0.5);
+            X1 := Trunc(X1/FScale + 0.5);
+            Y1 := Trunc(Y1/FScale + 0.5);
+            X2 := Trunc(X2/FScale + 0.5);
+            Y2 := Trunc(Y2/FScale + 0.5);
 
-          if (X1 <> X2) or (Y1 <> Y2) then
-          begin
-            if X1 = X2 then
-              X2 := X2 + 1;
-            if Y1 = Y2 then
-              Y2 := Y2 + 1;
-          end;
+            if (X1 <> X2) or (Y1 <> Y2) then
+            begin
+              if X1 = X2 then
+                X2 := X2 + 1;
+              if Y1 = Y2 then
+                Y2 := Y2 + 1;
+            end;
 
-          PanelType := panels[a].PanelType;
+            PanelType := pan.PanelType;
+          end;
+        end;
       end;
-   end;
-
-  panels := nil;
-
-  MapReader.Free();
+    end;
+  finally
+    //writeln('freeing map');
+    map.Free();
+  end;
 end;
 
 procedure TGUIMapPreview.ClearMap();
@@ -2674,12 +2969,12 @@ begin
     end;
 end;
 
-function TGUIListBox.GetHeight: Word;
+function TGUIListBox.GetHeight: Integer;
 begin
   Result := 8+FHeight*16;
 end;
 
-function TGUIListBox.GetWidth: Word;
+function TGUIListBox.GetWidth: Integer;
 begin
   Result := 8+(FWidth+1)*16;
 end;
@@ -3043,12 +3338,12 @@ begin
       FFont.Draw(FX+4, FY+4+(a-FStartLine)*16, FLines[a], FColor.R, FColor.G, FColor.B);
 end;
 
-function TGUIMemo.GetHeight: Word;
+function TGUIMemo.GetHeight: Integer;
 begin
   Result := 8+FHeight*16;
 end;
 
-function TGUIMemo.GetWidth: Word;
+function TGUIMemo.GetWidth: Integer;
 begin
   Result := 8+(FWidth+1)*16;
 end;