Sync with trunk r63831.
[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)
635 break;
636 else if(key == KEY_SPACE)
637 break;
638 else if(key == KEY_ESC)
639 break;
640 }
641
642 TuiUpdateDateTime();
643
644 VideoCopyOffScreenBufferToVRAM();
645
646 MachHwIdle();
647 }
648
649 }
650
651 VOID TuiDrawProgressBarCenter(ULONG Position, ULONG Range, PCHAR ProgressText)
652 {
653 ULONG Left, Top, Right, Bottom;
654 ULONG Width = 50; // Allow for 50 "bars"
655 ULONG Height = 2;
656
657 Left = (UiScreenWidth - Width - 4) / 2;
658 Right = Left + Width + 3;
659 Top = (UiScreenHeight - Height - 2) / 2;
660 Top += 2;
661 Bottom = Top + Height + 1;
662
663 TuiDrawProgressBar(Left, Top, Right, Bottom, Position, Range, ProgressText);
664 }
665
666 VOID TuiDrawProgressBar(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, ULONG Position, ULONG Range, PCHAR ProgressText)
667 {
668 ULONG i;
669 ULONG ProgressBarWidth = (Right - Left) - 3;
670
671 // First make sure the progress bar text fits
672 UiTruncateStringEllipsis(ProgressText, ProgressBarWidth - 4);
673
674 if (Position > Range)
675 {
676 Position = Range;
677 }
678
679 // Draw the box
680 TuiDrawBox(Left, Top, Right, Bottom, VERT, HORZ, TRUE, TRUE, ATTR(UiMenuFgColor, UiMenuBgColor));
681
682 //
683 // Draw the "Loading..." text
684 //
685 TuiDrawCenteredText(Left + 2, Top + 2, Right - 2, Top + 2, ProgressText, ATTR(UiTextColor, UiMenuBgColor));
686
687 // Draw the percent complete
688 for (i=0; i<(Position*ProgressBarWidth)/Range; i++)
689 {
690 TuiDrawText(Left+2+i, Top+2, "\xDB", ATTR(UiTextColor, UiMenuBgColor));
691 }
692
693 // Draw the shadow
694 for (; i<ProgressBarWidth; i++)
695 {
696 TuiDrawText(Left+2+i, Top+2, "\xB2", ATTR(UiTextColor, UiMenuBgColor));
697 }
698
699 TuiUpdateDateTime();
700 VideoCopyOffScreenBufferToVRAM();
701 }
702
703 UCHAR TuiTextToColor(PCSTR ColorText)
704 {
705 if (_stricmp(ColorText, "Black") == 0)
706 return COLOR_BLACK;
707 else if (_stricmp(ColorText, "Blue") == 0)
708 return COLOR_BLUE;
709 else if (_stricmp(ColorText, "Green") == 0)
710 return COLOR_GREEN;
711 else if (_stricmp(ColorText, "Cyan") == 0)
712 return COLOR_CYAN;
713 else if (_stricmp(ColorText, "Red") == 0)
714 return COLOR_RED;
715 else if (_stricmp(ColorText, "Magenta") == 0)
716 return COLOR_MAGENTA;
717 else if (_stricmp(ColorText, "Brown") == 0)
718 return COLOR_BROWN;
719 else if (_stricmp(ColorText, "Gray") == 0)
720 return COLOR_GRAY;
721 else if (_stricmp(ColorText, "DarkGray") == 0)
722 return COLOR_DARKGRAY;
723 else if (_stricmp(ColorText, "LightBlue") == 0)
724 return COLOR_LIGHTBLUE;
725 else if (_stricmp(ColorText, "LightGreen") == 0)
726 return COLOR_LIGHTGREEN;
727 else if (_stricmp(ColorText, "LightCyan") == 0)
728 return COLOR_LIGHTCYAN;
729 else if (_stricmp(ColorText, "LightRed") == 0)
730 return COLOR_LIGHTRED;
731 else if (_stricmp(ColorText, "LightMagenta") == 0)
732 return COLOR_LIGHTMAGENTA;
733 else if (_stricmp(ColorText, "Yellow") == 0)
734 return COLOR_YELLOW;
735 else if (_stricmp(ColorText, "White") == 0)
736 return COLOR_WHITE;
737
738 return COLOR_BLACK;
739 }
740
741 UCHAR TuiTextToFillStyle(PCSTR FillStyleText)
742 {
743 if (_stricmp(FillStyleText, "Light") == 0)
744 {
745 return LIGHT_FILL;
746 }
747 else if (_stricmp(FillStyleText, "Medium") == 0)
748 {
749 return MEDIUM_FILL;
750 }
751 else if (_stricmp(FillStyleText, "Dark") == 0)
752 {
753 return DARK_FILL;
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 = 0;
886 EditBoxTextPosition = 0;
887 EditBoxLine = y2 - 2;
888 EditBoxStartX = x1 + 3;
889 EditBoxEndX = x2 - 3;
890 UiFillArea(EditBoxStartX, EditBoxLine, EditBoxEndX, EditBoxLine, ' ', ATTR(UiEditBoxTextColor, UiEditBoxBgColor));
891
892 // Show the cursor
893 EditBoxCursorX = EditBoxStartX;
894 MachVideoSetTextCursorPosition(EditBoxCursorX, EditBoxLine);
895 MachVideoHideShowTextCursor(TRUE);
896
897 // Draw status text
898 UiDrawStatusText("Press ENTER to continue, or ESC to cancel");
899
900 VideoCopyOffScreenBufferToVRAM();
901
902 //
903 // Enter the text. Please keep in mind that the default input mode
904 // of the edit boxes is in insertion mode, that is, you can insert
905 // text without erasing the existing one.
906 //
907 for (;;)
908 {
909 if (MachConsKbHit())
910 {
911 Extended = FALSE;
912 key = MachConsGetCh();
913 if(key == KEY_EXTENDED)
914 {
915 Extended = TRUE;
916 key = MachConsGetCh();
917 }
918
919 if(key == KEY_ENTER)
920 {
921 ReturnCode = TRUE;
922 break;
923 }
924 else if(key == KEY_ESC)
925 {
926 ReturnCode = FALSE;
927 break;
928 }
929 else if (key == KEY_BACKSPACE) // Remove a character
930 {
931 if ( (EditBoxTextLength > 0) && (EditBoxTextPosition > 0) &&
932 (EditBoxTextPosition <= EditBoxTextLength) )
933 {
934 EditBoxTextPosition--;
935 memmove(EditTextBuffer + EditBoxTextPosition,
936 EditTextBuffer + EditBoxTextPosition + 1,
937 EditBoxTextLength - EditBoxTextPosition);
938 EditBoxTextLength--;
939 EditTextBuffer[EditBoxTextLength] = 0;
940 }
941 else
942 {
943 MachBeep();
944 }
945 }
946 else if (Extended && key == KEY_DELETE) // Remove a character
947 {
948 if ( (EditBoxTextLength > 0) &&
949 (EditBoxTextPosition < EditBoxTextLength) )
950 {
951 memmove(EditTextBuffer + EditBoxTextPosition,
952 EditTextBuffer + EditBoxTextPosition + 1,
953 EditBoxTextLength - EditBoxTextPosition);
954 EditBoxTextLength--;
955 EditTextBuffer[EditBoxTextLength] = 0;
956 }
957 else
958 {
959 MachBeep();
960 }
961 }
962 else if (Extended && key == KEY_HOME) // Go to the start of the buffer
963 {
964 EditBoxTextPosition = 0;
965 }
966 else if (Extended && key == KEY_END) // Go to the end of the buffer
967 {
968 EditBoxTextPosition = EditBoxTextLength;
969 }
970 else if (Extended && key == KEY_RIGHT) // Go right
971 {
972 if (EditBoxTextPosition < EditBoxTextLength)
973 EditBoxTextPosition++;
974 else
975 MachBeep();
976 }
977 else if (Extended && key == KEY_LEFT) // Go left
978 {
979 if (EditBoxTextPosition > 0)
980 EditBoxTextPosition--;
981 else
982 MachBeep();
983 }
984 else if (!Extended) // Add this key to the buffer
985 {
986 if ( (EditBoxTextLength < Length - 1) &&
987 (EditBoxTextPosition < Length - 1) )
988 {
989 memmove(EditTextBuffer + EditBoxTextPosition + 1,
990 EditTextBuffer + EditBoxTextPosition,
991 EditBoxTextLength - EditBoxTextPosition);
992 EditTextBuffer[EditBoxTextPosition] = key;
993 EditBoxTextPosition++;
994 EditBoxTextLength++;
995 EditTextBuffer[EditBoxTextLength] = 0;
996 }
997 else
998 {
999 MachBeep();
1000 }
1001 }
1002 else
1003 {
1004 MachBeep();
1005 }
1006 }
1007
1008 // Draw the edit box background
1009 UiFillArea(EditBoxStartX, EditBoxLine, EditBoxEndX, EditBoxLine, ' ', ATTR(UiEditBoxTextColor, UiEditBoxBgColor));
1010
1011 // Fill the text in
1012 if (EditBoxTextPosition > (EditBoxEndX - EditBoxStartX))
1013 {
1014 EditBoxTextDisplayIndex = EditBoxTextPosition - (EditBoxEndX - EditBoxStartX);
1015 EditBoxCursorX = EditBoxEndX;
1016 }
1017 else
1018 {
1019 EditBoxTextDisplayIndex = 0;
1020 EditBoxCursorX = EditBoxStartX + EditBoxTextPosition;
1021 }
1022 UiDrawText2(EditBoxStartX, EditBoxLine, EditBoxEndX - EditBoxStartX + 1, &EditTextBuffer[EditBoxTextDisplayIndex], ATTR(UiEditBoxTextColor, UiEditBoxBgColor));
1023
1024 // Move the cursor
1025 MachVideoSetTextCursorPosition(EditBoxCursorX, EditBoxLine);
1026
1027 TuiUpdateDateTime();
1028
1029 VideoCopyOffScreenBufferToVRAM();
1030
1031 MachHwIdle();
1032 }
1033
1034 // Hide the cursor again
1035 MachVideoHideShowTextCursor(FALSE);
1036
1037 // Restore the screen contents
1038 TuiRestoreScreen(ScreenBuffer);
1039 FrLdrTempFree(ScreenBuffer, TAG_TUI_SCREENBUFFER);
1040
1041 return ReturnCode;
1042 }
1043
1044 const UIVTBL TuiVtbl =
1045 {
1046 TuiInitialize,
1047 TuiUnInitialize,
1048 TuiDrawBackdrop,
1049 TuiFillArea,
1050 TuiDrawShadow,
1051 TuiDrawBox,
1052 TuiDrawText,
1053 TuiDrawText2,
1054 TuiDrawCenteredText,
1055 TuiDrawStatusText,
1056 TuiUpdateDateTime,
1057 TuiMessageBox,
1058 TuiMessageBoxCritical,
1059 TuiDrawProgressBarCenter,
1060 TuiDrawProgressBar,
1061 TuiEditBox,
1062 TuiTextToColor,
1063 TuiTextToFillStyle,
1064 TuiFadeInBackdrop,
1065 TuiFadeOut,
1066 TuiDisplayMenu,
1067 TuiDrawMenu,
1068 };
1069 #endif