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 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/genlist.c
23 * PURPOSE: Generic list functions
24 * PROGRAMMER: Christoph von Wittich <christoph at reactos.org>
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "usetup.h"
30
31 #define NDEBUG
32 #include <debug.h>
33
34 /* FUNCTIONS ****************************************************************/
35
36 VOID
InitGenericListUi(IN OUT PGENERIC_LIST_UI ListUi,IN PGENERIC_LIST List,IN PGET_ENTRY_DESCRIPTION GetEntryDescriptionProc)37 InitGenericListUi(
38 IN OUT PGENERIC_LIST_UI ListUi,
39 IN PGENERIC_LIST List,
40 IN PGET_ENTRY_DESCRIPTION GetEntryDescriptionProc)
41 {
42 ListUi->List = List;
43 ListUi->FirstShown = NULL;
44 ListUi->LastShown = NULL;
45 ListUi->BackupEntry = NULL;
46
47 ListUi->GetEntryDescriptionProc = GetEntryDescriptionProc;
48
49 ListUi->Left = 0;
50 ListUi->Top = 0;
51 ListUi->Right = 0;
52 ListUi->Bottom = 0;
53 ListUi->Redraw = TRUE;
54
55 ListUi->CurrentItemText[0] = ANSI_NULL;
56
57 /* SaveGenericListUiState(ListUi); */
58 ListUi->BackupEntry = ListUi->List->CurrentEntry;
59 }
60
61 VOID
RestoreGenericListUiState(IN PGENERIC_LIST_UI ListUi)62 RestoreGenericListUiState(
63 IN PGENERIC_LIST_UI ListUi)
64 {
65 ListUi->List->CurrentEntry = ListUi->BackupEntry;
66 }
67
68 static
69 VOID
DrawListFrame(IN PGENERIC_LIST_UI ListUi)70 DrawListFrame(
71 IN PGENERIC_LIST_UI ListUi)
72 {
73 COORD coPos;
74 DWORD Written;
75 SHORT i;
76
77 /* Draw upper left corner */
78 coPos.X = ListUi->Left;
79 coPos.Y = ListUi->Top;
80 FillConsoleOutputCharacterA(StdOutput,
81 CharUpperLeftCorner, // '+',
82 1,
83 coPos,
84 &Written);
85
86 /* Draw upper edge */
87 coPos.X = ListUi->Left + 1;
88 coPos.Y = ListUi->Top;
89 FillConsoleOutputCharacterA(StdOutput,
90 CharHorizontalLine, // '-',
91 ListUi->Right - ListUi->Left - 1,
92 coPos,
93 &Written);
94
95 /* Draw upper right corner */
96 coPos.X = ListUi->Right;
97 coPos.Y = ListUi->Top;
98 FillConsoleOutputCharacterA(StdOutput,
99 CharUpperRightCorner, // '+',
100 1,
101 coPos,
102 &Written);
103
104 /* Draw left and right edge */
105 for (i = ListUi->Top + 1; i < ListUi->Bottom; i++)
106 {
107 coPos.X = ListUi->Left;
108 coPos.Y = i;
109 FillConsoleOutputCharacterA(StdOutput,
110 CharVerticalLine, // '|',
111 1,
112 coPos,
113 &Written);
114
115 coPos.X = ListUi->Right;
116 FillConsoleOutputCharacterA(StdOutput,
117 CharVerticalLine, //'|',
118 1,
119 coPos,
120 &Written);
121 }
122
123 /* Draw lower left corner */
124 coPos.X = ListUi->Left;
125 coPos.Y = ListUi->Bottom;
126 FillConsoleOutputCharacterA(StdOutput,
127 CharLowerLeftCorner, // '+',
128 1,
129 coPos,
130 &Written);
131
132 /* Draw lower edge */
133 coPos.X = ListUi->Left + 1;
134 coPos.Y = ListUi->Bottom;
135 FillConsoleOutputCharacterA(StdOutput,
136 CharHorizontalLine, // '-',
137 ListUi->Right - ListUi->Left - 1,
138 coPos,
139 &Written);
140
141 /* Draw lower right corner */
142 coPos.X = ListUi->Right;
143 coPos.Y = ListUi->Bottom;
144 FillConsoleOutputCharacterA(StdOutput,
145 CharLowerRightCorner, // '+',
146 1,
147 coPos,
148 &Written);
149 }
150
151 static
152 VOID
DrawListEntries(IN PGENERIC_LIST_UI ListUi)153 DrawListEntries(
154 IN PGENERIC_LIST_UI ListUi)
155 {
156 PGENERIC_LIST List = ListUi->List;
157 PGENERIC_LIST_ENTRY ListEntry;
158 PLIST_ENTRY Entry;
159 COORD coPos;
160 DWORD Written;
161 USHORT Width;
162
163 coPos.X = ListUi->Left + 1;
164 coPos.Y = ListUi->Top + 1;
165 Width = ListUi->Right - ListUi->Left - 1;
166
167 Entry = ListUi->FirstShown;
168 while (Entry != &List->ListHead)
169 {
170 ListEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
171
172 if (coPos.Y == ListUi->Bottom)
173 break;
174 ListUi->LastShown = Entry;
175
176 ListUi->CurrentItemText[0] = ANSI_NULL;
177 if (ListUi->GetEntryDescriptionProc)
178 {
179 ListUi->GetEntryDescriptionProc(ListEntry,
180 ListUi->CurrentItemText,
181 ARRAYSIZE(ListUi->CurrentItemText));
182 }
183
184 FillConsoleOutputAttribute(StdOutput,
185 (List->CurrentEntry == ListEntry) ?
186 FOREGROUND_BLUE | BACKGROUND_WHITE :
187 FOREGROUND_WHITE | BACKGROUND_BLUE,
188 Width,
189 coPos,
190 &Written);
191
192 FillConsoleOutputCharacterA(StdOutput,
193 ' ',
194 Width,
195 coPos,
196 &Written);
197
198 coPos.X++;
199 WriteConsoleOutputCharacterA(StdOutput,
200 ListUi->CurrentItemText,
201 min(strlen(ListUi->CurrentItemText), (SIZE_T)Width - 2),
202 coPos,
203 &Written);
204 coPos.X--;
205
206 coPos.Y++;
207 Entry = Entry->Flink;
208 }
209
210 while (coPos.Y < ListUi->Bottom)
211 {
212 FillConsoleOutputAttribute(StdOutput,
213 FOREGROUND_WHITE | BACKGROUND_BLUE,
214 Width,
215 coPos,
216 &Written);
217
218 FillConsoleOutputCharacterA(StdOutput,
219 ' ',
220 Width,
221 coPos,
222 &Written);
223 coPos.Y++;
224 }
225 }
226
227 static
228 VOID
DrawScrollBarGenericList(IN PGENERIC_LIST_UI ListUi)229 DrawScrollBarGenericList(
230 IN PGENERIC_LIST_UI ListUi)
231 {
232 PGENERIC_LIST List = ListUi->List;
233 COORD coPos;
234 DWORD Written;
235
236 coPos.X = ListUi->Right + 1;
237 coPos.Y = ListUi->Top;
238
239 if (ListUi->FirstShown != List->ListHead.Flink)
240 {
241 FillConsoleOutputCharacterA(StdOutput,
242 CharUpArrow,
243 1,
244 coPos,
245 &Written);
246 }
247 else
248 {
249 FillConsoleOutputCharacterA(StdOutput,
250 ' ',
251 1,
252 coPos,
253 &Written);
254 }
255
256 coPos.Y = ListUi->Bottom;
257 if (ListUi->LastShown != List->ListHead.Blink)
258 {
259 FillConsoleOutputCharacterA(StdOutput,
260 CharDownArrow,
261 1,
262 coPos,
263 &Written);
264 }
265 else
266 {
267 FillConsoleOutputCharacterA(StdOutput,
268 ' ',
269 1,
270 coPos,
271 &Written);
272 }
273 }
274
275 static
276 VOID
CenterCurrentListItem(IN PGENERIC_LIST_UI ListUi)277 CenterCurrentListItem(
278 IN PGENERIC_LIST_UI ListUi)
279 {
280 PGENERIC_LIST List = ListUi->List;
281 PLIST_ENTRY Entry;
282 ULONG MaxVisibleItems, ItemCount, i;
283
284 if ((ListUi->Top == 0 && ListUi->Bottom == 0) ||
285 IsListEmpty(&List->ListHead) ||
286 List->CurrentEntry == NULL)
287 {
288 return;
289 }
290
291 MaxVisibleItems = (ULONG)(ListUi->Bottom - ListUi->Top - 1);
292
293 /*****************************************
294 ItemCount = 0;
295 Entry = List->ListHead.Flink;
296 while (Entry != &List->ListHead)
297 {
298 ItemCount++;
299 Entry = Entry->Flink;
300 }
301 *****************************************/
302 ItemCount = List->NumOfEntries; // GetNumberOfListEntries(List);
303
304 if (ItemCount > MaxVisibleItems)
305 {
306 Entry = &List->CurrentEntry->Entry;
307 for (i = 0; i < MaxVisibleItems / 2; i++)
308 {
309 if (Entry->Blink != &List->ListHead)
310 Entry = Entry->Blink;
311 }
312
313 ListUi->FirstShown = Entry;
314
315 for (i = 0; i < MaxVisibleItems; i++)
316 {
317 if (Entry->Flink != &List->ListHead)
318 Entry = Entry->Flink;
319 }
320
321 ListUi->LastShown = Entry;
322 }
323 }
324
325 VOID
DrawGenericList(IN PGENERIC_LIST_UI ListUi,IN SHORT Left,IN SHORT Top,IN SHORT Right,IN SHORT Bottom)326 DrawGenericList(
327 IN PGENERIC_LIST_UI ListUi,
328 IN SHORT Left,
329 IN SHORT Top,
330 IN SHORT Right,
331 IN SHORT Bottom)
332 {
333 PGENERIC_LIST List = ListUi->List;
334
335 ListUi->FirstShown = List->ListHead.Flink;
336 ListUi->Left = Left;
337 ListUi->Top = Top;
338 ListUi->Right = Right;
339 ListUi->Bottom = Bottom;
340
341 DrawListFrame(ListUi);
342
343 if (IsListEmpty(&List->ListHead))
344 return;
345
346 CenterCurrentListItem(ListUi);
347
348 DrawListEntries(ListUi);
349 DrawScrollBarGenericList(ListUi);
350 }
351
352 VOID
DrawGenericListCurrentItem(IN PGENERIC_LIST List,IN PGET_ENTRY_DESCRIPTION GetEntryDescriptionProc,IN SHORT Left,IN SHORT Top)353 DrawGenericListCurrentItem(
354 IN PGENERIC_LIST List,
355 IN PGET_ENTRY_DESCRIPTION GetEntryDescriptionProc,
356 IN SHORT Left,
357 IN SHORT Top)
358 {
359 CHAR CurrentItemText[256];
360
361 if (GetEntryDescriptionProc &&
362 GetNumberOfListEntries(List) > 0)
363 {
364 GetEntryDescriptionProc(GetCurrentListEntry(List),
365 CurrentItemText,
366 ARRAYSIZE(CurrentItemText));
367 CONSOLE_SetTextXY(Left, Top, CurrentItemText);
368 }
369 else
370 {
371 CONSOLE_SetTextXY(Left, Top, "");
372 }
373 }
374
375 VOID
ScrollDownGenericList(IN PGENERIC_LIST_UI ListUi)376 ScrollDownGenericList(
377 IN PGENERIC_LIST_UI ListUi)
378 {
379 PGENERIC_LIST List = ListUi->List;
380 PLIST_ENTRY Entry;
381
382 if (List->CurrentEntry == NULL)
383 return;
384
385 if (List->CurrentEntry->Entry.Flink != &List->ListHead)
386 {
387 Entry = List->CurrentEntry->Entry.Flink;
388 if (ListUi->LastShown == &List->CurrentEntry->Entry)
389 {
390 ListUi->FirstShown = ListUi->FirstShown->Flink;
391 ListUi->LastShown = ListUi->LastShown->Flink;
392 }
393 List->CurrentEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
394
395 if (ListUi->Redraw)
396 {
397 DrawListEntries(ListUi);
398 DrawScrollBarGenericList(ListUi);
399 }
400 }
401 }
402
403 VOID
ScrollUpGenericList(IN PGENERIC_LIST_UI ListUi)404 ScrollUpGenericList(
405 IN PGENERIC_LIST_UI ListUi)
406 {
407 PGENERIC_LIST List = ListUi->List;
408 PLIST_ENTRY Entry;
409
410 if (List->CurrentEntry == NULL)
411 return;
412
413 if (List->CurrentEntry->Entry.Blink != &List->ListHead)
414 {
415 Entry = List->CurrentEntry->Entry.Blink;
416 if (ListUi->FirstShown == &List->CurrentEntry->Entry)
417 {
418 ListUi->FirstShown = ListUi->FirstShown->Blink;
419 ListUi->LastShown = ListUi->LastShown->Blink;
420 }
421 List->CurrentEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
422
423 if (ListUi->Redraw)
424 {
425 DrawListEntries(ListUi);
426 DrawScrollBarGenericList(ListUi);
427 }
428 }
429 }
430
431 VOID
ScrollPageDownGenericList(IN PGENERIC_LIST_UI ListUi)432 ScrollPageDownGenericList(
433 IN PGENERIC_LIST_UI ListUi)
434 {
435 SHORT i;
436
437 /* Suspend auto-redraw */
438 ListUi->Redraw = FALSE;
439
440 for (i = ListUi->Top + 1; i < ListUi->Bottom - 1; i++)
441 {
442 ScrollDownGenericList(ListUi);
443 }
444
445 /* Update user interface */
446 DrawListEntries(ListUi);
447 DrawScrollBarGenericList(ListUi);
448
449 /* Re enable auto-redraw */
450 ListUi->Redraw = TRUE;
451 }
452
453 VOID
ScrollPageUpGenericList(IN PGENERIC_LIST_UI ListUi)454 ScrollPageUpGenericList(
455 IN PGENERIC_LIST_UI ListUi)
456 {
457 SHORT i;
458
459 /* Suspend auto-redraw */
460 ListUi->Redraw = FALSE;
461
462 for (i = ListUi->Bottom - 1; i > ListUi->Top + 1; i--)
463 {
464 ScrollUpGenericList(ListUi);
465 }
466
467 /* Update user interface */
468 DrawListEntries(ListUi);
469 DrawScrollBarGenericList(ListUi);
470
471 /* Re enable auto-redraw */
472 ListUi->Redraw = TRUE;
473 }
474
475 VOID
ScrollToPositionGenericList(IN PGENERIC_LIST_UI ListUi,IN ULONG uIndex)476 ScrollToPositionGenericList(
477 IN PGENERIC_LIST_UI ListUi,
478 IN ULONG uIndex)
479 {
480 PGENERIC_LIST List = ListUi->List;
481 PLIST_ENTRY Entry;
482 ULONG uCount = 0;
483
484 if (List->CurrentEntry == NULL || uIndex == 0)
485 return;
486
487 do
488 {
489 if (List->CurrentEntry->Entry.Flink != &List->ListHead)
490 {
491 Entry = List->CurrentEntry->Entry.Flink;
492 if (ListUi->LastShown == &List->CurrentEntry->Entry)
493 {
494 ListUi->FirstShown = ListUi->FirstShown->Flink;
495 ListUi->LastShown = ListUi->LastShown->Flink;
496 }
497 List->CurrentEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
498 }
499 uCount++;
500 }
501 while (uIndex != uCount);
502
503 if (ListUi->Redraw)
504 {
505 DrawListEntries(ListUi);
506 DrawScrollBarGenericList(ListUi);
507 }
508 }
509
510 VOID
RedrawGenericList(IN PGENERIC_LIST_UI ListUi)511 RedrawGenericList(
512 IN PGENERIC_LIST_UI ListUi)
513 {
514 if (ListUi->List->CurrentEntry == NULL)
515 return;
516
517 if (ListUi->Redraw)
518 {
519 DrawListEntries(ListUi);
520 DrawScrollBarGenericList(ListUi);
521 }
522 }
523
524 VOID
GenericListKeyPress(IN PGENERIC_LIST_UI ListUi,IN CHAR AsciiChar)525 GenericListKeyPress(
526 IN PGENERIC_LIST_UI ListUi,
527 IN CHAR AsciiChar)
528 {
529 PGENERIC_LIST List = ListUi->List;
530 PGENERIC_LIST_ENTRY ListEntry;
531 PGENERIC_LIST_ENTRY OldListEntry;
532 BOOLEAN Flag = FALSE;
533
534 ListEntry = List->CurrentEntry;
535 OldListEntry = List->CurrentEntry;
536
537 ListUi->Redraw = FALSE;
538
539 ListUi->CurrentItemText[0] = ANSI_NULL;
540 if (ListUi->GetEntryDescriptionProc)
541 {
542 ListUi->GetEntryDescriptionProc(ListEntry,
543 ListUi->CurrentItemText,
544 ARRAYSIZE(ListUi->CurrentItemText));
545 }
546
547 if ((strlen(ListUi->CurrentItemText) > 0) && (tolower(ListUi->CurrentItemText[0]) == AsciiChar) &&
548 (List->CurrentEntry->Entry.Flink != &List->ListHead))
549 {
550 ScrollDownGenericList(ListUi);
551 ListEntry = List->CurrentEntry;
552
553 ListUi->CurrentItemText[0] = ANSI_NULL;
554 if (ListUi->GetEntryDescriptionProc)
555 {
556 ListUi->GetEntryDescriptionProc(ListEntry,
557 ListUi->CurrentItemText,
558 ARRAYSIZE(ListUi->CurrentItemText));
559 }
560
561 if ((strlen(ListUi->CurrentItemText) > 0) && (tolower(ListUi->CurrentItemText[0]) == AsciiChar))
562 goto End;
563 }
564
565 while (List->CurrentEntry->Entry.Blink != &List->ListHead)
566 ScrollUpGenericList(ListUi);
567
568 ListEntry = List->CurrentEntry;
569
570 for (;;)
571 {
572 ListUi->CurrentItemText[0] = ANSI_NULL;
573 if (ListUi->GetEntryDescriptionProc)
574 {
575 ListUi->GetEntryDescriptionProc(ListEntry,
576 ListUi->CurrentItemText,
577 ARRAYSIZE(ListUi->CurrentItemText));
578 }
579
580 if ((strlen(ListUi->CurrentItemText) > 0) && (tolower(ListUi->CurrentItemText[0]) == AsciiChar))
581 {
582 Flag = TRUE;
583 break;
584 }
585
586 if (List->CurrentEntry->Entry.Flink == &List->ListHead)
587 break;
588
589 ScrollDownGenericList(ListUi);
590 ListEntry = List->CurrentEntry;
591 }
592
593 if (!Flag)
594 {
595 while (List->CurrentEntry->Entry.Blink != &List->ListHead)
596 {
597 if (List->CurrentEntry != OldListEntry)
598 ScrollUpGenericList(ListUi);
599 else
600 break;
601 }
602 }
603
604 End:
605 DrawListEntries(ListUi);
606 DrawScrollBarGenericList(ListUi);
607
608 ListUi->Redraw = TRUE;
609 }
610
611 /* EOF */
612