hedgewars/uChat.pas
branchui-scaling
changeset 13385 ec1491bb5acc
parent 13077 c213645ff848
child 13386 72bbccf9a715
equal deleted inserted replaced
13346:e461deddc942 13385:ec1491bb5acc
    33 procedure SendHogSpeech(s: shortstring);
    33 procedure SendHogSpeech(s: shortstring);
    34 procedure CopyToClipboard(var newContent: shortstring);
    34 procedure CopyToClipboard(var newContent: shortstring);
    35 procedure TextInput(var event: TSDL_TextInputEvent);
    35 procedure TextInput(var event: TSDL_TextInputEvent);
    36 
    36 
    37 implementation
    37 implementation
    38 uses uInputHandler, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO, uScript, uRenderUtils;
    38 uses uConsts, uInputHandler, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO, uScript, uRenderUtils, uStore, Math;
    39 
    39 
    40 const MaxStrIndex = 27;
    40 const MaxStrIndex = 27;
    41       MaxInputStrLen = 200;
    41       MaxInputStrLen = 200;
    42 
    42 
    43 type TChatLine = record
    43 type TChatLine = record
    91             (ChatCmd: '/history'; ProcedureCallChatCmd: 'history'),
    91             (ChatCmd: '/history'; ProcedureCallChatCmd: 'history'),
    92             (ChatCmd: '/fullscreen'; ProcedureCallChatCmd: 'fullscr')
    92             (ChatCmd: '/fullscreen'; ProcedureCallChatCmd: 'fullscr')
    93             );
    93             );
    94 
    94 
    95 
    95 
    96 const Padding  = 2;
    96 const PaddingFactor = (1/6); // relative to font size
    97       ClHeight = 2 * Padding + 16; // font height
    97 
       
    98 var Padding, ClHeight: integer;
       
    99     LastChatScaleValue, LastUIScaleValue: real;
       
   100     SkipNextInput: boolean;
       
   101 
       
   102 procedure UpdateInputLinePrefix(); forward;
       
   103 procedure UpdateCursorCoords(); forward;
    98 
   104 
    99 // relevant for UTF-8 handling
   105 // relevant for UTF-8 handling
   100 function IsFirstCharByte(c: char): boolean; inline;
   106 function IsFirstCharByte(c: char): boolean; inline;
   101 begin
   107 begin
   102     // based on https://en.wikipedia.org/wiki/UTF-8#Description
   108     // based on https://en.wikipedia.org/wiki/UTF-8#Description
   109 end;
   115 end;
   110 
   116 
   111 procedure ResetSelection();
   117 procedure ResetSelection();
   112 begin
   118 begin
   113     selectedPos:= -1;
   119     selectedPos:= -1;
       
   120 end;
       
   121 
       
   122 procedure AdjustToUIScale();
       
   123 var fntSize: integer;
       
   124 begin
       
   125     // don't do anything if no change
       
   126     if (ChatScaleValue = LastChatScaleValue) and (UIScaleValue = LastUIScaleValue) then
       
   127         exit;
       
   128 
       
   129     LastChatScaleValue:= ChatScaleValue;
       
   130     LastUIScaleValue:= UIScaleValue;
       
   131 
       
   132     // determine font size - note: +0.1 to because I don't trust float inaccuracy combined with floor
       
   133     fntSize:= max(1, floor(UIScaleValue * ChatScaleValue * Fontz[fnt16].Height + 0.1));
       
   134 
       
   135     if Fontz[fntChat].Height <> fntSize then
       
   136         begin
       
   137         // adjust associated heights
       
   138         Fontz[fntChat].Height:= fntSize;
       
   139         Fontz[CJKfntChat].Height:= fntSize;
       
   140         // reload if initialized already
       
   141         if Fontz[fntChat].Handle <> nil then
       
   142             LoadFont(fntChat);
       
   143         if Fontz[CJKfntChat].Handle <> nil then
       
   144             LoadFont(CJKfntChat);
       
   145         end;
       
   146 
       
   147     // adjust line height etc.
       
   148     Padding:= max(1, floor(PaddingFactor * fntSize + 0.1));
       
   149     ClHeight:= 2 * Padding + fntSize;
       
   150 
       
   151     // clear cache of already rendered lines
       
   152     ReloadLines();
       
   153     UpdateInputLinePrefix();
       
   154     UpdateCursorCoords();
       
   155 end;
       
   156 
       
   157 procedure ChatSizeInc();
       
   158 begin
       
   159 // TODO cChatMinScaleLevel, cChatSizeDelta (probably half of cZoomDelta)
       
   160 // TODO always - effectively -- increase font by 1px?
       
   161 if ChatScaleValue < cMinZoomLevel then
       
   162     begin
       
   163     ChatScaleValue:= ChatScaleValue + cZoomDelta;
       
   164     AdjustToUIScale();
       
   165     end;
       
   166 end;
       
   167 
       
   168 procedure ChatSizeDec();
       
   169 begin
       
   170 // TODO cChatMaxScaleLevel, cChatSizeDelta (probably half of cZoomDelta)
       
   171 // TODO always - effectively -- increase font by 1px?
       
   172 if ChatScaleValue > cMaxZoomLevel then
       
   173     begin
       
   174     ChatScaleValue:= ChatScaleValue - cZoomDelta;
       
   175     AdjustToUIScale();
       
   176     end;
       
   177 end;
       
   178 
       
   179 procedure chatSizeReset();
       
   180 begin
       
   181 ChatScaleValue:= cDefaultChatScaleLevel;
       
   182 AdjustToUIScale();
       
   183 end;
       
   184 
       
   185 function GetChatFont(str: shortstring): THWFONT;
       
   186 begin
       
   187     GetChatFont:= CheckCJKFont(ansistring(str), fntChat);
   114 end;
   188 end;
   115 
   189 
   116 procedure UpdateCursorCoords();
   190 procedure UpdateCursorCoords();
   117 var font: THWFont;
   191 var font: THWFont;
   118     str : shortstring;
   192     str : shortstring;
   119     coff, soff: LongInt;
   193     coff, soff: LongInt;
   120 begin
   194 begin
       
   195     AdjustToUIScale();
       
   196 
   121     if cursorPos = selectedPos then
   197     if cursorPos = selectedPos then
   122         ResetSelection();
   198         ResetSelection();
   123 
   199 
   124     // calculate cursor offset
   200     // calculate cursor offset
   125 
   201 
   126     str:= InputStr.s;
   202     str:= InputStr.s;
   127     font:= CheckCJKFont(ansistring(str), fnt16);
   203     font:= GetChatFont(str);
   128 
   204 
   129     // get only substring before cursor to determine length
   205     // get only substring before cursor to determine length
   130     // SetLength(str, cursorPos); // makes pas2c unhappy
   206     // SetLength(str, cursorPos); // makes pas2c unhappy
   131     str[0]:= char(cursorPos);
   207     str[0]:= char(cursorPos);
   132     // get render size of text
   208     // get render size of text
   133     TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(str), @coff, nil);
   209     TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(str), @coff, nil);
   134 
   210     cursorX:= Padding + coff;
   135     cursorX:= 2 + coff;
       
   136 
   211 
   137     // calculate selection width on screen
   212     // calculate selection width on screen
   138     if selectedPos >= 0 then
   213     if selectedPos >= 0 then
   139         begin
   214         begin
   140         if selectedPos > cursorPos then
   215         if selectedPos > cursorPos then
   168     shadowint  = $80 shl AShift;
   243     shadowint  = $80 shl AShift;
   169 begin
   244 begin
   170 
   245 
   171 FreeAndNilTexture(cl.Tex);
   246 FreeAndNilTexture(cl.Tex);
   172 
   247 
   173 font:= CheckCJKFont(ansistring(str), fnt16);
   248 font:= GetChatFont(str);
   174 
   249 
   175 // get render size of text
   250 // get render size of text
   176 TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(str), @cl.Width, nil);
   251 TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(str), @cl.Width, nil);
   177 
   252 
   178 // calculate and save size
   253 // calculate and save size
   197 strSurface:= TTF_RenderUTF8_Blended(Fontz[font].Handle, Str2PChar(str), cl.color);
   272 strSurface:= TTF_RenderUTF8_Blended(Fontz[font].Handle, Str2PChar(str), cl.color);
   198 // fix format
   273 // fix format
   199 if strSurface <> nil then tmpSurface:= SDL_ConvertSurface(strSurface, resSurface^.format, 0);
   274 if strSurface <> nil then tmpSurface:= SDL_ConvertSurface(strSurface, resSurface^.format, 0);
   200 SDL_FreeSurface(strSurface);
   275 SDL_FreeSurface(strSurface);
   201 //SDL_UpperBlit(strSurface, nil, resSurface, @dstrect);
   276 //SDL_UpperBlit(strSurface, nil, resSurface, @dstrect);
   202 if tmpSurface <> nil then copyToXY(tmpSurface, resSurface, Padding, Padding);
   277 if tmpSurface <> nil then copyToXY(tmpSurface, resSurface, Padding, 2);
   203 SDL_FreeSurface(tmpSurface);
   278 SDL_FreeSurface(tmpSurface);
   204 
   279 
   205 cl.Tex:= Surface2Tex(resSurface, false);
   280 cl.Tex:= Surface2Tex(resSurface, false);
   206 
   281 
   207 SDL_FreeSurface(resSurface)
   282 SDL_FreeSurface(resSurface)
   242 
   317 
   243 // For uStore texture recreation
   318 // For uStore texture recreation
   244 procedure ReloadLines;
   319 procedure ReloadLines;
   245 var i: LongWord;
   320 var i: LongWord;
   246 begin
   321 begin
   247     if InputStr.s <> '' then
   322     // also reload empty input line (as chat size/scaling might have changed)
   248         SetLine(InputStr, InputStr.s, true);
   323     //if InputStr.s <> '' then SetLine(InputStr, InputStr.s, true); for i:= 0 to MaxStrIndex do
   249     for i:= 0 to MaxStrIndex do
   324     for i:= 0 to MaxStrIndex do
   250         if Strs[i].s <> '' then
   325         if Strs[i].s <> '' then
   251             begin
   326             begin
   252             RenderChatLineTex(Strs[i], Strs[i].s);
   327             RenderChatLineTex(Strs[i], Strs[i].s);
   253             end;
   328             end;
   291 procedure DrawChat;
   366 procedure DrawChat;
   292 var i, t, left, top, cnt: LongInt;
   367 var i, t, left, top, cnt: LongInt;
   293     selRect: TSDL_Rect;
   368     selRect: TSDL_Rect;
   294     c: char;
   369     c: char;
   295 begin
   370 begin
       
   371 AdjustToUIScale();
       
   372 
   296 ChatReady:= true; // maybe move to somewhere else?
   373 ChatReady:= true; // maybe move to somewhere else?
   297 
   374 
   298 if ChatHidden and (not showAll) then
   375 if ChatHidden and (not showAll) then
   299     visibleCount:= 0;
   376     visibleCount:= 0;
   300 
   377 
   321 
   398 
   322     if selectedPos < 0 then
   399     if selectedPos < 0 then
   323         begin
   400         begin
   324         // draw cursor
   401         // draw cursor
   325         if ((RealTicks - LastKeyPressTick) and 512) < 256 then
   402         if ((RealTicks - LastKeyPressTick) and 512) < 256 then
   326             DrawLineOnScreen(left + cursorX, top + 2, left + cursorX, top + ClHeight - 2, 2.0, $00, $FF, $FF, $FF);
   403             DrawLineOnScreen(left + cursorX, top + Padding, left + cursorX, top + ClHeight - Padding, 2.0, $00, $FF, $FF, $FF);
   327         end
   404         end
   328     else // draw selection
   405     else // draw selection
   329         begin
   406         begin
   330         selRect.y:= top + 2;
   407         selRect.y:= top + Padding;
   331         selRect.h:= clHeight - 4;
   408         selRect.h:= clHeight - 2 * Padding;
   332         if selectionDx < 0 then
   409         if selectionDx < 0 then
   333             begin
   410             begin
   334             selRect.x:= left + cursorX + selectionDx;
   411             selRect.x:= left + cursorX + selectionDx;
   335             selRect.w:= -selectionDx;
   412             selRect.w:= -selectionDx;
   336             end
   413             end
   970         SDL_SCANCODE_PAGEUP, SDL_SCANCODE_PAGEDOWN:
  1047         SDL_SCANCODE_PAGEUP, SDL_SCANCODE_PAGEDOWN:
   971             begin
  1048             begin
   972             // ignore me!!!
  1049             // ignore me!!!
   973             end;
  1050             end;
   974         // TODO: figure out how to determine those keys better
  1051         // TODO: figure out how to determine those keys better
   975         SDL_SCANCODE_a:
  1052         SDL_SCANCODE_b:
   976             begin
  1053             begin
   977             // select all
  1054             // select all
   978             if ctrlonly then
  1055             if ctrlonly then
   979                 begin
  1056                 begin
   980                 ResetSelection();
  1057                 ResetSelection();
  1006                 begin
  1083                 begin
  1007                 CopySelectionToClipboard();
  1084                 CopySelectionToClipboard();
  1008                 DeleteSelected();
  1085                 DeleteSelected();
  1009                 end
  1086                 end
  1010             end;
  1087             end;
       
  1088             // make chat bigger
       
  1089         SDL_SCANCODE_KP_PLUS, SDL_SCANCODE_EQUALS:
       
  1090             begin
       
  1091             if ctrl then
       
  1092                 begin
       
  1093                 ChatSizeInc();
       
  1094                 SkipNextInput:= true;
       
  1095                 end;
       
  1096             end;
       
  1097             // make chat smaller
       
  1098         SDL_SCANCODE_KP_MINUS, SDL_SCANCODE_MINUS:
       
  1099             begin
       
  1100             if ctrl then
       
  1101                 begin
       
  1102                 ChatSizeDec();
       
  1103                 SkipNextInput:= true;
       
  1104                 end;
       
  1105             end;
       
  1106             // revert chat size to default
       
  1107         SDL_SCANCODE_KP_0, SDL_SCANCODE_0:
       
  1108             begin
       
  1109             if ctrl then
       
  1110                 begin
       
  1111                 ChatSizeReset();
       
  1112                 SkipNextInput:= true;
       
  1113                 end;
       
  1114             end;
  1011         end;
  1115         end;
  1012 end;
  1116 end;
  1013 
  1117 
  1014 procedure TextInput(var event: TSDL_TextInputEvent);
  1118 procedure TextInput(var event: TSDL_TextInputEvent);
  1015 var s: shortstring;
  1119 var s: shortstring;
  1016     l: byte;
  1120     l: byte;
  1017     isl: integer;
  1121     isl: integer;
  1018 begin
  1122 begin
       
  1123     if SkipNextInput then
       
  1124         begin
       
  1125         SkipNextInput:= false;
       
  1126         exit;
       
  1127         end;
       
  1128 
  1019     DeleteSelected();
  1129     DeleteSelected();
  1020 
  1130 
       
  1131     s:= '';
  1021     l:= 0;
  1132     l:= 0;
  1022     // fetch all bytes of character/input
  1133     // fetch all bytes of character/input
  1023     while event.text[l] <> #0 do
  1134     while event.text[l] <> #0 do
  1024         begin
  1135         begin
  1025         s[l + 1]:= event.text[l];
  1136         if Length(s) < 255 then
  1026         inc(l)
  1137             begin
  1027         end;
  1138             s[l + 1]:= event.text[l];
  1028 
  1139             inc(l)
       
  1140             end
       
  1141         end;
  1029     if l > 0 then
  1142     if l > 0 then
  1030         begin
  1143         begin
  1031         isl:= Length(InputStr.s);
  1144         isl:= Length(InputStr.s);
  1032         // check if user is typing a redundant closing hog-speech quotation mark
  1145         // check if user is typing a redundant closing hog-speech quotation mark
  1033         if (l = 1) and (isl >= 2) and (cursorPos = isl - 1) and charIsForHogSpeech(s[1])
  1146         if (l = 1) and (isl >= 2) and (cursorPos = isl - 1) and charIsForHogSpeech(s[1])
  1139     missedCount:= 0;
  1252     missedCount:= 0;
  1140     liveLua:= false;
  1253     liveLua:= false;
  1141     ChatHidden:= false;
  1254     ChatHidden:= false;
  1142     firstDraw:= true;
  1255     firstDraw:= true;
  1143 
  1256 
       
  1257     LastChatScaleValue:= 0;
       
  1258     LastUIScaleValue:= 0;
       
  1259     SkipNextInput:= true;
       
  1260 
  1144     InputLinePrefix.Tex:= nil;
  1261     InputLinePrefix.Tex:= nil;
  1145     UpdateInputLinePrefix();
  1262     UpdateInputLinePrefix();
  1146     inputStr.s:= '';
  1263     inputStr.s:= '';
  1147     inputStr.Tex := nil;
  1264     inputStr.Tex := nil;
  1148     for i:= 0 to MaxStrIndex do
  1265     for i:= 0 to MaxStrIndex do