67f12edebe250dfd91b0ea658ac883d0bb1132c0
[reactos.git] / base / setup / usetup / genlist.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS text-mode setup
21 * FILE: base/setup/usetup/genlist.c
22 * PURPOSE: Generic list functions
23 * PROGRAMMER: Christoph von Wittich <christoph at reactos.org>
24 */
25
26 /* INCLUDES *****************************************************************/
27
28 #include "usetup.h"
29
30 #define NDEBUG
31 #include <debug.h>
32
33 /* FUNCTIONS ****************************************************************/
34
35 VOID
36 InitGenericListUi(
37 IN OUT PGENERIC_LIST_UI ListUi,
38 IN PGENERIC_LIST List)
39 {
40 ListUi->List = List;
41 ListUi->FirstShown = NULL;
42 ListUi->LastShown = NULL;
43
44 ListUi->Left = 0;
45 ListUi->Top = 0;
46 ListUi->Right = 0;
47 ListUi->Bottom = 0;
48 ListUi->Redraw = TRUE;
49 }
50
51 static
52 VOID
53 DrawListFrame(
54 IN PGENERIC_LIST_UI ListUi)
55 {
56 COORD coPos;
57 DWORD Written;
58 SHORT i;
59
60 /* Draw upper left corner */
61 coPos.X = ListUi->Left;
62 coPos.Y = ListUi->Top;
63 FillConsoleOutputCharacterA (StdOutput,
64 0xDA, // '+',
65 1,
66 coPos,
67 &Written);
68
69 /* Draw upper edge */
70 coPos.X = ListUi->Left + 1;
71 coPos.Y = ListUi->Top;
72 FillConsoleOutputCharacterA (StdOutput,
73 0xC4, // '-',
74 ListUi->Right - ListUi->Left - 1,
75 coPos,
76 &Written);
77
78 /* Draw upper right corner */
79 coPos.X = ListUi->Right;
80 coPos.Y = ListUi->Top;
81 FillConsoleOutputCharacterA (StdOutput,
82 0xBF, // '+',
83 1,
84 coPos,
85 &Written);
86
87 /* Draw left and right edge */
88 for (i = ListUi->Top + 1; i < ListUi->Bottom; i++)
89 {
90 coPos.X = ListUi->Left;
91 coPos.Y = i;
92 FillConsoleOutputCharacterA (StdOutput,
93 0xB3, // '|',
94 1,
95 coPos,
96 &Written);
97
98 coPos.X = ListUi->Right;
99 FillConsoleOutputCharacterA (StdOutput,
100 0xB3, //'|',
101 1,
102 coPos,
103 &Written);
104 }
105
106 /* Draw lower left corner */
107 coPos.X = ListUi->Left;
108 coPos.Y = ListUi->Bottom;
109 FillConsoleOutputCharacterA (StdOutput,
110 0xC0, // '+',
111 1,
112 coPos,
113 &Written);
114
115 /* Draw lower edge */
116 coPos.X = ListUi->Left + 1;
117 coPos.Y = ListUi->Bottom;
118 FillConsoleOutputCharacterA (StdOutput,
119 0xC4, // '-',
120 ListUi->Right - ListUi->Left - 1,
121 coPos,
122 &Written);
123
124 /* Draw lower right corner */
125 coPos.X = ListUi->Right;
126 coPos.Y = ListUi->Bottom;
127 FillConsoleOutputCharacterA (StdOutput,
128 0xD9, // '+',
129 1,
130 coPos,
131 &Written);
132 }
133
134 static
135 VOID
136 DrawListEntries(
137 IN PGENERIC_LIST_UI ListUi)
138 {
139 PGENERIC_LIST List = ListUi->List;
140 PGENERIC_LIST_ENTRY ListEntry;
141 PLIST_ENTRY Entry;
142 COORD coPos;
143 DWORD Written;
144 USHORT Width;
145
146 coPos.X = ListUi->Left + 1;
147 coPos.Y = ListUi->Top + 1;
148 Width = ListUi->Right - ListUi->Left - 1;
149
150 Entry = ListUi->FirstShown;
151 while (Entry != &List->ListHead)
152 {
153 ListEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
154
155 if (coPos.Y == ListUi->Bottom)
156 break;
157 ListUi->LastShown = Entry;
158
159 FillConsoleOutputAttribute (StdOutput,
160 (List->CurrentEntry == ListEntry) ?
161 FOREGROUND_BLUE | BACKGROUND_WHITE :
162 FOREGROUND_WHITE | BACKGROUND_BLUE,
163 Width,
164 coPos,
165 &Written);
166
167 FillConsoleOutputCharacterA (StdOutput,
168 ' ',
169 Width,
170 coPos,
171 &Written);
172
173 coPos.X++;
174 WriteConsoleOutputCharacterA (StdOutput,
175 ListEntry->Text,
176 min (strlen(ListEntry->Text), (SIZE_T)Width - 2),
177 coPos,
178 &Written);
179 coPos.X--;
180
181 coPos.Y++;
182 Entry = Entry->Flink;
183 }
184
185 while (coPos.Y < ListUi->Bottom)
186 {
187 FillConsoleOutputAttribute (StdOutput,
188 FOREGROUND_WHITE | BACKGROUND_BLUE,
189 Width,
190 coPos,
191 &Written);
192
193 FillConsoleOutputCharacterA (StdOutput,
194 ' ',
195 Width,
196 coPos,
197 &Written);
198 coPos.Y++;
199 }
200 }
201
202 static
203 VOID
204 DrawScrollBarGenericList(
205 IN PGENERIC_LIST_UI ListUi)
206 {
207 PGENERIC_LIST List = ListUi->List;
208 COORD coPos;
209 DWORD Written;
210
211 coPos.X = ListUi->Right + 1;
212 coPos.Y = ListUi->Top;
213
214 if (ListUi->FirstShown != List->ListHead.Flink)
215 {
216 FillConsoleOutputCharacterA (StdOutput,
217 '\x18',
218 1,
219 coPos,
220 &Written);
221 }
222 else
223 {
224 FillConsoleOutputCharacterA (StdOutput,
225 ' ',
226 1,
227 coPos,
228 &Written);
229 }
230
231 coPos.Y = ListUi->Bottom;
232 if (ListUi->LastShown != List->ListHead.Blink)
233 {
234 FillConsoleOutputCharacterA (StdOutput,
235 '\x19',
236 1,
237 coPos,
238 &Written);
239 }
240 else
241 {
242 FillConsoleOutputCharacterA (StdOutput,
243 ' ',
244 1,
245 coPos,
246 &Written);
247 }
248 }
249
250 static
251 VOID
252 CenterCurrentListItem(
253 IN PGENERIC_LIST_UI ListUi)
254 {
255 PGENERIC_LIST List = ListUi->List;
256 PLIST_ENTRY Entry;
257 ULONG MaxVisibleItems, ItemCount, i;
258
259 if ((ListUi->Top == 0 && ListUi->Bottom == 0) ||
260 IsListEmpty(&List->ListHead) ||
261 List->CurrentEntry == NULL)
262 {
263 return;
264 }
265
266 MaxVisibleItems = (ULONG)(ListUi->Bottom - ListUi->Top - 1);
267
268 /*****************************************
269 ItemCount = 0;
270 Entry = List->ListHead.Flink;
271 while (Entry != &List->ListHead)
272 {
273 ItemCount++;
274 Entry = Entry->Flink;
275 }
276 *****************************************/
277 ItemCount = List->NumOfEntries; // GetNumberOfListEntries(List);
278
279 if (ItemCount > MaxVisibleItems)
280 {
281 Entry = &List->CurrentEntry->Entry;
282 for (i = 0; i < MaxVisibleItems / 2; i++)
283 {
284 if (Entry->Blink != &List->ListHead)
285 Entry = Entry->Blink;
286 }
287
288 ListUi->FirstShown = Entry;
289
290 for (i = 0; i < MaxVisibleItems; i++)
291 {
292 if (Entry->Flink != &List->ListHead)
293 Entry = Entry->Flink;
294 }
295
296 ListUi->LastShown = Entry;
297 }
298 }
299
300 VOID
301 DrawGenericList(
302 IN PGENERIC_LIST_UI ListUi,
303 IN SHORT Left,
304 IN SHORT Top,
305 IN SHORT Right,
306 IN SHORT Bottom)
307 {
308 PGENERIC_LIST List = ListUi->List;
309
310 ListUi->FirstShown = List->ListHead.Flink;
311 ListUi->Left = Left;
312 ListUi->Top = Top;
313 ListUi->Right = Right;
314 ListUi->Bottom = Bottom;
315
316 DrawListFrame(ListUi);
317
318 if (IsListEmpty(&List->ListHead))
319 return;
320
321 CenterCurrentListItem(ListUi);
322
323 DrawListEntries(ListUi);
324 DrawScrollBarGenericList(ListUi);
325 }
326
327 VOID
328 ScrollDownGenericList(
329 IN PGENERIC_LIST_UI ListUi)
330 {
331 PGENERIC_LIST List = ListUi->List;
332 PLIST_ENTRY Entry;
333
334 if (List->CurrentEntry == NULL)
335 return;
336
337 if (List->CurrentEntry->Entry.Flink != &List->ListHead)
338 {
339 Entry = List->CurrentEntry->Entry.Flink;
340 if (ListUi->LastShown == &List->CurrentEntry->Entry)
341 {
342 ListUi->FirstShown = ListUi->FirstShown->Flink;
343 ListUi->LastShown = ListUi->LastShown->Flink;
344 }
345 List->CurrentEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
346
347 if (ListUi->Redraw)
348 {
349 DrawListEntries(ListUi);
350 DrawScrollBarGenericList(ListUi);
351 }
352 }
353 }
354
355 VOID
356 ScrollUpGenericList(
357 IN PGENERIC_LIST_UI ListUi)
358 {
359 PGENERIC_LIST List = ListUi->List;
360 PLIST_ENTRY Entry;
361
362 if (List->CurrentEntry == NULL)
363 return;
364
365 if (List->CurrentEntry->Entry.Blink != &List->ListHead)
366 {
367 Entry = List->CurrentEntry->Entry.Blink;
368 if (ListUi->FirstShown == &List->CurrentEntry->Entry)
369 {
370 ListUi->FirstShown = ListUi->FirstShown->Blink;
371 ListUi->LastShown = ListUi->LastShown->Blink;
372 }
373 List->CurrentEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
374
375 if (ListUi->Redraw)
376 {
377 DrawListEntries(ListUi);
378 DrawScrollBarGenericList(ListUi);
379 }
380 }
381 }
382
383 VOID
384 ScrollPageDownGenericList(
385 IN PGENERIC_LIST_UI ListUi)
386 {
387 SHORT i;
388
389 /* Suspend auto-redraw */
390 ListUi->Redraw = FALSE;
391
392 for (i = ListUi->Top + 1; i < ListUi->Bottom - 1; i++)
393 {
394 ScrollDownGenericList(ListUi);
395 }
396
397 /* Update user interface */
398 DrawListEntries(ListUi);
399 DrawScrollBarGenericList(ListUi);
400
401 /* Re enable auto-redraw */
402 ListUi->Redraw = TRUE;
403 }
404
405 VOID
406 ScrollPageUpGenericList(
407 IN PGENERIC_LIST_UI ListUi)
408 {
409 SHORT i;
410
411 /* Suspend auto-redraw */
412 ListUi->Redraw = FALSE;
413
414 for (i = ListUi->Bottom - 1; i > ListUi->Top + 1; i--)
415 {
416 ScrollUpGenericList(ListUi);
417 }
418
419 /* Update user interface */
420 DrawListEntries(ListUi);
421 DrawScrollBarGenericList(ListUi);
422
423 /* Re enable auto-redraw */
424 ListUi->Redraw = TRUE;
425 }
426
427 VOID
428 ScrollToPositionGenericList(
429 IN PGENERIC_LIST_UI ListUi,
430 IN ULONG uIndex)
431 {
432 PGENERIC_LIST List = ListUi->List;
433 PLIST_ENTRY Entry;
434 ULONG uCount = 0;
435
436 if (List->CurrentEntry == NULL || uIndex == 0)
437 return;
438
439 do
440 {
441 if (List->CurrentEntry->Entry.Flink != &List->ListHead)
442 {
443 Entry = List->CurrentEntry->Entry.Flink;
444 if (ListUi->LastShown == &List->CurrentEntry->Entry)
445 {
446 ListUi->FirstShown = ListUi->FirstShown->Flink;
447 ListUi->LastShown = ListUi->LastShown->Flink;
448 }
449 List->CurrentEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
450 }
451 uCount++;
452 }
453 while (uIndex != uCount);
454
455 if (ListUi->Redraw)
456 {
457 DrawListEntries(ListUi);
458 DrawScrollBarGenericList(ListUi);
459 }
460 }
461
462 VOID
463 RedrawGenericList(
464 IN PGENERIC_LIST_UI ListUi)
465 {
466 if (ListUi->List->CurrentEntry == NULL)
467 return;
468
469 if (ListUi->Redraw)
470 {
471 DrawListEntries(ListUi);
472 DrawScrollBarGenericList(ListUi);
473 }
474 }
475
476 VOID
477 GenericListKeyPress(
478 IN PGENERIC_LIST_UI ListUi,
479 IN CHAR AsciiChar)
480 {
481 PGENERIC_LIST List = ListUi->List;
482 PGENERIC_LIST_ENTRY ListEntry;
483 PGENERIC_LIST_ENTRY OldListEntry;
484 BOOLEAN Flag = FALSE;
485
486 ListEntry = List->CurrentEntry;
487 OldListEntry = List->CurrentEntry;
488
489 ListUi->Redraw = FALSE;
490
491 if ((strlen(ListEntry->Text) > 0) && (tolower(ListEntry->Text[0]) == AsciiChar) &&
492 (List->CurrentEntry->Entry.Flink != &List->ListHead))
493 {
494 ScrollDownGenericList(ListUi);
495 ListEntry = List->CurrentEntry;
496
497 if ((strlen(ListEntry->Text) > 0) && (tolower(ListEntry->Text[0]) == AsciiChar))
498 goto End;
499 }
500
501 while (List->CurrentEntry->Entry.Blink != &List->ListHead)
502 ScrollUpGenericList(ListUi);
503
504 ListEntry = List->CurrentEntry;
505
506 for (;;)
507 {
508 if ((strlen(ListEntry->Text) > 0) && (tolower(ListEntry->Text[0]) == AsciiChar))
509 {
510 Flag = TRUE;
511 break;
512 }
513
514 if (List->CurrentEntry->Entry.Flink == &List->ListHead)
515 break;
516
517 ScrollDownGenericList(ListUi);
518 ListEntry = List->CurrentEntry;
519 }
520
521 if (!Flag)
522 {
523 while (List->CurrentEntry->Entry.Blink != &List->ListHead)
524 {
525 if (List->CurrentEntry != OldListEntry)
526 ScrollUpGenericList(ListUi);
527 else
528 break;
529 }
530 }
531
532 End:
533 DrawListEntries(ListUi);
534 DrawScrollBarGenericList(ListUi);
535
536 ListUi->Redraw = TRUE;
537 }
538
539 /* EOF */