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