Rev 738 | Rev 746 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 738 | Rev 740 | ||
---|---|---|---|
1 | unit VTSCUI; |
1 | unit VTSCUI; |
2 | 2 | ||
3 | (************************************************) |
3 | (************************************************) |
4 | (* VTSCUI.PAS *) |
4 | (* VTSCUI.PAS *) |
5 | (* Author: Daniel Marschall *) |
5 | (* Author: Daniel Marschall *) |
6 | (* Revision: 2022-02-14 *) |
6 | (* Revision: 2022-02-14 *) |
7 | (* License: Apache 2.0 *) |
7 | (* License: Apache 2.0 *) |
8 | (* This file contains: *) |
8 | (* This file contains: *) |
9 | (* - ViaThinkSoft CUI (Console User Interface) *) |
9 | (* - ViaThinkSoft CUI (Console User Interface) *) |
10 | (************************************************) |
10 | (************************************************) |
11 | 11 | ||
12 | interface |
12 | interface |
13 | 13 | ||
14 | uses |
14 | uses |
15 | StrList; |
15 | StrList; |
16 | 16 | ||
17 | const |
17 | const |
18 | ScreenWidth = 80; |
18 | ScreenWidth = 80; |
19 | ScreenHeight = 25; |
19 | ScreenHeight = 25; |
20 | SINGLE_LINE_BOX_PADDING = 3; |
20 | SINGLE_LINE_BOX_PADDING = 3; |
21 | SINGLE_LINE_BOX_PADDING_INNER = 10; |
21 | SINGLE_LINE_BOX_PADDING_INNER = 10; |
22 | 22 | ||
23 | procedure DrawThinBorder(x, y, width, height: integer); |
23 | procedure DrawThinBorder(x, y, width, height: integer); |
24 | procedure DrawDoubleBorder(x, y, width, height: integer); |
24 | procedure DrawDoubleBorder(x, y, width, height: integer); |
25 | procedure DrawTextBar(str: string; line: integer); |
25 | procedure DrawTextBar(str: string; line: integer); |
26 | procedure DrawTitleBar(center, left, right: string); |
26 | procedure DrawTitleBar(center, left, right: string); |
27 | procedure DrawStatusBar(str: string); |
27 | procedure DrawStatusBar(str: string); |
28 | function DrawSelectionList(X, Y, ListWidth, ListHeight: integer; |
28 | function DrawSelectionList(X, Y, ListWidth, ListHeight: integer; |
29 | items: PStringList; allowESC: boolean; |
29 | items: PStringList; allowESC: boolean; |
30 | Title: string; borderStrength: integer): integer; |
30 | Title: string; borderStrength: integer): integer; |
31 | procedure ClearSection(x, y, width, height: integer); |
31 | procedure ClearSection(x, y, width, height: integer); |
32 | function QueryVal(var s: string; initX, initY, width, height: integer; |
32 | function QueryVal(var s: string; initX, initY, width, height: integer; |
33 | Title: string; borderStrength: integer): boolean; |
33 | Title: string; borderStrength: integer): boolean; |
34 | procedure ShowMessage(msg: string; title: string; dobeep: boolean); |
34 | procedure ShowMessage(msg: string; title: string; dobeep: boolean); |
35 | 35 | ||
36 | implementation |
36 | implementation |
37 | 37 | ||
38 | uses |
38 | uses |
39 | Crt, Drivers, VtsFuncs; |
39 | Crt, Drivers, VtsFuncs; |
40 | 40 | ||
41 | type |
41 | type |
42 | TCharDefs = array[0..7] of char; |
42 | TCharDefs = array[0..7] of char; |
43 | 43 | ||
44 | const |
44 | const |
45 | ThinLineChars: TCharDefs = |
45 | ThinLineChars: TCharDefs = |
46 | ( #$DA, #$C4, #$BF, |
46 | ( #$DA, #$C4, #$BF, |
47 | #$B3, #$B3, |
47 | #$B3, #$B3, |
48 | #$C0, #$C4, #$D9 |
48 | #$C0, #$C4, #$D9 |
49 | ); |
49 | ); |
50 | DoubleLineChars: TCharDefs = |
50 | DoubleLineChars: TCharDefs = |
51 | ( #$C9, #$CD, #$BB, |
51 | ( #$C9, #$CD, #$BB, |
52 | #$BA, #$BA, |
52 | #$BA, #$BA, |
53 | #$C8, #$CD, #$BC |
53 | #$C8, #$CD, #$BC |
54 | ); |
54 | ); |
55 | 55 | ||
56 | function FillRight(str: string; len: integer; c: char): string; |
56 | function FillRight(str: string; len: integer; c: char): string; |
57 | var |
57 | var |
58 | s: string; |
58 | s: string; |
59 | i: integer; |
59 | i: integer; |
60 | begin |
60 | begin |
61 | s := str; |
61 | s := str; |
62 | for i := Length(str) to len-1 do |
62 | for i := Length(str) to len-1 do |
63 | begin |
63 | begin |
64 | s := s + c; |
64 | s := s + c; |
65 | end; |
65 | end; |
66 | FillRight := s; |
66 | FillRight := s; |
67 | end; |
67 | end; |
68 | 68 | ||
69 | procedure DrawBorder(x, y, width, height, thickness: integer); |
69 | procedure DrawBorder(x, y, width, height, thickness: integer); |
70 | var |
70 | var |
71 | ix,iy: integer; |
71 | ix,iy: integer; |
72 | chars: TCharDefs; |
72 | chars: TCharDefs; |
73 | begin |
73 | begin |
74 | if thickness = 1 then |
74 | if thickness = 1 then |
75 | chars := ThinLineChars; |
75 | chars := ThinLineChars; |
76 | if thickness = 2 then |
76 | if thickness = 2 then |
77 | chars := DoubleLineChars; |
77 | chars := DoubleLineChars; |
78 | 78 | ||
79 | (* Top line *) |
79 | (* Top line *) |
80 | if y >= 1 then |
80 | if y >= 1 then |
81 | begin |
81 | begin |
82 | (* Top left corner *) |
82 | (* Top left corner *) |
83 | if x >= 1 then |
83 | if x >= 1 then |
84 | begin |
84 | begin |
85 | GotoXY(x,y); |
85 | GotoXY(x,y); |
86 | Write(chars[0]); |
86 | Write(chars[0]); |
87 | end |
87 | end |
88 | else |
88 | else |
89 | begin |
89 | begin |
90 | GotoXY(1,y); |
90 | GotoXY(1,y); |
91 | end; |
91 | end; |
92 | 92 | ||
93 | (* Top edge *) |
93 | (* Top edge *) |
94 | for ix := 1 to width-2 do |
94 | for ix := 1 to width-2 do |
95 | Write(chars[1]); |
95 | Write(chars[1]); |
96 | 96 | ||
97 | (* Top right corner *) |
97 | (* Top right corner *) |
98 | if x+width-1 <= ScreenWidth then |
98 | if x+width-1 <= ScreenWidth then |
99 | Write(chars[2]); |
99 | Write(chars[2]); |
100 | end; |
100 | end; |
101 | 101 | ||
102 | (* Left edge *) |
102 | (* Left edge *) |
103 | for iy := 1 to height-2 do |
103 | for iy := 1 to height-2 do |
104 | begin |
104 | begin |
105 | if (x >= 1) and (x <= ScreenWidth) and |
105 | if (x >= 1) and (x <= ScreenWidth) and |
106 | (y+iy >= 1) and (y+iy <= ScreenHeight) then |
106 | (y+iy >= 1) and (y+iy <= ScreenHeight) then |
107 | begin |
107 | begin |
108 | GotoXY(x,y+iy); |
108 | GotoXY(x,y+iy); |
109 | Write(chars[3]); |
109 | Write(chars[3]); |
110 | end; |
110 | end; |
111 | end; |
111 | end; |
112 | 112 | ||
113 | (* Right edge *) |
113 | (* Right edge *) |
114 | for iy := 1 to height-2 do |
114 | for iy := 1 to height-2 do |
115 | begin |
115 | begin |
116 | if (x+width-1 >= 1) and (x+width-1 <= ScreenWidth) and |
116 | if (x+width-1 >= 1) and (x+width-1 <= ScreenWidth) and |
117 | (y+iy >= 1) and (y+iy <= ScreenHeight) then |
117 | (y+iy >= 1) and (y+iy <= ScreenHeight) then |
118 | begin |
118 | begin |
119 | GotoXY(x+width-1,y+iy); |
119 | GotoXY(x+width-1,y+iy); |
120 | Write(chars[4]); |
120 | Write(chars[4]); |
121 | end; |
121 | end; |
122 | end; |
122 | end; |
123 | 123 | ||
124 | (* Bottom line *) |
124 | (* Bottom line *) |
125 | if y+height-1 <= ScreenHeight then |
125 | if y+height-1 <= ScreenHeight then |
126 | begin |
126 | begin |
127 | (* Bottom left corner *) |
127 | (* Bottom left corner *) |
128 | if x >= 1 then |
128 | if x >= 1 then |
129 | begin |
129 | begin |
130 | GotoXY(x,y+height-1); |
130 | GotoXY(x,y+height-1); |
131 | Write(chars[5]); |
131 | Write(chars[5]); |
132 | end |
132 | end |
133 | else |
133 | else |
134 | begin |
134 | begin |
135 | GotoXY(1,y+height-1); |
135 | GotoXY(1,y+height-1); |
136 | end; |
136 | end; |
137 | 137 | ||
138 | (* Bottom edge *) |
138 | (* Bottom edge *) |
139 | for ix := 1 to width-2 do |
139 | for ix := 1 to width-2 do |
140 | Write(chars[6]); |
140 | Write(chars[6]); |
141 | 141 | ||
142 | (* Bottom right corner *) |
142 | (* Bottom right corner *) |
143 | if x+width-1 <= ScreenWidth then |
143 | if x+width-1 <= ScreenWidth then |
144 | Write(chars[7]); |
144 | Write(chars[7]); |
145 | end; |
145 | end; |
146 | end; |
146 | end; |
147 | 147 | ||
148 | procedure DrawThinBorder(x, y, width, height: integer); |
148 | procedure DrawThinBorder(x, y, width, height: integer); |
149 | begin |
149 | begin |
150 | DrawBorder(x, y, width, height, 1); |
150 | DrawBorder(x, y, width, height, 1); |
151 | end; |
151 | end; |
152 | 152 | ||
153 | procedure DrawDoubleBorder(x, y, width, height: integer); |
153 | procedure DrawDoubleBorder(x, y, width, height: integer); |
154 | begin |
154 | begin |
155 | DrawBorder(x, y, width, height, 2); |
155 | DrawBorder(x, y, width, height, 2); |
156 | end; |
156 | end; |
157 | 157 | ||
158 | procedure DrawTextBar(str: string; line: integer); |
158 | procedure DrawTextBar(str: string; line: integer); |
159 | var |
159 | var |
160 | i, left, right: integer; |
160 | i, left, right: integer; |
161 | len: integer; |
161 | len: integer; |
162 | begin |
162 | begin |
163 | GotoXY(1,line); |
163 | GotoXY(1,line); |
164 | 164 | ||
165 | TextBackground(White); |
165 | TextBackground(White); |
166 | TextColor(Black); |
166 | TextColor(Black); |
167 | len := Length(str); |
167 | len := Length(str); |
168 | 168 | ||
169 | left := round((ScreenWidth-len)/2); |
169 | left := round((ScreenWidth-len)/2); |
170 | right := ScreenWidth - left - len; |
170 | right := ScreenWidth - left - len; |
171 | 171 | ||
172 | for i := 1 to left do |
172 | for i := 1 to left do |
173 | begin |
173 | begin |
174 | Write(' '); |
174 | Write(' '); |
175 | end; |
175 | end; |
176 | 176 | ||
177 | Write(str); |
177 | Write(str); |
178 | 178 | ||
179 | (* TODO: If we do "for i := 1 to right", then the console will scroll *) |
179 | (* TODO: If we do "for i := 1 to right", then the console will scroll *) |
180 | (* since the char in the right bottom corner is written! *) |
180 | (* since the char in the right bottom corner is written! *) |
181 | for i := 1 to right-1 do |
181 | for i := 1 to right-1 do |
182 | begin |
182 | begin |
183 | Write(' '); |
183 | Write(' '); |
184 | end; |
184 | end; |
185 | 185 | ||
186 | TextBackground(Black); |
186 | TextBackground(Black); |
187 | TextColor(White); |
187 | TextColor(White); |
188 | end; |
188 | end; |
189 | 189 | ||
190 | procedure DrawTitleBar(center, left, right: string); |
190 | procedure DrawTitleBar(center, left, right: string); |
191 | begin |
191 | begin |
192 | DrawTextBar(center, 1); |
192 | DrawTextBar(center, 1); |
193 | 193 | ||
194 | (* Put left text into the title bar *) |
194 | (* Put left text into the title bar *) |
195 | GoToXY(1,1); |
195 | GoToXY(1,1); |
196 | TextBackground(White); |
196 | TextBackground(White); |
197 | TextColor(Black); |
197 | TextColor(Black); |
198 | WriteLn(left); |
198 | WriteLn(left); |
199 | TextBackground(Black); |
199 | TextBackground(Black); |
200 | TextColor(White); |
200 | TextColor(White); |
201 | 201 | ||
202 | (* Put right text into the title bar *) |
202 | (* Put right text into the title bar *) |
203 | GotoXY(ScreenWidth-Length(right)+1,1); |
203 | GotoXY(ScreenWidth-Length(right)+1,1); |
204 | TextBackground(White); |
204 | TextBackground(White); |
205 | TextColor(Black); |
205 | TextColor(Black); |
206 | WriteLn(right); |
206 | WriteLn(right); |
207 | TextBackground(Black); |
207 | TextBackground(Black); |
208 | TextColor(White); |
208 | TextColor(White); |
209 | end; |
209 | end; |
210 | 210 | ||
211 | procedure DrawStatusBar(str: string); |
211 | procedure DrawStatusBar(str: string); |
212 | begin |
212 | begin |
213 | DrawTextBar(str, ScreenHeight); |
213 | DrawTextBar(str, ScreenHeight); |
214 | end; |
214 | end; |
215 | 215 | ||
216 | function DrawSelectionList(X, Y, ListWidth, ListHeight: integer; |
216 | function DrawSelectionList(X, Y, ListWidth, ListHeight: integer; |
217 | items: PStringList; allowESC: boolean; |
217 | items: PStringList; allowESC: boolean; |
218 | Title: string; borderStrength: integer): integer; |
218 | Title: string; borderStrength: integer): integer; |
219 | var |
219 | var |
220 | i: integer; |
220 | i: integer; |
221 | itemIndex: integer; |
221 | itemIndex: integer; |
222 | sc: char; |
222 | sc: char; |
223 | iStartScope, iEndScope: integer; |
223 | iStartScope, iEndScope: integer; |
224 | sTmp: string; |
224 | sTmp: string; |
225 | label |
225 | label |
226 | doAgain; |
226 | doAgain; |
227 | begin |
227 | begin |
228 | if borderStrength = 1 then |
228 | if borderStrength = 1 then |
229 | begin |
229 | begin |
230 | DrawThinBorder(X-1, Y-1, ListWidth+2, ListHeight+2); |
230 | DrawThinBorder(X-1, Y-1, ListWidth+2, ListHeight+2); |
231 | end; |
231 | end; |
232 | 232 | ||
233 | if borderStrength = 2 then |
233 | if borderStrength = 2 then |
234 | begin |
234 | begin |
235 | DrawDoubleBorder(X-1, Y-1, ListWidth+2, ListHeight+2); |
235 | DrawDoubleBorder(X-1, Y-1, ListWidth+2, ListHeight+2); |
236 | end; |
236 | end; |
237 | 237 | ||
238 | if Title <> '' then |
238 | if Title <> '' then |
239 | begin |
239 | begin |
240 | if borderStrength > 0 then |
240 | if borderStrength > 0 then |
241 | GoToXY(X+1, Y-1) |
241 | GoToXY(X+1, Y-1) |
242 | else |
242 | else |
243 | GoToXY(X, Y-1); |
243 | GoToXY(X, Y-1); |
244 | Write(Title); |
244 | Write(Title); |
245 | end; |
245 | end; |
246 | 246 | ||
247 | (*CursorOff;*) |
247 | (*CursorOff;*) |
248 | 248 | ||
249 | itemIndex := 0; |
249 | itemIndex := 0; |
250 | iStartScope := itemIndex; |
250 | iStartScope := itemIndex; |
251 | iEndScope := itemIndex + ListHeight; |
251 | iEndScope := itemIndex + ListHeight; |
252 | 252 | ||
253 | doAgain: |
253 | doAgain: |
254 | 254 | ||
255 | if itemIndex < 0 then |
255 | if itemIndex < 0 then |
256 | itemIndex := 0; |
256 | itemIndex := 0; |
257 | if itemIndex > ListCount(items)-1 then |
257 | if itemIndex > ListCount(items)-1 then |
258 | itemIndex := ListCount(items)-1; |
258 | itemIndex := ListCount(items)-1; |
259 | 259 | ||
260 | if itemIndex < iStartScope then |
260 | if itemIndex < iStartScope then |
261 | begin |
261 | begin |
262 | Dec(iEndScope); |
262 | Dec(iEndScope); |
263 | Dec(iStartScope); |
263 | Dec(iStartScope); |
264 | end; |
264 | end; |
265 | 265 | ||
266 | if itemIndex > iEndScope-1 then |
266 | if itemIndex > iEndScope-1 then |
267 | begin |
267 | begin |
268 | Inc(iEndScope); |
268 | Inc(iEndScope); |
269 | Inc(iStartScope); |
269 | Inc(iStartScope); |
270 | end; |
270 | end; |
271 | 271 | ||
272 | if borderStrength > 0 then |
272 | if borderStrength > 0 then |
273 | begin |
273 | begin |
274 | (* Show scroll arrows *) |
274 | (* Show scroll arrows *) |
275 | GotoXY(X+ListWidth, Y); |
275 | GotoXY(X+ListWidth, Y); |
276 | if iStartScope > 0 then |
276 | if iStartScope > 0 then |
277 | begin |
277 | begin |
278 | TextBackground(White); |
278 | TextBackground(White); |
279 | TextColor(Black); |
279 | TextColor(Black); |
280 | WriteLn(#$18(*ArrowUp*)); |
280 | WriteLn(#$18(*ArrowUp*)); |
281 | TextBackground(Black); |
281 | TextBackground(Black); |
282 | TextColor(White); |
282 | TextColor(White); |
283 | end |
283 | end |
284 | else if borderStrength = 1 then |
284 | else if borderStrength = 1 then |
285 | WriteLn(ThinLineChars[4]) |
285 | WriteLn(ThinLineChars[4]) |
286 | else if borderStrength = 2 then |
286 | else if borderStrength = 2 then |
287 | WriteLn(DoubleLineChars[4]); |
287 | WriteLn(DoubleLineChars[4]); |
288 | 288 | ||
289 | GotoXY(X+ListWidth, Y+ListHeight-1); |
289 | GotoXY(X+ListWidth, Y+ListHeight-1); |
290 | if ListCount(items) > iEndScope then |
290 | if ListCount(items) > iEndScope then |
291 | begin |
291 | begin |
292 | TextBackground(White); |
292 | TextBackground(White); |
293 | TextColor(Black); |
293 | TextColor(Black); |
294 | WriteLn(#$19(*ArrowDown*)); |
294 | WriteLn(#$19(*ArrowDown*)); |
295 | TextBackground(Black); |
295 | TextBackground(Black); |
296 | TextColor(White); |
296 | TextColor(White); |
297 | end |
297 | end |
298 | else if borderStrength = 1 then |
298 | else if borderStrength = 1 then |
299 | WriteLn(ThinLineChars[4]) |
299 | WriteLn(ThinLineChars[4]) |
300 | else if borderStrength = 2 then |
300 | else if borderStrength = 2 then |
301 | WriteLn(DoubleLineChars[4]); |
301 | WriteLn(DoubleLineChars[4]); |
302 | end; |
302 | end; |
303 | 303 | ||
304 | for i := iStartScope to iEndScope-1 do |
304 | for i := iStartScope to iEndScope-1 do |
305 | begin |
305 | begin |
306 | if itemIndex = i then |
306 | if itemIndex = i then |
307 | begin |
307 | begin |
308 | TextColor(Black); |
308 | TextColor(Black); |
309 | TextBackground(White); |
309 | TextBackground(White); |
310 | end |
310 | end |
311 | else |
311 | else |
312 | begin |
312 | begin |
313 | TextColor(White); |
313 | TextColor(White); |
314 | TextBackground(Black); |
314 | TextBackground(Black); |
315 | end; |
315 | end; |
316 | GotoXY(x,y+i-iStartScope); |
316 | GotoXY(x,y+i-iStartScope); |
317 | if i > ListCount(items)-1 then |
317 | if i > ListCount(items)-1 then |
318 | Write(FillRight('', ListWidth, ' ')) |
318 | Write(FillRight('', ListWidth, ' ')) |
319 | else |
319 | else |
320 | begin |
320 | begin |
321 | sTmp := ListGetElement(items, i); |
321 | sTmp := ListGetElement(items, i); |
322 | if Length(sTmp) > ListWidth then |
- | |
323 | begin |
- | |
324 | (* Cut too long line *) |
- | |
325 | sTmp := Copy(sTmp, 1, ListWidth-3) + '...'; |
322 | sTmp := TrimLineToWidth(sTmp, ListWidth); |
326 | end; |
- | |
327 | Write(FillRight(sTmp, ListWidth, ' ')); |
323 | Write(FillRight(sTmp, ListWidth, ' ')); |
328 | end; |
324 | end; |
329 | TextColor(White); |
325 | TextColor(White); |
330 | TextBackground(Black); |
326 | TextBackground(Black); |
331 | end; |
327 | end; |
332 | 328 | ||
333 | repeat |
329 | repeat |
334 | GotoXY(ScreenWidth, ScreenHeight); |
330 | GotoXY(ScreenWidth, ScreenHeight); |
335 | 331 | ||
336 | sc := ReadKey; |
332 | sc := ReadKey; |
337 | if sc = #$00(*ExtendedKeyCode*) then |
333 | if sc = #$00(*ExtendedKeyCode*) then |
338 | begin |
334 | begin |
339 | sc := ReadKey; |
335 | sc := ReadKey; |
340 | if sc = #$48(*UpKey*) then |
336 | if sc = #$48(*UpKey*) then |
341 | begin |
337 | begin |
342 | dec(itemIndex); |
338 | dec(itemIndex); |
343 | goto doAgain; |
339 | goto doAgain; |
344 | end |
340 | end |
345 | else if sc = #$50(*DownKey*) then |
341 | else if sc = #$50(*DownKey*) then |
346 | begin |
342 | begin |
347 | inc(itemIndex); |
343 | inc(itemIndex); |
348 | goto doAgain; |
344 | goto doAgain; |
349 | end |
345 | end |
350 | else if sc = #$47(*POS1*) then |
346 | else if sc = #$47(*POS1*) then |
351 | begin |
347 | begin |
352 | itemIndex := 0; |
348 | itemIndex := 0; |
- | 349 | iStartScope := 0; |
|
- | 350 | iEndScope := iStartScope + ListHeight; |
|
353 | goto doAgain; |
351 | goto doAgain; |
354 | end |
352 | end |
355 | else if sc = #$4F(*END*) then |
353 | else if sc = #$4F(*END*) then |
356 | begin |
354 | begin |
357 | itemIndex := ListCount(items); |
355 | itemIndex := ListCount(items)-1; |
- | 356 | iStartScope := itemIndex - Min(ListHeight,ListCount(items)); |
|
- | 357 | iEndScope := itemIndex; |
|
358 | goto doAgain; |
358 | goto doAgain; |
359 | end; |
359 | end; |
360 | end; |
360 | end; |
361 | 361 | ||
362 | if sc = #13(*Return*) then |
362 | if sc = #13(*Return*) then |
363 | begin |
363 | begin |
364 | DrawSelectionList := itemIndex; |
364 | DrawSelectionList := itemIndex; |
365 | break; |
365 | break; |
366 | end; |
366 | end; |
367 | 367 | ||
368 | if allowESC and (sc = #27(*ESC*)) then |
368 | if allowESC and (sc = #27(*ESC*)) then |
369 | begin |
369 | begin |
370 | DrawSelectionList := -1; |
370 | DrawSelectionList := -1; |
371 | break; |
371 | break; |
372 | end; |
372 | end; |
373 | until false; |
373 | until false; |
374 | 374 | ||
375 | (*CursorOn;*) |
375 | (*CursorOn;*) |
376 | end; |
376 | end; |
377 | 377 | ||
378 | procedure ClearSection(x, y, width, height: integer); |
378 | procedure ClearSection(x, y, width, height: integer); |
379 | var |
379 | var |
380 | ix, iy: integer; |
380 | ix, iy: integer; |
381 | begin |
381 | begin |
382 | for iy := y to y+height-1 do |
382 | for iy := y to y+height-1 do |
383 | begin |
383 | begin |
384 | for ix := x to x+width-1 do |
384 | for ix := x to x+width-1 do |
385 | begin |
385 | begin |
386 | GoToXY(ix,iy); |
386 | GoToXY(ix,iy); |
387 | Write(' '); |
387 | Write(' '); |
388 | end; |
388 | end; |
389 | end; |
389 | end; |
390 | end; |
390 | end; |
391 | 391 | ||
392 | function QueryVal(var s: string; initX, initY, width, height: integer; |
392 | function QueryVal(var s: string; initX, initY, width, height: integer; |
393 | Title: string; borderStrength: integer): boolean; |
393 | Title: string; borderStrength: integer): boolean; |
394 | var |
394 | var |
395 | x, y: integer; |
395 | x, y: integer; |
396 | i, j: integer; |
396 | i, j: integer; |
397 | sc: char; |
397 | sc: char; |
398 | stmp: string; |
398 | stmp: string; |
399 | begin |
399 | begin |
400 | if borderStrength = 1 then |
400 | if borderStrength = 1 then |
401 | DrawThinBorder(initX-1,initY-1,width+2,height+2); |
401 | DrawThinBorder(initX-1,initY-1,width+2,height+2); |
402 | if borderStrength = 2 then |
402 | if borderStrength = 2 then |
403 | DrawDoubleBorder(initX-1,initY-1,width+2,height+2); |
403 | DrawDoubleBorder(initX-1,initY-1,width+2,height+2); |
404 | if title <> '' then |
404 | if title <> '' then |
405 | begin |
405 | begin |
406 | if borderStrength > 0 then |
406 | if borderStrength > 0 then |
407 | GoToXY(initX+1, initY-1) |
407 | GoToXY(initX+1, initY-1) |
408 | else |
408 | else |
409 | GoToXY(initX, initY-1); |
409 | GoToXY(initX, initY-1); |
410 | Write(title); |
410 | Write(title); |
411 | end; |
411 | end; |
412 | ClearSection(initX,initY,width,height); |
412 | ClearSection(initX,initY,width,height); |
413 | 413 | ||
414 | x := initX; |
414 | x := initX; |
415 | y := initY; |
415 | y := initY; |
416 | 416 | ||
417 | (* Write existing string value and set cursor *) |
417 | (* Write existing string value and set cursor *) |
418 | stmp := s; |
418 | stmp := s; |
419 | s := ''; |
419 | s := ''; |
420 | for i := 1 to Length(stmp) do |
420 | for i := 1 to Length(stmp) do |
421 | begin |
421 | begin |
422 | if stmp[i] = #10 then |
422 | if stmp[i] = #10 then |
423 | begin |
423 | begin |
424 | s := s + stmp[i]; |
424 | s := s + stmp[i]; |
425 | continue; |
425 | continue; |
426 | end; |
426 | end; |
427 | 427 | ||
428 | GoToXY(x,y); |
428 | GoToXY(x,y); |
429 | s := s + stmp[i]; |
429 | s := s + stmp[i]; |
430 | Write(stmp[i]); |
430 | Write(stmp[i]); |
431 | Inc(x); |
431 | Inc(x); |
432 | 432 | ||
433 | if (x=initX+width-1) and (y=initY+height-1) then |
433 | if (x=initX+width-1) and (y=initY+height-1) then |
434 | begin |
434 | begin |
435 | (* Attention: Data following after this will be lost! *) |
435 | (* Attention: Data following after this will be lost! *) |
436 | break; |
436 | break; |
437 | end; |
437 | end; |
438 | 438 | ||
439 | if stmp[i] = #13 then |
439 | if stmp[i] = #13 then |
440 | begin |
440 | begin |
441 | if y=initY+height-1 then |
441 | if y=initY+height-1 then |
442 | begin |
442 | begin |
443 | (* Attention: Data following after this will be lost! *) |
443 | (* Attention: Data following after this will be lost! *) |
444 | s := Copy(s, 1, Length(s)-1); |
444 | s := Copy(s, 1, Length(s)-1); |
445 | Dec(x); |
445 | Dec(x); |
446 | break; |
446 | break; |
447 | end; |
447 | end; |
448 | x := initX; |
448 | x := initX; |
449 | Inc(y); |
449 | Inc(y); |
450 | continue; |
450 | continue; |
451 | end; |
451 | end; |
452 | 452 | ||
453 | if x=initX+width then |
453 | if x=initX+width then |
454 | begin |
454 | begin |
455 | Inc(y); |
455 | Inc(y); |
456 | x := initX; |
456 | x := initX; |
457 | end; |
457 | end; |
458 | end; |
458 | end; |
459 | 459 | ||
460 | repeat |
460 | repeat |
461 | GotoXY(x, y); |
461 | GotoXY(x, y); |
462 | sc := ReadKey; |
462 | sc := ReadKey; |
463 | 463 | ||
464 | if sc = #0 then |
464 | if sc = #0 then |
465 | begin |
465 | begin |
466 | (* Extended key code *) |
466 | (* Extended key code *) |
467 | sc := ReadKey; |
467 | sc := ReadKey; |
468 | (* TODO: Implement keys like DEL, END, POS1, and ArrowKeys *) |
468 | (* TODO: Implement keys like DEL, END, POS1, and ArrowKeys *) |
469 | Beep; |
469 | Beep; |
470 | continue; |
470 | continue; |
471 | end |
471 | end |
472 | else if sc = #8(*Backspace*) then |
472 | else if sc = #8(*Backspace*) then |
473 | begin |
473 | begin |
474 | if x <= initX then |
474 | if x <= initX then |
475 | begin |
475 | begin |
476 | if y = initY then |
476 | if y = initY then |
477 | begin |
477 | begin |
478 | Beep; |
478 | Beep; |
479 | continue; |
479 | continue; |
480 | end; |
480 | end; |
481 | Dec(y); |
481 | Dec(y); |
482 | 482 | ||
483 | (* Find out length of previous line *) |
483 | (* Find out length of previous line *) |
484 | j := Length(s)-2(*CRLF*); |
484 | j := Length(s)-2(*CRLF*); |
485 | while (j >= 0) do |
485 | while (j >= 0) do |
486 | begin |
486 | begin |
487 | if (s[j]=#13) or (s[j]=#10) then break; |
487 | if (s[j]=#13) or (s[j]=#10) then break; |
488 | Dec(j); |
488 | Dec(j); |
489 | end; |
489 | end; |
490 | j := Length(s)-2(*CRLF*)-j; |
490 | j := Length(s)-2(*CRLF*)-j; |
491 | x := initX + j; |
491 | x := initX + j; |
492 | s := Copy(s, 1, Length(s)-1); (* Remove #10 now. #13 will be removed below *) |
492 | s := Copy(s, 1, Length(s)-1); (* Remove #10 now. #13 will be removed below *) |
493 | end |
493 | end |
494 | else |
494 | else |
495 | begin |
495 | begin |
496 | Dec(x); |
496 | Dec(x); |
497 | end; |
497 | end; |
498 | GotoXY(x, y); |
498 | GotoXY(x, y); |
499 | Write(' '); |
499 | Write(' '); |
500 | GotoXY(x, y); |
500 | GotoXY(x, y); |
501 | s := Copy(s, 1, Length(s)-1); |
501 | s := Copy(s, 1, Length(s)-1); |
502 | continue; |
502 | continue; |
503 | end |
503 | end |
504 | else if sc = #13(*Return*) then |
504 | else if sc = #13(*Return*) then |
505 | begin |
505 | begin |
506 | if GetShiftState and kbRightShift <> 0 then |
506 | if GetShiftState and kbRightShift <> 0 then |
507 | begin |
507 | begin |
508 | if y=initY+height-1 then |
508 | if y=initY+height-1 then |
509 | begin |
509 | begin |
510 | Beep; |
510 | Beep; |
511 | continue; |
511 | continue; |
512 | end; |
512 | end; |
513 | s := s + #13 + #10; |
513 | s := s + #13 + #10; |
514 | x := initX; |
514 | x := initX; |
515 | Inc(y); |
515 | Inc(y); |
516 | end |
516 | end |
517 | else |
517 | else |
518 | begin |
518 | begin |
519 | QueryVal := true; |
519 | QueryVal := true; |
520 | exit; |
520 | exit; |
521 | end; |
521 | end; |
522 | end |
522 | end |
523 | else if sc = #27(*ESC*) then |
523 | else if sc = #27(*ESC*) then |
524 | begin |
524 | begin |
525 | QueryVal := false; |
525 | QueryVal := false; |
526 | exit; |
526 | exit; |
527 | end |
527 | end |
528 | else |
528 | else |
529 | begin |
529 | begin |
530 | if (x=initX+width-1) and (y=initY+height-1) then |
530 | if (x=initX+width-1) and (y=initY+height-1) then |
531 | begin |
531 | begin |
532 | Beep; |
532 | Beep; |
533 | continue; |
533 | continue; |
534 | end; |
534 | end; |
535 | s := s + sc; |
535 | s := s + sc; |
536 | Write(sc); |
536 | Write(sc); |
537 | Inc(x); |
537 | Inc(x); |
538 | if x >= initX+width then |
538 | if x >= initX+width then |
539 | begin |
539 | begin |
540 | Inc(y); |
540 | Inc(y); |
541 | x := initX; |
541 | x := initX; |
542 | end; |
542 | end; |
543 | end; |
543 | end; |
544 | until false; |
544 | until false; |
545 | end; |
545 | end; |
546 | 546 | ||
547 | procedure ShowMessage(msg: string; title: string; dobeep: boolean); |
547 | procedure ShowMessage(msg: string; title: string; dobeep: boolean); |
548 | var |
548 | var |
549 | x, y, w, h: integer; |
549 | x, y, w, h: integer; |
550 | begin |
550 | begin |
551 | x := SINGLE_LINE_BOX_PADDING_INNER; |
551 | x := SINGLE_LINE_BOX_PADDING_INNER; |
552 | y := ScreenHeight div 2 - 1; |
552 | y := ScreenHeight div 2 - 1; |
553 | w := ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2; |
553 | w := ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2; |
554 | h := 1; |
554 | h := 1; |
555 | DrawDoubleBorder(x-1, y, w+2, h+2); |
555 | DrawDoubleBorder(x-1, y, w+2, h+2); |
556 | ClearSection(x, y+1, w-2, h); |
556 | ClearSection(x, y+1, w-2, h); |
557 | if title <> '' then |
557 | if title <> '' then |
558 | begin |
558 | begin |
559 | GoToXY(x+1, y); |
559 | GoToXY(x+1, y); |
560 | Write(title); |
560 | Write(title); |
561 | end; |
561 | end; |
562 | GoToXY(x, y+1); |
562 | GoToXY(x, y+1); |
563 | Write(msg); |
563 | Write(msg); |
564 | if DoBeep then Beep; |
564 | if DoBeep then Beep; |
565 | end; |
565 | end; |
566 | 566 | ||
567 | end. |
567 | end. |
568 | 568 |