hedgewars/uChat.pas
changeset 10921 05e6f3b02612
parent 10920 11a28d22985f
child 10926 43612076e989
--- a/hedgewars/uChat.pas	Thu Apr 30 21:53:41 2015 +0200
+++ b/hedgewars/uChat.pas	Fri May 01 00:17:38 2015 +0200
@@ -36,7 +36,7 @@
 uses SDLh, uInputHandler, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO, uScript, uRenderUtils;
 
 const MaxStrIndex = 27;
-      MaxInputStrLen = 240;
+      MaxInputStrLen = 200;
 
 type TChatLine = record
     Tex: PTexture;
@@ -68,8 +68,6 @@
 
 
 const
-    InputStrLNoPred: byte = 255;
-
     colors: array[#0..#6] of TSDL_Color = (
             (r:$FF; g:$FF; b:$FF; a:$FF), // unused, feel free to take it for anything
             (r:$FF; g:$FF; b:$FF; a:$FF), // chat message [White]
@@ -95,10 +93,10 @@
       ClHeight = 2 * Padding + 16; // font height
 
 // relevant for UTF-8 handling
-function IsFirstCharByte(b: byte): boolean; inline;
+function IsFirstCharByte(c: char): boolean; inline;
 begin
     // based on https://en.wikipedia.org/wiki/UTF-8#Description
-    IsFirstCharByte:= (b and $C0) <> $80;
+    IsFirstCharByte:= (byte(c) and $C0) <> $80;
 end;
 
 function charIsForHogSpeech(c: char): boolean;
@@ -597,7 +595,7 @@
 begin
     if cursorPos > 0 then
         begin
-        while (not IsFirstCharByte(byte(InputStr.s[cursorPos]))) do
+        while (not IsFirstCharByte(InputStr.s[cursorPos])) do
             begin
             dec(cursorPos);
             end;
@@ -610,7 +608,7 @@
     if cursorPos <  Length(InputStr.s) then
         begin
         inc(cursorPos, 2);
-        while (cursorPos <  Length(InputStr.s)) and (not IsFirstCharByte(byte(InputStr.s[cursorPos]))) do
+        while (cursorPos <  Length(InputStr.s)) and (not IsFirstCharByte(InputStr.s[cursorPos])) do
             begin
             inc(cursorPos);
             end;
@@ -618,6 +616,22 @@
         end;
 end;
 
+procedure DeleteLastUTF8CharFromStr(var s: shortstring);
+var l: byte;
+begin
+    l:= Length(s);
+
+    while (l > 1) and (not IsFirstCharByte(s[l])) do
+        begin
+        dec(l);
+        end;
+
+    if l > 0 then
+        dec(l);
+
+    s[0]:= char(l);
+end;
+
 procedure DeleteSelected();
 begin
     if (selectedPos >= 0) and (cursorPos <> selectedPos) then
@@ -732,25 +746,43 @@
 end;
 
 procedure InsertIntoInputStr(s: shortstring);
-var l, lastc: integer;
+var limit: integer;
 begin
-    // safe length for string
-    l:= min(MaxInputStrLen-cursorPos, Length(s));
-    // SetLength(s, l);
-    s[0]:= char(l);
+    // we check limit for trailing stuff before insertion limit for a reason
+    // (possible remaining space after too long UTF8-insertion has been shortened)
+
+    // length limit for stuff to that will trail the insertion
+    limit:= max(cursorPos, MaxInputStrLen-Length(s));
+
+    while Length(InputStr.s) > limit do
+        begin
+        DeleteLastUTF8CharFromStr(InputStr.s);
+        end;
+
+    // length limit for stuff to insert
+    limit:= max(0, MaxInputStrLen-cursorPos);
 
-    // insert string truncated to safe length
-    Insert(s, InputStr.s, cursorPos + 1);
-    // TODO: honor utf8, don't break utf8 chars when shifting chars beyond limit
-    if Length(InputStr.s) > MaxInputStrLen then
-        InputStr.s[0]:= char(MaxInputStrLen);
+    if limit = 0 then
+        s:= ''
+    else while Length(s) > limit do
+        begin
+        DeleteLastUTF8CharFromStr(s);
+        end;
 
-    SetLine(InputStr, InputStr.s, true);
+    if Length(s) > 0 then
+        begin
+        // insert string truncated to safe length
+        Insert(s, InputStr.s, cursorPos + 1);
 
-    // move cursor to end of inserted string
-    lastc:= MaxInputStrLen;
-    cursorPos:= min(lastc, cursorPos + l);
-    UpdateCursorCoords();
+        if Length(InputStr.s) > MaxInputStrLen then
+            InputStr.s[0]:= char(MaxInputStrLen);
+
+        SetLine(InputStr, InputStr.s, true);
+
+        // move cursor to end of inserted string
+        inc(cursorPos, Length(s));
+        UpdateCursorCoords();
+        end;
 end;
 
 procedure PasteFromClipboard();
@@ -963,7 +995,10 @@
             begin
             // paste
             if ctrl then
-                PasteFromClipboard()
+                begin
+                DeleteSelected();
+                PasteFromClipboard();
+                end
             else
                 action:= false;
             end;