1 //**************************************************************************
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
13 //** This program is free software: you can redistribute it and/or modify
14 //** it under the terms of the GNU General Public License as published by
15 //** the Free Software Foundation, version 3 of the License ONLY.
17 //** This program is distributed in the hope that it will be useful,
18 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 //** GNU General Public License for more details.
22 //** You should have received a copy of the GNU General Public License
23 //** along with this program. If not, see <http://www.gnu.org/licenses/>.
25 //**************************************************************************
31 #define MAX_ILINE_LENGTH (4096)
34 //==========================================================================
38 //==========================================================================
49 //==========================================================================
53 //==========================================================================
54 void TILine::setup () {
55 if (maxlen
< 0) maxlen
= 80;
56 else if (maxlen
== 0 || maxlen
> MAX_ILINE_LENGTH
) maxlen
= MAX_ILINE_LENGTH
;
58 data
= (char *)Z_Realloc(data
, maxlen
+16);
67 //==========================================================================
71 //==========================================================================
72 void TILine::Init () {
80 //==========================================================================
82 // TILine::SetVisChars
84 //==========================================================================
85 void TILine::SetVisChars (int vc
) {
87 if (vc
== vischars
) return;
89 ensureCursorVisible();
93 //==========================================================================
95 // TILine::ensureCursorVisible
97 //==========================================================================
98 void TILine::ensureCursorVisible () {
99 curpos
= clampval(curpos
, 0, len
);
102 visfirst
= max2(0, len
-(vischars
-1));
105 if (curpos
< visfirst
) {
107 visfirst
= max2(0, curpos
-4);
108 } else if (curpos
-visfirst
>= vischars
-1) {
109 visfirst
= curpos
-(vischars
-4);
110 if (visfirst
+vischars
> len
) visfirst
= len
-(vischars
-1);
111 if (visfirst
< 0) visfirst
= 0;
116 //==========================================================================
120 //==========================================================================
121 void TILine::AddChar (char ch
) {
122 if (ch
== '\t') ch
= ' '; // why not?
123 if ((vuint8
)ch
< ' ' || (vuint8
)ch
>= 127) return;
124 if (len
>= maxlen
) return;
130 if (curpos
< 0) curpos
= 0;
131 for (int f
= len
; f
> curpos
; --f
) data
[f
] = data
[f
-1];
133 data
[len
] = 0; // just in case
137 ensureCursorVisible();
141 //==========================================================================
145 //==========================================================================
146 void TILine::AddString (const char *s
) {
147 if (!s
|| !s
[0]) return;
148 while (*s
) AddChar(*s
++);
152 //==========================================================================
156 //==========================================================================
157 void TILine::AddString (VStr s
) {
162 //==========================================================================
166 //==========================================================================
167 void TILine::DelChar () {
168 if (len
== 0 || curpos
< 1) return;
170 for (int f
= curpos
; f
< len
; ++f
) data
[f
] = data
[f
+1];
172 ensureCursorVisible();
176 //==========================================================================
178 // TILine::RemoveChar
180 // this removes char at the current cursor position
181 // and doesn't move cursor
183 //==========================================================================
184 void TILine::RemoveChar () {
185 if (curpos
>= len
) return;
186 for (int f
= curpos
; f
< len
; ++f
) data
[f
] = data
[f
+1];
188 ensureCursorVisible();
192 //==========================================================================
196 //==========================================================================
197 void TILine::DelWord () {
198 ensureCursorVisible();
199 if (curpos
== 0) return;
200 if ((vuint8
)data
[curpos
-1] <= ' ') {
201 // delete trailing spaces
202 while (curpos
> 0 && (vuint8
)data
[curpos
-1] <= ' ') DelChar();
205 while (curpos
> 0 && (vuint8
)data
[curpos
-1] > ' ') DelChar();
210 //==========================================================================
214 //==========================================================================
215 void TILine::WordLeft () {
217 if ((vuint8
)data
[curpos
-1] <= ' ') {
219 while (curpos
> 0 && (vuint8
)data
[curpos
-1] <= ' ') --curpos
;
222 if (data
[curpos
-1] == ';') { --curpos
; return; }
224 vuint8 ch
= (vuint8
)data
[curpos
-1];
225 if (ch
<= ' ' || ch
== ';') break;
232 //==========================================================================
236 //==========================================================================
237 void TILine::WordRight () {
239 if ((vuint8
)data
[curpos
] <= ' ') {
241 while (curpos
< len
&& (vuint8
)data
[curpos
] <= ' ') ++curpos
;
244 if (data
[curpos
] == ';') { ++curpos
; return; }
245 while (curpos
< len
) {
246 vuint8 ch
= (vuint8
)data
[curpos
];
247 if (ch
<= ' ' || ch
== ';') break;
254 //==========================================================================
258 // Wrapper function for handling general keyed input.
259 // Returns true if it ate the key
261 //==========================================================================
262 bool TILine::Key (const event_t
&ev
) {
263 if (ev
.type
!= ev_keydown
) return false;
265 switch (ev
.keycode
) {
269 vuint32 flg
= ev
.modflags
&(bCtrl
|bAlt
|bShift
|bHyper
);
270 // ctrl+insert: copy to clipboard
272 GInput
->SetClipboardText(VStr(data
));
275 // shift+insert: insert from clipboard
277 VStr ntx
= GInput
->GetClipboardText();
279 bool prevWasBlank
= false;
280 for (int f
= 0; f
< ntx
.length(); ++f
) {
282 if (ch
< 0) continue;
284 if (data
[len
] != ' ' && data
[len
] != '\t') AddChar(' ');
286 prevWasBlank
= false;
290 if (!prevWasBlank
) AddChar(' ');
295 prevWasBlank
= false;
304 vuint32 flg
= ev
.modflags
&(bCtrl
|bAlt
|bShift
|bHyper
);
305 // ctrl+del: delete to the end of the line
311 ensureCursorVisible();
325 if (ev
.isCtrlDown()) WordLeft(); else --curpos
;
326 ensureCursorVisible();
331 if (ev
.isCtrlDown()) WordRight(); else ++curpos
;
332 ensureCursorVisible();
337 ensureCursorVisible();
341 ensureCursorVisible();
346 if (ev
.isCtrlDown()) {
353 // to the start of the line
355 if (ev
.isCtrlDown()) {
357 ensureCursorVisible();
362 // to the end of the line
364 if (ev
.isCtrlDown()) {
366 ensureCursorVisible();
373 if (ev
.isCtrlDown()) {
380 if (ev
.keycode
== K_BACKSPACE
) {
381 if (ev
.isCtrlDown()) DelWord(); else DelChar();
383 } else if (ev
.keycode
== K_ENTER
|| ev
.keycode
== K_PADENTER
) {
386 int ch
= GInput
->TranslateKey(ev
.keycode
);
387 if (ch
>= ' ' && ch
< 128) {
389 return true; // ate the key
393 return false; // did not eat key
397 //==========================================================================
401 //==========================================================================
402 void TILine::DrawAt (int x0
, int y0
, int clrNormal
, int clrLR
) {
403 if (!data
) return; // just in case
404 ensureCursorVisible();
405 T_SetCursorPos(x0
, y0
); // for empty input lines
406 if (len
== 0) { T_DrawCursorAt(x0
, y0
, cursorChar
, CR_DEBUG_GREEN
); return; }
407 // ensure that our temporary buffer is ok
408 if (tempsize
< vischars
+8) {
409 tempsize
= vischars
+16;
410 temp
= (char *)Z_Realloc(temp
, tempsize
);
413 if (visfirst
> 0) { T_DrawText(x0
, y0
, "<", clrLR
); x0
= T_GetCursorX(); }
414 // draw text before cursor
417 while (cpos
< curpos
) {
418 vassert(tpos
< tempsize
+4);
419 temp
[tpos
++] = data
[cpos
++];
423 T_DrawText(x0
, y0
, temp
, clrNormal
);
425 // remember cursor position
428 // draw text after cursor
430 while (cpos
< len
&& cpos
-visfirst
< vischars
) {
431 vassert(tpos
< tempsize
+4);
432 temp
[tpos
++] = data
[cpos
++];
435 if (cpos
< len
) --tpos
;
437 T_DrawText(x0
, y0
, temp
, clrNormal
);
438 // draw right "arrow"
439 if (cpos
< len
) T_DrawText(T_GetCursorX(), y0
, ">", clrLR
);
442 T_DrawCursorAt(x0
, y0
, cursorChar
, CR_DEBUG_GREEN
);