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