hedgewars/uChat.pas
changeset 10921 05e6f3b02612
parent 10920 11a28d22985f
child 10926 43612076e989
equal deleted inserted replaced
10920:11a28d22985f 10921:05e6f3b02612
    34 
    34 
    35 implementation
    35 implementation
    36 uses SDLh, uInputHandler, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO, uScript, uRenderUtils;
    36 uses SDLh, uInputHandler, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO, uScript, uRenderUtils;
    37 
    37 
    38 const MaxStrIndex = 27;
    38 const MaxStrIndex = 27;
    39       MaxInputStrLen = 240;
    39       MaxInputStrLen = 200;
    40 
    40 
    41 type TChatLine = record
    41 type TChatLine = record
    42     Tex: PTexture;
    42     Tex: PTexture;
    43     Time: Longword;
    43     Time: Longword;
    44     Width: LongInt;
    44     Width: LongInt;
    66     cursorPos, cursorX, selectedPos, selectionDx: LongInt;
    66     cursorPos, cursorX, selectedPos, selectionDx: LongInt;
    67     LastKeyPressTick: LongWord;
    67     LastKeyPressTick: LongWord;
    68 
    68 
    69 
    69 
    70 const
    70 const
    71     InputStrLNoPred: byte = 255;
       
    72 
       
    73     colors: array[#0..#6] of TSDL_Color = (
    71     colors: array[#0..#6] of TSDL_Color = (
    74             (r:$FF; g:$FF; b:$FF; a:$FF), // unused, feel free to take it for anything
    72             (r:$FF; g:$FF; b:$FF; a:$FF), // unused, feel free to take it for anything
    75             (r:$FF; g:$FF; b:$FF; a:$FF), // chat message [White]
    73             (r:$FF; g:$FF; b:$FF; a:$FF), // chat message [White]
    76             (r:$FF; g:$00; b:$FF; a:$FF), // action message [Purple]
    74             (r:$FF; g:$00; b:$FF; a:$FF), // action message [Purple]
    77             (r:$90; g:$FF; b:$90; a:$FF), // join/leave message [Lime]
    75             (r:$90; g:$FF; b:$90; a:$FF), // join/leave message [Lime]
    93 
    91 
    94 const Padding  = 2;
    92 const Padding  = 2;
    95       ClHeight = 2 * Padding + 16; // font height
    93       ClHeight = 2 * Padding + 16; // font height
    96 
    94 
    97 // relevant for UTF-8 handling
    95 // relevant for UTF-8 handling
    98 function IsFirstCharByte(b: byte): boolean; inline;
    96 function IsFirstCharByte(c: char): boolean; inline;
    99 begin
    97 begin
   100     // based on https://en.wikipedia.org/wiki/UTF-8#Description
    98     // based on https://en.wikipedia.org/wiki/UTF-8#Description
   101     IsFirstCharByte:= (b and $C0) <> $80;
    99     IsFirstCharByte:= (byte(c) and $C0) <> $80;
   102 end;
   100 end;
   103 
   101 
   104 function charIsForHogSpeech(c: char): boolean;
   102 function charIsForHogSpeech(c: char): boolean;
   105 begin
   103 begin
   106 exit((c = '"') or (c = '''') or (c = '-'));
   104 exit((c = '"') or (c = '''') or (c = '-'));
   595 
   593 
   596 procedure MoveCursorToPreviousChar();
   594 procedure MoveCursorToPreviousChar();
   597 begin
   595 begin
   598     if cursorPos > 0 then
   596     if cursorPos > 0 then
   599         begin
   597         begin
   600         while (not IsFirstCharByte(byte(InputStr.s[cursorPos]))) do
   598         while (not IsFirstCharByte(InputStr.s[cursorPos])) do
   601             begin
   599             begin
   602             dec(cursorPos);
   600             dec(cursorPos);
   603             end;
   601             end;
   604         dec(cursorPos);
   602         dec(cursorPos);
   605         end;
   603         end;
   608 procedure MoveCursorToNextChar();
   606 procedure MoveCursorToNextChar();
   609 begin
   607 begin
   610     if cursorPos <  Length(InputStr.s) then
   608     if cursorPos <  Length(InputStr.s) then
   611         begin
   609         begin
   612         inc(cursorPos, 2);
   610         inc(cursorPos, 2);
   613         while (cursorPos <  Length(InputStr.s)) and (not IsFirstCharByte(byte(InputStr.s[cursorPos]))) do
   611         while (cursorPos <  Length(InputStr.s)) and (not IsFirstCharByte(InputStr.s[cursorPos])) do
   614             begin
   612             begin
   615             inc(cursorPos);
   613             inc(cursorPos);
   616             end;
   614             end;
   617         dec(cursorPos);
   615         dec(cursorPos);
   618         end;
   616         end;
       
   617 end;
       
   618 
       
   619 procedure DeleteLastUTF8CharFromStr(var s: shortstring);
       
   620 var l: byte;
       
   621 begin
       
   622     l:= Length(s);
       
   623 
       
   624     while (l > 1) and (not IsFirstCharByte(s[l])) do
       
   625         begin
       
   626         dec(l);
       
   627         end;
       
   628 
       
   629     if l > 0 then
       
   630         dec(l);
       
   631 
       
   632     s[0]:= char(l);
   619 end;
   633 end;
   620 
   634 
   621 procedure DeleteSelected();
   635 procedure DeleteSelected();
   622 begin
   636 begin
   623     if (selectedPos >= 0) and (cursorPos <> selectedPos) then
   637     if (selectedPos >= 0) and (cursorPos <> selectedPos) then
   730         CopyToClipboard(selection);
   744         CopyToClipboard(selection);
   731         end;
   745         end;
   732 end;
   746 end;
   733 
   747 
   734 procedure InsertIntoInputStr(s: shortstring);
   748 procedure InsertIntoInputStr(s: shortstring);
   735 var l, lastc: integer;
   749 var limit: integer;
   736 begin
   750 begin
   737     // safe length for string
   751     // we check limit for trailing stuff before insertion limit for a reason
   738     l:= min(MaxInputStrLen-cursorPos, Length(s));
   752     // (possible remaining space after too long UTF8-insertion has been shortened)
   739     // SetLength(s, l);
   753 
   740     s[0]:= char(l);
   754     // length limit for stuff to that will trail the insertion
   741 
   755     limit:= max(cursorPos, MaxInputStrLen-Length(s));
   742     // insert string truncated to safe length
   756 
   743     Insert(s, InputStr.s, cursorPos + 1);
   757     while Length(InputStr.s) > limit do
   744     // TODO: honor utf8, don't break utf8 chars when shifting chars beyond limit
   758         begin
   745     if Length(InputStr.s) > MaxInputStrLen then
   759         DeleteLastUTF8CharFromStr(InputStr.s);
   746         InputStr.s[0]:= char(MaxInputStrLen);
   760         end;
   747 
   761 
   748     SetLine(InputStr, InputStr.s, true);
   762     // length limit for stuff to insert
   749 
   763     limit:= max(0, MaxInputStrLen-cursorPos);
   750     // move cursor to end of inserted string
   764 
   751     lastc:= MaxInputStrLen;
   765     if limit = 0 then
   752     cursorPos:= min(lastc, cursorPos + l);
   766         s:= ''
   753     UpdateCursorCoords();
   767     else while Length(s) > limit do
       
   768         begin
       
   769         DeleteLastUTF8CharFromStr(s);
       
   770         end;
       
   771 
       
   772     if Length(s) > 0 then
       
   773         begin
       
   774         // insert string truncated to safe length
       
   775         Insert(s, InputStr.s, cursorPos + 1);
       
   776 
       
   777         if Length(InputStr.s) > MaxInputStrLen then
       
   778             InputStr.s[0]:= char(MaxInputStrLen);
       
   779 
       
   780         SetLine(InputStr, InputStr.s, true);
       
   781 
       
   782         // move cursor to end of inserted string
       
   783         inc(cursorPos, Length(s));
       
   784         UpdateCursorCoords();
       
   785         end;
   754 end;
   786 end;
   755 
   787 
   756 procedure PasteFromClipboard();
   788 procedure PasteFromClipboard();
   757 begin
   789 begin
   758     SendIPC(_S'Y');
   790     SendIPC(_S'Y');
   961             end;
   993             end;
   962         SDLK_v:
   994         SDLK_v:
   963             begin
   995             begin
   964             // paste
   996             // paste
   965             if ctrl then
   997             if ctrl then
   966                 PasteFromClipboard()
   998                 begin
       
   999                 DeleteSelected();
       
  1000                 PasteFromClipboard();
       
  1001                 end
   967             else
  1002             else
   968                 action:= false;
  1003                 action:= false;
   969             end;
  1004             end;
   970         SDLK_x:
  1005         SDLK_x:
   971             begin
  1006             begin