3 * Copyright (C) 2004 ReactOS Team
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.
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.
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.
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: Eric Kohl
24 * Christoph von Wittich <christoph at reactos.org>
27 /* INCLUDES *****************************************************************/
34 /* FUNCTIONS ****************************************************************/
36 typedef struct _GENERIC_LIST_ENTRY
45 typedef struct _GENERIC_LIST
49 PLIST_ENTRY FirstShown
;
50 PLIST_ENTRY LastShown
;
57 PGENERIC_LIST_ENTRY CurrentEntry
;
58 PGENERIC_LIST_ENTRY BackupEntry
;
62 CreateGenericList(VOID
)
66 List
= (PGENERIC_LIST
)RtlAllocateHeap(ProcessHeap
,
68 sizeof(GENERIC_LIST
));
72 InitializeListHead(&List
->ListHead
);
80 List
->CurrentEntry
= NULL
;
91 PGENERIC_LIST_ENTRY ListEntry
;
94 /* Release list entries */
95 while (!IsListEmpty (&List
->ListHead
))
97 Entry
= RemoveHeadList (&List
->ListHead
);
98 ListEntry
= CONTAINING_RECORD (Entry
, GENERIC_LIST_ENTRY
, Entry
);
100 /* Release user data */
101 if (FreeUserData
&& ListEntry
->UserData
!= NULL
)
102 RtlFreeHeap (ProcessHeap
, 0, ListEntry
->UserData
);
104 /* Release list entry */
105 RtlFreeHeap (ProcessHeap
, 0, ListEntry
);
108 /* Release list head */
109 RtlFreeHeap (ProcessHeap
, 0, List
);
114 AppendGenericListEntry(
120 PGENERIC_LIST_ENTRY Entry
;
122 Entry
= (PGENERIC_LIST_ENTRY
)RtlAllocateHeap(ProcessHeap
,
124 sizeof(GENERIC_LIST_ENTRY
) + strlen(Text
));
128 strcpy (Entry
->Text
, Text
);
130 Entry
->UserData
= UserData
;
132 InsertTailList(&List
->ListHead
,
135 if (Current
|| List
->CurrentEntry
== NULL
)
137 List
->CurrentEntry
= Entry
;
147 PGENERIC_LIST GenericList
)
153 /* Draw upper left corner */
154 coPos
.X
= GenericList
->Left
;
155 coPos
.Y
= GenericList
->Top
;
156 FillConsoleOutputCharacterA (StdOutput
,
162 /* Draw upper edge */
163 coPos
.X
= GenericList
->Left
+ 1;
164 coPos
.Y
= GenericList
->Top
;
165 FillConsoleOutputCharacterA (StdOutput
,
167 GenericList
->Right
- GenericList
->Left
- 1,
171 /* Draw upper right corner */
172 coPos
.X
= GenericList
->Right
;
173 coPos
.Y
= GenericList
->Top
;
174 FillConsoleOutputCharacterA (StdOutput
,
180 /* Draw left and right edge */
181 for (i
= GenericList
->Top
+ 1; i
< GenericList
->Bottom
; i
++)
183 coPos
.X
= GenericList
->Left
;
185 FillConsoleOutputCharacterA (StdOutput
,
191 coPos
.X
= GenericList
->Right
;
192 FillConsoleOutputCharacterA (StdOutput
,
199 /* Draw lower left corner */
200 coPos
.X
= GenericList
->Left
;
201 coPos
.Y
= GenericList
->Bottom
;
202 FillConsoleOutputCharacterA (StdOutput
,
208 /* Draw lower edge */
209 coPos
.X
= GenericList
->Left
+ 1;
210 coPos
.Y
= GenericList
->Bottom
;
211 FillConsoleOutputCharacterA (StdOutput
,
213 GenericList
->Right
- GenericList
->Left
- 1,
217 /* Draw lower right corner */
218 coPos
.X
= GenericList
->Right
;
219 coPos
.Y
= GenericList
->Bottom
;
220 FillConsoleOutputCharacterA (StdOutput
,
231 PGENERIC_LIST GenericList
)
233 PGENERIC_LIST_ENTRY ListEntry
;
239 coPos
.X
= GenericList
->Left
+ 1;
240 coPos
.Y
= GenericList
->Top
+ 1;
241 Width
= GenericList
->Right
- GenericList
->Left
- 1;
243 Entry
= GenericList
->FirstShown
;
244 while (Entry
!= &GenericList
->ListHead
)
246 ListEntry
= CONTAINING_RECORD (Entry
, GENERIC_LIST_ENTRY
, Entry
);
248 if (coPos
.Y
== GenericList
->Bottom
)
250 GenericList
->LastShown
= Entry
;
252 FillConsoleOutputAttribute (StdOutput
,
253 (GenericList
->CurrentEntry
== ListEntry
) ?
254 FOREGROUND_BLUE
| BACKGROUND_WHITE
:
255 FOREGROUND_WHITE
| BACKGROUND_BLUE
,
260 FillConsoleOutputCharacterA (StdOutput
,
267 WriteConsoleOutputCharacterA (StdOutput
,
269 min (strlen(ListEntry
->Text
), (SIZE_T
)Width
- 2),
275 Entry
= Entry
->Flink
;
278 while (coPos
.Y
< GenericList
->Bottom
)
280 FillConsoleOutputAttribute (StdOutput
,
281 FOREGROUND_WHITE
| BACKGROUND_BLUE
,
286 FillConsoleOutputCharacterA (StdOutput
,
298 DrawScrollBarGenericList(
299 PGENERIC_LIST GenericList
)
304 coPos
.X
= GenericList
->Right
+ 1;
305 coPos
.Y
= GenericList
->Top
;
307 if (GenericList
->FirstShown
!= GenericList
->ListHead
.Flink
)
309 FillConsoleOutputCharacterA (StdOutput
,
317 FillConsoleOutputCharacterA (StdOutput
,
324 coPos
.Y
= GenericList
->Bottom
;
325 if (GenericList
->LastShown
!= GenericList
->ListHead
.Blink
)
327 FillConsoleOutputCharacterA (StdOutput
,
335 FillConsoleOutputCharacterA (StdOutput
,
346 CenterCurrentListItem(
350 ULONG MaxVisibleItems
, ItemCount
, i
;
352 if ((List
->Top
== 0 && List
->Bottom
== 0) ||
353 IsListEmpty(&List
->ListHead
) ||
354 List
->CurrentEntry
== NULL
)
357 MaxVisibleItems
= (ULONG
)(List
->Bottom
- List
->Top
- 1);
360 Entry
= List
->ListHead
.Flink
;
361 while (Entry
!= &List
->ListHead
)
364 Entry
= Entry
->Flink
;
367 if (ItemCount
> MaxVisibleItems
)
369 Entry
= &List
->CurrentEntry
->Entry
;
370 for (i
= 0; i
< MaxVisibleItems
/ 2; i
++)
372 if (Entry
->Blink
!= &List
->ListHead
)
373 Entry
= Entry
->Blink
;
376 List
->FirstShown
= Entry
;
378 for (i
= 0; i
< MaxVisibleItems
; i
++)
380 if (Entry
->Flink
!= &List
->ListHead
)
381 Entry
= Entry
->Flink
;
384 List
->LastShown
= Entry
;
397 List
->FirstShown
= List
->ListHead
.Flink
;
401 List
->Bottom
= Bottom
;
405 if (IsListEmpty(&List
->ListHead
))
408 CenterCurrentListItem(List
);
410 DrawListEntries(List
);
411 DrawScrollBarGenericList(List
);
416 ScrollPageDownGenericList(
421 /* Suspend auto-redraw */
422 List
->Redraw
= FALSE
;
424 for (i
= List
->Top
+ 1; i
< List
->Bottom
- 1; i
++)
426 ScrollDownGenericList (List
);
429 /* Update user interface */
430 DrawListEntries(List
);
431 DrawScrollBarGenericList(List
);
433 /* Re enable auto-redraw */
439 ScrollPageUpGenericList(
444 /* Suspend auto-redraw */
445 List
->Redraw
= FALSE
;
447 for (i
= List
->Bottom
- 1; i
> List
->Top
+ 1; i
--)
449 ScrollUpGenericList (List
);
452 /* Update user interface */
453 DrawListEntries(List
);
454 DrawScrollBarGenericList(List
);
456 /* Re enable auto-redraw */
462 ScrollDownGenericList(
467 if (List
->CurrentEntry
== NULL
)
470 if (List
->CurrentEntry
->Entry
.Flink
!= &List
->ListHead
)
472 Entry
= List
->CurrentEntry
->Entry
.Flink
;
473 if (List
->LastShown
== &List
->CurrentEntry
->Entry
)
475 List
->FirstShown
= List
->FirstShown
->Flink
;
476 List
->LastShown
= List
->LastShown
->Flink
;
478 List
->CurrentEntry
= CONTAINING_RECORD (Entry
, GENERIC_LIST_ENTRY
, Entry
);
482 DrawListEntries(List
);
483 DrawScrollBarGenericList(List
);
490 ScrollToPositionGenericList(
497 if (List
->CurrentEntry
== NULL
|| uIndex
== 0)
502 if (List
->CurrentEntry
->Entry
.Flink
!= &List
->ListHead
)
504 Entry
= List
->CurrentEntry
->Entry
.Flink
;
505 if (List
->LastShown
== &List
->CurrentEntry
->Entry
)
507 List
->FirstShown
= List
->FirstShown
->Flink
;
508 List
->LastShown
= List
->LastShown
->Flink
;
510 List
->CurrentEntry
= CONTAINING_RECORD (Entry
, GENERIC_LIST_ENTRY
, Entry
);
514 while (uIndex
!= uCount
);
518 DrawListEntries(List
);
519 DrawScrollBarGenericList(List
);
530 if (List
->CurrentEntry
== NULL
)
533 if (List
->CurrentEntry
->Entry
.Blink
!= &List
->ListHead
)
535 Entry
= List
->CurrentEntry
->Entry
.Blink
;
536 if (List
->FirstShown
== &List
->CurrentEntry
->Entry
)
538 List
->FirstShown
= List
->FirstShown
->Blink
;
539 List
->LastShown
= List
->LastShown
->Blink
;
541 List
->CurrentEntry
= CONTAINING_RECORD (Entry
, GENERIC_LIST_ENTRY
, Entry
);
545 DrawListEntries(List
);
546 DrawScrollBarGenericList(List
);
556 if (List
->CurrentEntry
== NULL
)
561 DrawListEntries(List
);
562 DrawScrollBarGenericList(List
);
570 PGENERIC_LIST_ENTRY Entry
)
572 if (Entry
->List
!= List
)
574 List
->CurrentEntry
= Entry
;
582 return List
->CurrentEntry
;
590 PLIST_ENTRY Entry
= List
->ListHead
.Flink
;
592 if (Entry
== &List
->ListHead
)
594 return CONTAINING_RECORD(Entry
, GENERIC_LIST_ENTRY
, Entry
);
600 PGENERIC_LIST_ENTRY Entry
)
602 PLIST_ENTRY Next
= Entry
->Entry
.Flink
;
604 if (Next
== &Entry
->List
->ListHead
)
606 return CONTAINING_RECORD(Next
, GENERIC_LIST_ENTRY
, Entry
);
611 GetListEntryUserData(
612 PGENERIC_LIST_ENTRY List
)
614 return List
->UserData
;
620 PGENERIC_LIST_ENTRY List
)
628 PGENERIC_LIST GenericList
,
631 PGENERIC_LIST_ENTRY ListEntry
;
632 PGENERIC_LIST_ENTRY OldListEntry
;
633 BOOLEAN Flag
= FALSE
;
635 ListEntry
= GenericList
->CurrentEntry
;
636 OldListEntry
= GenericList
->CurrentEntry
;
638 GenericList
->Redraw
= FALSE
;
640 if ((strlen(ListEntry
->Text
) > 0) && (tolower(ListEntry
->Text
[0]) == AsciiChar
) &&
641 (GenericList
->CurrentEntry
->Entry
.Flink
!= &GenericList
->ListHead
))
643 ScrollDownGenericList(GenericList
);
644 ListEntry
= GenericList
->CurrentEntry
;
646 if ((strlen(ListEntry
->Text
) > 0) && (tolower(ListEntry
->Text
[0]) == AsciiChar
))
650 while (GenericList
->CurrentEntry
->Entry
.Blink
!= &GenericList
->ListHead
)
651 ScrollUpGenericList(GenericList
);
653 ListEntry
= GenericList
->CurrentEntry
;
657 if ((strlen(ListEntry
->Text
) > 0) && (tolower(ListEntry
->Text
[0]) == AsciiChar
))
663 if (GenericList
->CurrentEntry
->Entry
.Flink
== &GenericList
->ListHead
)
666 ScrollDownGenericList(GenericList
);
667 ListEntry
= GenericList
->CurrentEntry
;
672 while (GenericList
->CurrentEntry
->Entry
.Blink
!= &GenericList
->ListHead
)
674 if (GenericList
->CurrentEntry
!= OldListEntry
)
675 ScrollUpGenericList(GenericList
);
681 DrawListEntries(GenericList
);
682 DrawScrollBarGenericList(GenericList
);
684 GenericList
->Redraw
= TRUE
;
689 SaveGenericListState(
692 List
->BackupEntry
= List
->CurrentEntry
;
697 RestoreGenericListState(
700 List
->CurrentEntry
= List
->BackupEntry
;
705 GenericListHasSingleEntry(
708 if (!IsListEmpty(&List
->ListHead
) && List
->ListHead
.Flink
== List
->ListHead
.Blink
)
711 /* if both list head pointers (which normally point to the first and last list member, respectively)
712 point to the same entry then it means that there's just a single thing in there, otherwise... false! */