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 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 62 RestoreGenericListUiState( 63 IN PGENERIC_LIST_UI ListUi) 64 { 65 ListUi->List->CurrentEntry = ListUi->BackupEntry; 66 } 67 68 static 69 VOID 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 0xDA, // '+', 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 0xC4, // '-', 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 0xBF, // '+', 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 0xB3, // '|', 111 1, 112 coPos, 113 &Written); 114 115 coPos.X = ListUi->Right; 116 FillConsoleOutputCharacterA(StdOutput, 117 0xB3, //'|', 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 0xC0, // '+', 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 0xC4, // '-', 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 0xD9, // '+', 146 1, 147 coPos, 148 &Written); 149 } 150 151 static 152 VOID 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 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 '\x18', 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 '\x19', 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 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 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 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 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 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 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 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 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 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 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