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