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