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; |
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 |
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]) |