1 /* 2 * FreeLoader 3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com> 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 #ifndef _M_ARM 20 #include <freeldr.h> 21 22 #define TAG_TUI_SCREENBUFFER 'SiuT' 23 #define TAG_TAG_TUI_PALETTE 'PiuT' 24 25 PVOID TextVideoBuffer = NULL; 26 27 /* 28 * TuiPrintf() 29 * Prints formatted text to the screen 30 */ 31 int TuiPrintf(const char *Format, ...) 32 { 33 int i; 34 int Length; 35 va_list ap; 36 CHAR Buffer[512]; 37 38 va_start(ap, Format); 39 Length = _vsnprintf(Buffer, sizeof(Buffer), Format, ap); 40 va_end(ap); 41 42 if (Length == -1) Length = sizeof(Buffer); 43 44 for (i = 0; i < Length; i++) 45 { 46 MachConsPutChar(Buffer[i]); 47 } 48 49 return Length; 50 } 51 52 BOOLEAN TuiInitialize(VOID) 53 { 54 MachVideoHideShowTextCursor(FALSE); 55 MachVideoSetTextCursorPosition(0, 0); 56 MachVideoClearScreen(ATTR(COLOR_GRAY, COLOR_BLACK)); 57 58 TextVideoBuffer = VideoAllocateOffScreenBuffer(); 59 if (TextVideoBuffer == NULL) 60 { 61 return FALSE; 62 } 63 64 return TRUE; 65 } 66 67 VOID TuiUnInitialize(VOID) 68 { 69 if (UiUseSpecialEffects) 70 { 71 TuiFadeOut(); 72 } 73 else 74 { 75 MachVideoSetDisplayMode(NULL, FALSE); 76 } 77 78 MachVideoClearScreen(ATTR(COLOR_GRAY, COLOR_BLACK)); 79 MachVideoSetTextCursorPosition(0, 0); 80 MachVideoHideShowTextCursor(TRUE); 81 } 82 83 VOID TuiDrawBackdrop(VOID) 84 { 85 // 86 // Fill in the background (excluding title box & status bar) 87 // 88 TuiFillArea(0, 89 TUI_TITLE_BOX_CHAR_HEIGHT, 90 UiScreenWidth - 1, 91 UiScreenHeight - 2, 92 UiBackdropFillStyle, 93 ATTR(UiBackdropFgColor, UiBackdropBgColor)); 94 95 // 96 // Draw the title box 97 // 98 TuiDrawBox(0, 99 0, 100 UiScreenWidth - 1, 101 TUI_TITLE_BOX_CHAR_HEIGHT - 1, 102 D_VERT, 103 D_HORZ, 104 TRUE, 105 FALSE, 106 ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor)); 107 108 // 109 // Draw version text 110 // 111 TuiDrawText(2, 112 1, 113 FrLdrVersionString, 114 ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor)); 115 116 // 117 // Draw copyright 118 // 119 TuiDrawText(2, 120 2, 121 BY_AUTHOR, 122 ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor)); 123 TuiDrawText(2, 124 3, 125 AUTHOR_EMAIL, 126 ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor)); 127 128 // 129 // Draw help text 130 // 131 TuiDrawText(UiScreenWidth - 16, 3, /*"F1 for Help"*/"F8 for Options", ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor)); 132 133 // 134 // Draw title text 135 // 136 TuiDrawText((UiScreenWidth - (ULONG)strlen(UiTitleBoxTitleText)) / 2, 137 2, 138 UiTitleBoxTitleText, 139 ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor)); 140 141 // 142 // Update the date & time 143 // 144 TuiUpdateDateTime(); 145 146 VideoCopyOffScreenBufferToVRAM(); 147 } 148 149 /* 150 * FillArea() 151 * This function assumes coordinates are zero-based 152 */ 153 VOID TuiFillArea(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, CHAR FillChar, UCHAR Attr /* Color Attributes */) 154 { 155 PUCHAR ScreenMemory = (PUCHAR)TextVideoBuffer; 156 ULONG i, j; 157 158 // Clip the area to the screen 159 if ((Left >= UiScreenWidth) || (Top >= UiScreenHeight)) 160 { 161 return; 162 } 163 if (Right >= UiScreenWidth) 164 { 165 Right = UiScreenWidth - 1; 166 } 167 if (Bottom >= UiScreenHeight) 168 { 169 Bottom = UiScreenHeight - 1; 170 } 171 172 // Loop through each line and fill it in 173 for (i=Top; i<=Bottom; i++) 174 { 175 // Loop through each character (column) in the line and fill it in 176 for (j=Left; j<=Right; j++) 177 { 178 ScreenMemory[((i*2)*UiScreenWidth)+(j*2)] = (UCHAR)FillChar; 179 ScreenMemory[((i*2)*UiScreenWidth)+(j*2)+1] = Attr; 180 } 181 } 182 } 183 184 /* 185 * DrawShadow() 186 * This function assumes coordinates are zero-based 187 */ 188 VOID TuiDrawShadow(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom) 189 { 190 PUCHAR ScreenMemory = (PUCHAR)TextVideoBuffer; 191 ULONG Idx; 192 193 // Shade the bottom of the area 194 if (Bottom < (UiScreenHeight - 1)) 195 { 196 if (UiScreenHeight < 34) 197 { 198 Idx=Left + 2; 199 } 200 else 201 { 202 Idx=Left + 1; 203 } 204 205 for (; Idx<=Right; Idx++) 206 { 207 ScreenMemory[(((Bottom+1)*2)*UiScreenWidth)+(Idx*2)+1] = ATTR(COLOR_GRAY, COLOR_BLACK); 208 } 209 } 210 211 // Shade the right of the area 212 if (Right < (UiScreenWidth - 1)) 213 { 214 for (Idx=Top+1; Idx<=Bottom; Idx++) 215 { 216 ScreenMemory[((Idx*2)*UiScreenWidth)+((Right+1)*2)+1] = ATTR(COLOR_GRAY, COLOR_BLACK); 217 } 218 } 219 if (UiScreenHeight < 34) 220 { 221 if ((Right + 1) < (UiScreenWidth - 1)) 222 { 223 for (Idx=Top+1; Idx<=Bottom; Idx++) 224 { 225 ScreenMemory[((Idx*2)*UiScreenWidth)+((Right+2)*2)+1] = ATTR(COLOR_GRAY, COLOR_BLACK); 226 } 227 } 228 } 229 230 // Shade the bottom right corner 231 if ((Right < (UiScreenWidth - 1)) && (Bottom < (UiScreenHeight - 1))) 232 { 233 ScreenMemory[(((Bottom+1)*2)*UiScreenWidth)+((Right+1)*2)+1] = ATTR(COLOR_GRAY, COLOR_BLACK); 234 } 235 if (UiScreenHeight < 34) 236 { 237 if (((Right + 1) < (UiScreenWidth - 1)) && (Bottom < (UiScreenHeight - 1))) 238 { 239 ScreenMemory[(((Bottom+1)*2)*UiScreenWidth)+((Right+2)*2)+1] = ATTR(COLOR_GRAY, COLOR_BLACK); 240 } 241 } 242 } 243 244 /* 245 * DrawBox() 246 * This function assumes coordinates are zero-based 247 */ 248 VOID TuiDrawBox(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, UCHAR VertStyle, UCHAR HorzStyle, BOOLEAN Fill, BOOLEAN Shadow, UCHAR Attr) 249 { 250 UCHAR ULCorner, URCorner, LLCorner, LRCorner; 251 252 // Calculate the corner values 253 if (HorzStyle == HORZ) 254 { 255 if (VertStyle == VERT) 256 { 257 ULCorner = UL; 258 URCorner = UR; 259 LLCorner = LL; 260 LRCorner = LR; 261 } 262 else // VertStyle == D_VERT 263 { 264 ULCorner = VD_UL; 265 URCorner = VD_UR; 266 LLCorner = VD_LL; 267 LRCorner = VD_LR; 268 } 269 } 270 else // HorzStyle == D_HORZ 271 { 272 if (VertStyle == VERT) 273 { 274 ULCorner = HD_UL; 275 URCorner = HD_UR; 276 LLCorner = HD_LL; 277 LRCorner = HD_LR; 278 } 279 else // VertStyle == D_VERT 280 { 281 ULCorner = D_UL; 282 URCorner = D_UR; 283 LLCorner = D_LL; 284 LRCorner = D_LR; 285 } 286 } 287 288 // Fill in box background 289 if (Fill) 290 { 291 TuiFillArea(Left, Top, Right, Bottom, ' ', Attr); 292 } 293 294 // Fill in corners 295 TuiFillArea(Left, Top, Left, Top, ULCorner, Attr); 296 TuiFillArea(Right, Top, Right, Top, URCorner, Attr); 297 TuiFillArea(Left, Bottom, Left, Bottom, LLCorner, Attr); 298 TuiFillArea(Right, Bottom, Right, Bottom, LRCorner, Attr); 299 300 // Fill in left line 301 TuiFillArea(Left, Top+1, Left, Bottom-1, VertStyle, Attr); 302 // Fill in top line 303 TuiFillArea(Left+1, Top, Right-1, Top, HorzStyle, Attr); 304 // Fill in right line 305 TuiFillArea(Right, Top+1, Right, Bottom-1, VertStyle, Attr); 306 // Fill in bottom line 307 TuiFillArea(Left+1, Bottom, Right-1, Bottom, HorzStyle, Attr); 308 309 // Draw the shadow 310 if (Shadow) 311 { 312 TuiDrawShadow(Left, Top, Right, Bottom); 313 } 314 } 315 316 /* 317 * DrawText() 318 * This function assumes coordinates are zero-based 319 */ 320 VOID TuiDrawText(ULONG X, ULONG Y, PCSTR Text, UCHAR Attr) 321 { 322 PUCHAR ScreenMemory = (PUCHAR)TextVideoBuffer; 323 ULONG i, j; 324 325 // Draw the text 326 for (i = X, j = 0; Text[j] && i < UiScreenWidth; i++, j++) 327 { 328 ScreenMemory[((Y*2)*UiScreenWidth)+(i*2)] = (UCHAR)Text[j]; 329 ScreenMemory[((Y*2)*UiScreenWidth)+(i*2)+1] = Attr; 330 } 331 } 332 333 /* 334 * DrawText2() 335 * This function assumes coordinates are zero-based. 336 * MaxNumChars is the maximum number of characters to display. 337 * If MaxNumChars == 0, then display the whole string. 338 */ 339 VOID TuiDrawText2(ULONG X, ULONG Y, ULONG MaxNumChars, PCSTR Text, UCHAR Attr) 340 { 341 PUCHAR ScreenMemory = (PUCHAR)TextVideoBuffer; 342 ULONG i, j; 343 344 // Draw the text 345 for (i = X, j = 0; Text[j] && i < UiScreenWidth && (MaxNumChars > 0 ? j < MaxNumChars : TRUE); i++, j++) 346 { 347 ScreenMemory[((Y*2)*UiScreenWidth)+(i*2)] = (UCHAR)Text[j]; 348 ScreenMemory[((Y*2)*UiScreenWidth)+(i*2)+1] = Attr; 349 } 350 } 351 352 VOID TuiDrawCenteredText(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, PCSTR TextString, UCHAR Attr) 353 { 354 SIZE_T TextLength; 355 ULONG BoxWidth; 356 ULONG BoxHeight; 357 ULONG LineBreakCount; 358 SIZE_T Index; 359 SIZE_T LastIndex; 360 ULONG RealLeft; 361 ULONG RealTop; 362 ULONG X; 363 ULONG Y; 364 CHAR Temp[2]; 365 366 TextLength = strlen(TextString); 367 368 // Count the new lines and the box width 369 LineBreakCount = 0; 370 BoxWidth = 0; 371 LastIndex = 0; 372 for (Index=0; Index<TextLength; Index++) 373 { 374 if (TextString[Index] == '\n') 375 { 376 LastIndex = Index; 377 LineBreakCount++; 378 } 379 else 380 { 381 if ((Index - LastIndex) > BoxWidth) 382 { 383 BoxWidth = (ULONG)(Index - LastIndex); 384 } 385 } 386 } 387 388 BoxHeight = LineBreakCount + 1; 389 390 RealLeft = (((Right - Left) - BoxWidth) / 2) + Left; 391 RealTop = (((Bottom - Top) - BoxHeight) / 2) + Top; 392 393 LastIndex = 0; 394 for (Index=0; Index<TextLength; Index++) 395 { 396 if (TextString[Index] == '\n') 397 { 398 RealTop++; 399 LastIndex = 0; 400 } 401 else 402 { 403 X = (ULONG)(RealLeft + LastIndex); 404 Y = RealTop; 405 LastIndex++; 406 Temp[0] = TextString[Index]; 407 Temp[1] = 0; 408 TuiDrawText(X, Y, Temp, Attr); 409 } 410 } 411 } 412 413 VOID TuiDrawStatusText(PCSTR StatusText) 414 { 415 SIZE_T i; 416 417 TuiDrawText(0, UiScreenHeight-1, " ", ATTR(UiStatusBarFgColor, UiStatusBarBgColor)); 418 TuiDrawText(1, UiScreenHeight-1, StatusText, ATTR(UiStatusBarFgColor, UiStatusBarBgColor)); 419 420 for (i=strlen(StatusText)+1; i<UiScreenWidth; i++) 421 { 422 TuiDrawText((ULONG)i, UiScreenHeight-1, " ", ATTR(UiStatusBarFgColor, UiStatusBarBgColor)); 423 } 424 425 VideoCopyOffScreenBufferToVRAM(); 426 } 427 428 VOID TuiUpdateDateTime(VOID) 429 { 430 TIMEINFO* TimeInfo; 431 char DateString[40]; 432 CHAR TimeString[40]; 433 CHAR TempString[20]; 434 BOOLEAN PMHour = FALSE; 435 436 /* Don't draw the time if this has been disabled */ 437 if (!UiDrawTime) return; 438 439 TimeInfo = ArcGetTime(); 440 if (TimeInfo->Year < 1 || 9999 < TimeInfo->Year || 441 TimeInfo->Month < 1 || 12 < TimeInfo->Month || 442 TimeInfo->Day < 1 || 31 < TimeInfo->Day || 443 23 < TimeInfo->Hour || 444 59 < TimeInfo->Minute || 445 59 < TimeInfo->Second) 446 { 447 /* This happens on QEmu sometimes. We just skip updating */ 448 return; 449 } 450 // Get the month name 451 strcpy(DateString, UiMonthNames[TimeInfo->Month - 1]); 452 // Get the day 453 _itoa(TimeInfo->Day, TempString, 10); 454 // Get the day postfix 455 if (1 == TimeInfo->Day || 21 == TimeInfo->Day || 31 == TimeInfo->Day) 456 { 457 strcat(TempString, "st"); 458 } 459 else if (2 == TimeInfo->Day || 22 == TimeInfo->Day) 460 { 461 strcat(TempString, "nd"); 462 } 463 else if (3 == TimeInfo->Day || 23 == TimeInfo->Day) 464 { 465 strcat(TempString, "rd"); 466 } 467 else 468 { 469 strcat(TempString, "th"); 470 } 471 472 // Add the day to the date 473 strcat(DateString, TempString); 474 strcat(DateString, " "); 475 476 // Get the year and add it to the date 477 _itoa(TimeInfo->Year, TempString, 10); 478 strcat(DateString, TempString); 479 480 // Draw the date 481 TuiDrawText(UiScreenWidth-(ULONG)strlen(DateString)-2, 1, DateString, ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor)); 482 483 // Get the hour and change from 24-hour mode to 12-hour 484 if (TimeInfo->Hour > 12) 485 { 486 TimeInfo->Hour -= 12; 487 PMHour = TRUE; 488 } 489 if (TimeInfo->Hour == 0) 490 { 491 TimeInfo->Hour = 12; 492 } 493 _itoa(TimeInfo->Hour, TempString, 10); 494 strcpy(TimeString, " "); 495 strcat(TimeString, TempString); 496 strcat(TimeString, ":"); 497 _itoa(TimeInfo->Minute, TempString, 10); 498 if (TimeInfo->Minute < 10) 499 { 500 strcat(TimeString, "0"); 501 } 502 strcat(TimeString, TempString); 503 strcat(TimeString, ":"); 504 _itoa(TimeInfo->Second, TempString, 10); 505 if (TimeInfo->Second < 10) 506 { 507 strcat(TimeString, "0"); 508 } 509 strcat(TimeString, TempString); 510 if (PMHour) 511 { 512 strcat(TimeString, " PM"); 513 } 514 else 515 { 516 strcat(TimeString, " AM"); 517 } 518 519 // Draw the time 520 TuiDrawText(UiScreenWidth-(ULONG)strlen(TimeString)-2, 2, TimeString, ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor)); 521 } 522 523 VOID TuiSaveScreen(PUCHAR Buffer) 524 { 525 PUCHAR ScreenMemory = (PUCHAR)TextVideoBuffer; 526 ULONG i; 527 528 for (i=0; i < (UiScreenWidth * UiScreenHeight * 2); i++) 529 { 530 Buffer[i] = ScreenMemory[i]; 531 } 532 } 533 534 VOID TuiRestoreScreen(PUCHAR Buffer) 535 { 536 PUCHAR ScreenMemory = (PUCHAR)TextVideoBuffer; 537 ULONG i; 538 539 for (i=0; i < (UiScreenWidth * UiScreenHeight * 2); i++) 540 { 541 ScreenMemory[i] = Buffer[i]; 542 } 543 } 544 545 VOID TuiMessageBox(PCSTR MessageText) 546 { 547 PVOID ScreenBuffer; 548 549 // Save the screen contents 550 ScreenBuffer = FrLdrTempAlloc(UiScreenWidth * UiScreenHeight * 2, 551 TAG_TUI_SCREENBUFFER); 552 TuiSaveScreen(ScreenBuffer); 553 554 // Display the message box 555 TuiMessageBoxCritical(MessageText); 556 557 // Restore the screen contents 558 TuiRestoreScreen(ScreenBuffer); 559 FrLdrTempFree(ScreenBuffer, TAG_TUI_SCREENBUFFER); 560 } 561 562 VOID TuiMessageBoxCritical(PCSTR MessageText) 563 { 564 int width = 8; 565 unsigned int height = 1; 566 int curline = 0; 567 int k; 568 size_t i , j; 569 int x1, x2, y1, y2; 570 char temp[260]; 571 char key; 572 573 // Find the height 574 for (i=0; i<strlen(MessageText); i++) 575 { 576 if (MessageText[i] == '\n') 577 height++; 578 } 579 580 // Find the width 581 for (i=0,j=0,k=0; i<height; i++) 582 { 583 while ((MessageText[j] != '\n') && (MessageText[j] != 0)) 584 { 585 j++; 586 k++; 587 } 588 589 if (k > width) 590 width = k; 591 592 k = 0; 593 j++; 594 } 595 596 // Calculate box area 597 x1 = (UiScreenWidth - (width+2))/2; 598 x2 = x1 + width + 3; 599 y1 = ((UiScreenHeight - height - 2)/2) + 1; 600 y2 = y1 + height + 4; 601 602 // Draw the box 603 TuiDrawBox(x1, y1, x2, y2, D_VERT, D_HORZ, TRUE, TRUE, ATTR(UiMessageBoxFgColor, UiMessageBoxBgColor)); 604 605 // Draw the text 606 for (i=0,j=0; i<strlen(MessageText)+1; i++) 607 { 608 if ((MessageText[i] == '\n') || (MessageText[i] == 0)) 609 { 610 temp[j] = 0; 611 j = 0; 612 UiDrawText(x1+2, y1+1+curline, temp, ATTR(UiMessageBoxFgColor, UiMessageBoxBgColor)); 613 curline++; 614 } 615 else 616 temp[j++] = MessageText[i]; 617 } 618 619 // Draw OK button 620 strcpy(temp, " OK "); 621 UiDrawText(x1+((x2-x1)/2)-3, y2-2, temp, ATTR(COLOR_BLACK, COLOR_GRAY)); 622 623 // Draw status text 624 UiDrawStatusText("Press ENTER to continue"); 625 626 VideoCopyOffScreenBufferToVRAM(); 627 628 for (;;) 629 { 630 if (MachConsKbHit()) 631 { 632 key = MachConsGetCh(); 633 if (key == KEY_EXTENDED) 634 key = MachConsGetCh(); 635 636 if ((key == KEY_ENTER) || (key == KEY_SPACE) || (key == KEY_ESC)) 637 break; 638 } 639 640 TuiUpdateDateTime(); 641 642 VideoCopyOffScreenBufferToVRAM(); 643 644 MachHwIdle(); 645 } 646 } 647 648 VOID TuiDrawProgressBarCenter(ULONG Position, ULONG Range, PCHAR ProgressText) 649 { 650 ULONG Left, Top, Right, Bottom; 651 ULONG Width = 50; // Allow for 50 "bars" 652 ULONG Height = 2; 653 654 Left = (UiScreenWidth - Width - 4) / 2; 655 Right = Left + Width + 3; 656 Top = (UiScreenHeight - Height - 2) / 2; 657 Top += 2; 658 Bottom = Top + Height + 1; 659 660 TuiDrawProgressBar(Left, Top, Right, Bottom, Position, Range, ProgressText); 661 } 662 663 VOID TuiDrawProgressBar(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, ULONG Position, ULONG Range, PCHAR ProgressText) 664 { 665 ULONG i; 666 ULONG ProgressBarWidth = (Right - Left) - 3; 667 668 // First make sure the progress bar text fits 669 UiTruncateStringEllipsis(ProgressText, ProgressBarWidth - 4); 670 671 if (Position > Range) 672 { 673 Position = Range; 674 } 675 676 // Draw the box 677 TuiDrawBox(Left, Top, Right, Bottom, VERT, HORZ, TRUE, TRUE, ATTR(UiMenuFgColor, UiMenuBgColor)); 678 679 // 680 // Draw the "Loading..." text 681 // 682 TuiDrawCenteredText(Left + 2, Top + 2, Right - 2, Top + 2, ProgressText, ATTR(UiTextColor, UiMenuBgColor)); 683 684 // Draw the percent complete 685 for (i=0; i<(Position*ProgressBarWidth)/Range; i++) 686 { 687 TuiDrawText(Left+2+i, Top+2, "\xDB", ATTR(UiTextColor, UiMenuBgColor)); 688 } 689 690 // Draw the shadow 691 for (; i<ProgressBarWidth; i++) 692 { 693 TuiDrawText(Left+2+i, Top+2, "\xB2", ATTR(UiTextColor, UiMenuBgColor)); 694 } 695 696 TuiUpdateDateTime(); 697 VideoCopyOffScreenBufferToVRAM(); 698 } 699 700 UCHAR TuiTextToColor(PCSTR ColorText) 701 { 702 static const struct 703 { 704 PCSTR ColorName; 705 UCHAR ColorValue; 706 } Colors[] = 707 { 708 {"Black" , COLOR_BLACK }, 709 {"Blue" , COLOR_BLUE }, 710 {"Green" , COLOR_GREEN }, 711 {"Cyan" , COLOR_CYAN }, 712 {"Red" , COLOR_RED }, 713 {"Magenta", COLOR_MAGENTA}, 714 {"Brown" , COLOR_BROWN }, 715 {"Gray" , COLOR_GRAY }, 716 {"DarkGray" , COLOR_DARKGRAY }, 717 {"LightBlue" , COLOR_LIGHTBLUE }, 718 {"LightGreen" , COLOR_LIGHTGREEN }, 719 {"LightCyan" , COLOR_LIGHTCYAN }, 720 {"LightRed" , COLOR_LIGHTRED }, 721 {"LightMagenta", COLOR_LIGHTMAGENTA}, 722 {"Yellow" , COLOR_YELLOW }, 723 {"White" , COLOR_WHITE }, 724 }; 725 ULONG i; 726 727 for (i = 0; i < sizeof(Colors)/sizeof(Colors[0]); ++i) 728 { 729 if (_stricmp(ColorText, Colors[i].ColorName) == 0) 730 return Colors[i].ColorValue; 731 } 732 733 return COLOR_BLACK; 734 } 735 736 UCHAR TuiTextToFillStyle(PCSTR FillStyleText) 737 { 738 static const struct 739 { 740 PCSTR FillStyleName; 741 UCHAR FillStyleValue; 742 } FillStyles[] = 743 { 744 {"Light" , LIGHT_FILL }, 745 {"Medium", MEDIUM_FILL}, 746 {"Dark" , DARK_FILL }, 747 }; 748 ULONG i; 749 750 for (i = 0; i < sizeof(FillStyles)/sizeof(FillStyles[0]); ++i) 751 { 752 if (_stricmp(FillStyleText, FillStyles[i].FillStyleName) == 0) 753 return FillStyles[i].FillStyleValue; 754 } 755 756 return LIGHT_FILL; 757 } 758 759 VOID TuiFadeInBackdrop(VOID) 760 { 761 PPALETTE_ENTRY TuiFadePalette = NULL; 762 763 if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed()) 764 { 765 TuiFadePalette = (PPALETTE_ENTRY)FrLdrTempAlloc(sizeof(PALETTE_ENTRY) * 64, 766 TAG_TAG_TUI_PALETTE); 767 768 if (TuiFadePalette != NULL) 769 { 770 VideoSavePaletteState(TuiFadePalette, 64); 771 VideoSetAllColorsToBlack(64); 772 } 773 } 774 775 // Draw the backdrop and title box 776 TuiDrawBackdrop(); 777 778 if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed() && TuiFadePalette != NULL) 779 { 780 VideoFadeIn(TuiFadePalette, 64); 781 FrLdrTempFree(TuiFadePalette, TAG_TAG_TUI_PALETTE); 782 } 783 } 784 785 VOID TuiFadeOut(VOID) 786 { 787 PPALETTE_ENTRY TuiFadePalette = NULL; 788 789 if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed()) 790 { 791 TuiFadePalette = (PPALETTE_ENTRY)FrLdrTempAlloc(sizeof(PALETTE_ENTRY) * 64, 792 TAG_TAG_TUI_PALETTE); 793 794 if (TuiFadePalette != NULL) 795 { 796 VideoSavePaletteState(TuiFadePalette, 64); 797 } 798 } 799 800 if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed() && TuiFadePalette != NULL) 801 { 802 VideoFadeOut(64); 803 } 804 805 MachVideoSetDisplayMode(NULL, FALSE); 806 807 if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed() && TuiFadePalette != NULL) 808 { 809 VideoRestorePaletteState(TuiFadePalette, 64); 810 FrLdrTempFree(TuiFadePalette, TAG_TAG_TUI_PALETTE); 811 } 812 813 } 814 815 BOOLEAN TuiEditBox(PCSTR MessageText, PCHAR EditTextBuffer, ULONG Length) 816 { 817 INT width = 8; 818 ULONG height = 1; 819 INT curline = 0; 820 INT k; 821 size_t i , j; 822 INT x1, x2, y1, y2; 823 CHAR temp[260]; 824 CHAR key; 825 BOOLEAN Extended; 826 INT EditBoxLine; 827 ULONG EditBoxStartX, EditBoxEndX; 828 INT EditBoxCursorX; 829 ULONG EditBoxTextLength, EditBoxTextPosition; 830 INT EditBoxTextDisplayIndex; 831 BOOLEAN ReturnCode; 832 PVOID ScreenBuffer; 833 834 // Save the screen contents 835 ScreenBuffer = FrLdrTempAlloc(UiScreenWidth * UiScreenHeight * 2, 836 TAG_TUI_SCREENBUFFER); 837 TuiSaveScreen(ScreenBuffer); 838 839 // Find the height 840 for (i=0; i<strlen(MessageText); i++) 841 { 842 if (MessageText[i] == '\n') 843 height++; 844 } 845 846 // Find the width 847 for (i=0,j=0,k=0; i<height; i++) 848 { 849 while ((MessageText[j] != '\n') && (MessageText[j] != 0)) 850 { 851 j++; 852 k++; 853 } 854 855 if (k > width) 856 width = k; 857 858 k = 0; 859 j++; 860 } 861 862 // Calculate box area 863 x1 = (UiScreenWidth - (width+2))/2; 864 x2 = x1 + width + 3; 865 y1 = ((UiScreenHeight - height - 2)/2) + 1; 866 y2 = y1 + height + 4; 867 868 // Draw the box 869 TuiDrawBox(x1, y1, x2, y2, D_VERT, D_HORZ, TRUE, TRUE, ATTR(UiMessageBoxFgColor, UiMessageBoxBgColor)); 870 871 // Draw the text 872 for (i=0,j=0; i<strlen(MessageText)+1; i++) 873 { 874 if ((MessageText[i] == '\n') || (MessageText[i] == 0)) 875 { 876 temp[j] = 0; 877 j = 0; 878 UiDrawText(x1+2, y1+1+curline, temp, ATTR(UiMessageBoxFgColor, UiMessageBoxBgColor)); 879 curline++; 880 } 881 else 882 temp[j++] = MessageText[i]; 883 } 884 885 EditBoxTextLength = (ULONG)strlen(EditTextBuffer); 886 EditBoxTextLength = min(EditBoxTextLength, Length - 1); 887 EditBoxTextPosition = 0; 888 EditBoxLine = y2 - 2; 889 EditBoxStartX = x1 + 3; 890 EditBoxEndX = x2 - 3; 891 892 // Draw the edit box background and the text 893 UiFillArea(EditBoxStartX, EditBoxLine, EditBoxEndX, EditBoxLine, ' ', ATTR(UiEditBoxTextColor, UiEditBoxBgColor)); 894 UiDrawText2(EditBoxStartX, EditBoxLine, EditBoxEndX - EditBoxStartX + 1, EditTextBuffer, ATTR(UiEditBoxTextColor, UiEditBoxBgColor)); 895 896 // Show the cursor 897 EditBoxCursorX = EditBoxStartX; 898 MachVideoSetTextCursorPosition(EditBoxCursorX, EditBoxLine); 899 MachVideoHideShowTextCursor(TRUE); 900 901 // Draw status text 902 UiDrawStatusText("Press ENTER to continue, or ESC to cancel"); 903 904 VideoCopyOffScreenBufferToVRAM(); 905 906 // 907 // Enter the text. Please keep in mind that the default input mode 908 // of the edit boxes is in insertion mode, that is, you can insert 909 // text without erasing the existing one. 910 // 911 for (;;) 912 { 913 if (MachConsKbHit()) 914 { 915 Extended = FALSE; 916 key = MachConsGetCh(); 917 if (key == KEY_EXTENDED) 918 { 919 Extended = TRUE; 920 key = MachConsGetCh(); 921 } 922 923 if (key == KEY_ENTER) 924 { 925 ReturnCode = TRUE; 926 break; 927 } 928 else if (key == KEY_ESC) 929 { 930 ReturnCode = FALSE; 931 break; 932 } 933 else if (key == KEY_BACKSPACE) // Remove a character 934 { 935 if ( (EditBoxTextLength > 0) && (EditBoxTextPosition > 0) && 936 (EditBoxTextPosition <= EditBoxTextLength) ) 937 { 938 EditBoxTextPosition--; 939 memmove(EditTextBuffer + EditBoxTextPosition, 940 EditTextBuffer + EditBoxTextPosition + 1, 941 EditBoxTextLength - EditBoxTextPosition); 942 EditBoxTextLength--; 943 EditTextBuffer[EditBoxTextLength] = 0; 944 } 945 else 946 { 947 MachBeep(); 948 } 949 } 950 else if (Extended && key == KEY_DELETE) // Remove a character 951 { 952 if ( (EditBoxTextLength > 0) && 953 (EditBoxTextPosition < EditBoxTextLength) ) 954 { 955 memmove(EditTextBuffer + EditBoxTextPosition, 956 EditTextBuffer + EditBoxTextPosition + 1, 957 EditBoxTextLength - EditBoxTextPosition); 958 EditBoxTextLength--; 959 EditTextBuffer[EditBoxTextLength] = 0; 960 } 961 else 962 { 963 MachBeep(); 964 } 965 } 966 else if (Extended && key == KEY_HOME) // Go to the start of the buffer 967 { 968 EditBoxTextPosition = 0; 969 } 970 else if (Extended && key == KEY_END) // Go to the end of the buffer 971 { 972 EditBoxTextPosition = EditBoxTextLength; 973 } 974 else if (Extended && key == KEY_RIGHT) // Go right 975 { 976 if (EditBoxTextPosition < EditBoxTextLength) 977 EditBoxTextPosition++; 978 else 979 MachBeep(); 980 } 981 else if (Extended && key == KEY_LEFT) // Go left 982 { 983 if (EditBoxTextPosition > 0) 984 EditBoxTextPosition--; 985 else 986 MachBeep(); 987 } 988 else if (!Extended) // Add this key to the buffer 989 { 990 if ( (EditBoxTextLength < Length - 1) && 991 (EditBoxTextPosition < Length - 1) ) 992 { 993 memmove(EditTextBuffer + EditBoxTextPosition + 1, 994 EditTextBuffer + EditBoxTextPosition, 995 EditBoxTextLength - EditBoxTextPosition); 996 EditTextBuffer[EditBoxTextPosition] = key; 997 EditBoxTextPosition++; 998 EditBoxTextLength++; 999 EditTextBuffer[EditBoxTextLength] = 0; 1000 } 1001 else 1002 { 1003 MachBeep(); 1004 } 1005 } 1006 else 1007 { 1008 MachBeep(); 1009 } 1010 } 1011 1012 // Draw the edit box background 1013 UiFillArea(EditBoxStartX, EditBoxLine, EditBoxEndX, EditBoxLine, ' ', ATTR(UiEditBoxTextColor, UiEditBoxBgColor)); 1014 1015 // Fill the text in 1016 if (EditBoxTextPosition > (EditBoxEndX - EditBoxStartX)) 1017 { 1018 EditBoxTextDisplayIndex = EditBoxTextPosition - (EditBoxEndX - EditBoxStartX); 1019 EditBoxCursorX = EditBoxEndX; 1020 } 1021 else 1022 { 1023 EditBoxTextDisplayIndex = 0; 1024 EditBoxCursorX = EditBoxStartX + EditBoxTextPosition; 1025 } 1026 UiDrawText2(EditBoxStartX, EditBoxLine, EditBoxEndX - EditBoxStartX + 1, &EditTextBuffer[EditBoxTextDisplayIndex], ATTR(UiEditBoxTextColor, UiEditBoxBgColor)); 1027 1028 // Move the cursor 1029 MachVideoSetTextCursorPosition(EditBoxCursorX, EditBoxLine); 1030 1031 TuiUpdateDateTime(); 1032 1033 VideoCopyOffScreenBufferToVRAM(); 1034 1035 MachHwIdle(); 1036 } 1037 1038 // Hide the cursor again 1039 MachVideoHideShowTextCursor(FALSE); 1040 1041 // Restore the screen contents 1042 TuiRestoreScreen(ScreenBuffer); 1043 FrLdrTempFree(ScreenBuffer, TAG_TUI_SCREENBUFFER); 1044 1045 return ReturnCode; 1046 } 1047 1048 const UIVTBL TuiVtbl = 1049 { 1050 TuiInitialize, 1051 TuiUnInitialize, 1052 TuiDrawBackdrop, 1053 TuiFillArea, 1054 TuiDrawShadow, 1055 TuiDrawBox, 1056 TuiDrawText, 1057 TuiDrawText2, 1058 TuiDrawCenteredText, 1059 TuiDrawStatusText, 1060 TuiUpdateDateTime, 1061 TuiMessageBox, 1062 TuiMessageBoxCritical, 1063 TuiDrawProgressBarCenter, 1064 TuiDrawProgressBar, 1065 TuiEditBox, 1066 TuiTextToColor, 1067 TuiTextToFillStyle, 1068 TuiFadeInBackdrop, 1069 TuiFadeOut, 1070 TuiDisplayMenu, 1071 TuiDrawMenu, 1072 }; 1073 #endif 1074