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