DEADSOFTWARE

holmes: fix build with -dDISABLE_GFX
[d2df-sdl.git] / src / game / g_gui.pas
index 3181e6969102e55d77b1be621b7e46ab32158a79..fe15869bee62b7ab781b7d04015caf5a7285c987 100644 (file)
@@ -19,7 +19,7 @@ interface
 
 uses
   {$IFDEF USE_MEMPOOL}mempool,{$ENDIF}
-  e_graphics, e_input, e_log, g_playermodel, g_basic, g_touch, MAPDEF, utils;
+  g_base, r_graphics, e_input, e_log, g_playermodel, g_basic, MAPDEF, utils;
 
 const
   MAINMENU_HEADER_COLOR: TRGB = (R:255; G:255; B:255);
@@ -75,6 +75,8 @@ const
   WM_CHAR    = 102;
   WM_USER    = 110;
 
+  MESSAGE_DIKEY = WM_USER + 1;
+
 type
   TMessage = record
     Msg: DWORD;
@@ -550,9 +552,11 @@ procedure g_GUI_LoadMenuPos();
 implementation
 
 uses
-  {$INCLUDE ../nogl/noGLuses.inc}
-  g_textures, g_sound, SysUtils, e_res,
-  g_game, Math, StrUtils, g_player, g_options,
+  {$IFDEF ENABLE_TOUCH}
+    g_system,
+  {$ENDIF}
+  g_sound, SysUtils, e_res, r_textures,
+  g_game, Math, StrUtils, g_player, g_options, g_console, r_playermodel,
   g_map, g_weapons, xdynrec, wadreader;
 
 
@@ -560,6 +564,81 @@ var
   Box: Array [0..8] of DWORD;
   Saved_Windows: SSArray;
 
+function GetLines (text: string; FontID: DWORD; MaxWidth: Word): SSArray;
+  var
+    k: Integer = 1;
+    lines: Integer = 0;
+    i, len, lastsep: Integer;
+
+  function PrepareStep (): Boolean; inline;
+  begin
+    // Skip leading spaces.
+    while PChar(text)[k-1] = ' ' do k += 1;
+    Result := k <= len;
+    i := k;
+  end;
+
+  function GetLine (j: Integer; Strip: Boolean): String; inline;
+  begin
+    // Exclude trailing spaces from the line.
+    if Strip then
+      while text[j] = ' ' do j -= 1;
+
+    Result := Copy(text, k, j-k+1);
+  end;
+
+  function LineWidth (): Integer; inline;
+    var w, h: Word;
+  begin
+    e_CharFont_GetSize(FontID, GetLine(i, False), w, h);
+    Result := w;
+  end;
+
+begin
+  Result := nil;
+  len := Length(text);
+  //e_LogWritefln('GetLines @%s len=%s [%s]', [MaxWidth, len, text]);
+
+  while PrepareStep() do
+  begin
+    // Get longest possible sequence (this is not constant because fonts are not monospaced).
+    lastsep := 0;
+    repeat
+      if text[i] in [' ', '.', ',', ':', ';']
+        then lastsep := i;
+      i += 1;
+    until (i > len) or (LineWidth() > MaxWidth);
+
+    // Do not include part of a word if possible.
+    if (lastsep-k > 3) and (i <= len) and (text[i] <> ' ')
+      then i := lastsep + 1;
+
+    // Add line.
+    SetLength(Result, lines + 1);
+    Result[lines] := GetLine(i-1, True);
+    //e_LogWritefln('  -> (%s:%s::%s) [%s]', [k, i, LineWidth(), Result[lines]]);
+    lines += 1;
+
+    k := i;
+  end;
+end;
+
+procedure Sort(var a: SSArray);
+var
+  i, j: Integer;
+  s: string;
+begin
+  if a = nil then Exit;
+
+  for i := High(a) downto Low(a) do
+    for j := Low(a) to High(a)-1 do
+      if LowerCase(a[j]) > LowerCase(a[j+1]) then
+      begin
+        s := a[j];
+        a[j] := a[j+1];
+        a[j+1] := s;
+      end;
+end;
 
 procedure g_GUI_Init();
 begin
@@ -819,7 +898,7 @@ begin
   if FBackTexture <> '' then  // Here goes code duplication from g_game.pas:DrawMenuBackground()
     if g_Texture_Get(FBackTexture, ID) then
     begin
-      e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
+      e_Clear(0, 0, 0);
       e_GetTextureSize(ID, @tw, @th);
       if tw = th then
         tw := round(tw * 1.333 * (gScreenHeight / th))
@@ -828,7 +907,7 @@ begin
       e_DrawSize(ID, (gScreenWidth - tw) div 2, 0, 0, False, False, tw, gScreenHeight);
     end
     else
-      e_Clear(GL_COLOR_BUFFER_BIT, 0.5, 0.5, 0.5);
+      e_Clear(0.5, 0.5, 0.5);
 
   // small hack here
   if FName = 'AuthorsMenu' then
@@ -2363,7 +2442,10 @@ begin
     end;
 
   g_GUIGrabInput := (@FOnEnterEvent = nil) and (FWindow.FActiveControl = Self);
-  g_Touch_ShowKeyboard(g_GUIGrabInput)
+
+  {$IFDEF ENABLE_TOUCH}
+    sys_ShowKeyboard(g_GUIGrabInput)
+  {$ENDIF}
 end;
 
 procedure TGUIEdit.SetText(Text: string);
@@ -2443,58 +2525,40 @@ begin
   with Msg do
     case Msg of
       WM_KEYDOWN:
-        case wParam of
-          VK_ESCAPE:
-            begin
-              if FIsQuery then actDefCtl();
-              FIsQuery := False;
-            end;
-          IK_RETURN, IK_KPRETURN, VK_FIRE, VK_OPEN, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
-            begin
-              if not FIsQuery then
-                begin
-                  with FWindow do
-                    if FActiveControl <> Self then
-                      SetActive(Self);
-
-                  FIsQuery := True;
-                end
-              else if (wParam < VK_FIRSTKEY) and (wParam > VK_LASTKEY) then
-                begin
-                  // FKey := IK_ENTER; // <Enter>
-                  FKey := wParam;
-                  FIsQuery := False;
-                  actDefCtl();
-                end;
-            end;
-          IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
-            begin
-              if not FIsQuery then
+        if not FIsQuery then
+        begin
+          case wParam of
+            IK_RETURN, IK_KPRETURN, VK_FIRE, VK_OPEN, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
+              begin
+                with FWindow do
+                  if FActiveControl <> Self then
+                    SetActive(Self);
+                FIsQuery := True;
+              end;
+            IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
               begin
                 FKey := 0;
                 actDefCtl();
               end;
-            end;
-        end;
-
-      MESSAGE_DIKEY:
+          else
+            FIsQuery := False;
+            actDefCtl();
+          end;
+        end
+        else
         begin
-          if not FIsQuery and (wParam = IK_BACKSPACE) then
-          begin
-            FKey := 0;
+          case wParam of
+            VK_FIRSTKEY..VK_LASTKEY: // do not allow to bind virtual keys
+              begin
+                FIsQuery := False;
+                actDefCtl();
+              end;
+          else
+            if (e_KeyNames[wParam] <> '') and not g_Console_MatchBind(wParam, 'togglemenu') then
+              FKey := wParam;
+            FIsQuery := False;
             actDefCtl();
           end
-          else if FIsQuery then
-          begin
-            case wParam of
-              IK_ENTER, IK_KPRETURN, VK_FIRSTKEY..VK_LASTKEY (*, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK*): // Not <Enter
-            else
-              if e_KeyNames[wParam] <> '' then
-                FKey := wParam;
-              FIsQuery := False;
-              actDefCtl();
-            end
-          end;
         end;
     end;
 
@@ -2599,72 +2663,52 @@ begin
   with Msg do
     case Msg of
       WM_KEYDOWN:
-        case wParam of
-          VK_ESCAPE:
-            begin
-              if FIsQuery then actDefCtl();
-              FIsQuery := False;
-            end;
-          IK_RETURN, IK_KPRETURN, VK_FIRE, VK_OPEN, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
-            begin
-              if not FIsQuery then
-                begin
-                  with FWindow do
-                    if FActiveControl <> Self then
-                      SetActive(Self);
-
-                  FIsQuery := True;
-                end
-              else if (wParam < VK_FIRSTKEY) and (wParam > VK_LASTKEY) then
-                begin
-                  // if (FKeyIdx = 0) then FKey0 := IK_ENTER else FKey1 := IK_ENTER; // <Enter>
-                  if (FKeyIdx = 0) then FKey0 := wParam else FKey1 := wParam;
-                  FIsQuery := False;
-                  actDefCtl();
-                end;
-            end;
-          IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
-            begin
-              if not FIsQuery then
+        if not FIsQuery then
+        begin
+          case wParam of
+            IK_RETURN, IK_KPRETURN, VK_FIRE, VK_OPEN, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
+              begin
+                with FWindow do
+                  if FActiveControl <> Self then
+                    SetActive(Self);
+                FIsQuery := True;
+              end;
+            IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
               begin
                 if (FKeyIdx = 0) then FKey0 := 0 else FKey1 := 0;
                 actDefCtl();
               end;
-            end;
-          IK_LEFT, IK_KPLEFT, VK_LEFT, JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
-            if not FIsQuery then
-            begin
-              FKeyIdx := 0;
-              actDefCtl();
-            end;
-          IK_RIGHT, IK_KPRIGHT, VK_RIGHT, JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT:
-            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 then
-          begin
-            case wParam of
-              IK_ENTER, IK_KPRETURN, VK_FIRSTKEY..VK_LASTKEY (*, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK*): // Not <Enter
-            else
-              if e_KeyNames[wParam] <> '' then
+            IK_LEFT, IK_KPLEFT, VK_LEFT, JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
+              begin
+                FKeyIdx := 0;
+                actDefCtl();
+              end;
+            IK_RIGHT, IK_KPRIGHT, VK_RIGHT, JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT:
               begin
-                if (FKeyIdx = 0) then FKey0 := wParam else FKey1 := wParam;
+                FKeyIdx := 1;
+                actDefCtl();
               end;
-              FIsQuery := False;
-              actDefCtl()
-            end
+          else
+            FIsQuery := False;
+            actDefCtl();
           end;
+        end
+        else
+        begin
+          case wParam of
+            VK_FIRSTKEY..VK_LASTKEY: // do not allow to bind virtual keys
+              begin
+                FIsQuery := False;
+                actDefCtl();
+              end;
+          else
+            if (e_KeyNames[wParam] <> '') and not g_Console_MatchBind(wParam, 'togglemenu') then
+            begin
+              if (FKeyIdx = 0) then FKey0 := wParam else FKey1 := wParam;
+            end;
+            FIsQuery := False;
+            actDefCtl()
+          end
         end;
     end;
 
@@ -2694,7 +2738,8 @@ begin
 
   DrawBox(FX, FY, 4, 4);
 
-  if FModel <> nil then FModel.Draw(FX+4, FY+4);
+  if FModel <> nil then
+    r_PlayerModel_Draw(FModel, FX+4, FY+4);
 end;
 
 procedure TGUIModelView.NextAnim();
@@ -2984,7 +3029,7 @@ begin
   SetLength(FItems, Length(FItems)+1);
   FItems[High(FItems)] := Item;
 
-  if FSort then g_Basic.Sort(FItems);
+  if FSort then g_gui.Sort(FItems);
 end;
 
 function TGUIListBox.ItemExists (item: String): Boolean;
@@ -3139,7 +3184,7 @@ begin
   FStartLine := 0;
   FIndex := -1;
 
-  if FSort then g_Basic.Sort(FItems);
+  if FSort then g_gui.Sort(FItems);
 end;
 
 procedure TGUIListBox.SelectItem(Item: String);
@@ -3270,13 +3315,13 @@ begin
                   begin
                     if FItems[FIndex] = #29 + '..' then
                     begin
-                      e_LogWritefln('TGUIFileListBox: Upper dir "%s" -> "%s"', [FSubPath, e_UpperDir(FSubPath)]);
+                      //e_LogWritefln('TGUIFileListBox: Upper dir "%s" -> "%s"', [FSubPath, e_UpperDir(FSubPath)]);
                       FSubPath := e_UpperDir(FSubPath)
                     end
                     else
                     begin
                       s := Copy(AnsiString(FItems[FIndex]), 2);
-                      e_LogWritefln('TGUIFileListBox: Enter dir "%s" -> "%s"', [FSubPath, e_CatPath(FSubPath, s)]);
+                      //e_LogWritefln('TGUIFileListBox: Enter dir "%s" -> "%s"', [FSubPath, e_CatPath(FSubPath, s)]);
                       FSubPath := e_CatPath(FSubPath, s);
                     end;
                     ScanDirs;