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