xref: /reactos/base/setup/usetup/genlist.c (revision aad80191)
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 */
540