FreeLdr Patch. Now fully loads ntoskrnl using a PE Loader, supports /3gb dynamically...
[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, UCHAR 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)] = 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, PUCHAR 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)] = 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, PUCHAR 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 UCHAR 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(PUCHAR 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 UCHAR DateString[40];
401 UCHAR TimeString[40];
402 UCHAR TempString[20];
403 BOOL PMHour = FALSE;
404
405 MachRTCGetCurrentDateTime(&Year, &Month, &Day, &Hour, &Minute, &Second);
406 // Get the month name
407 strcpy(DateString, UiMonthNames[Month - 1]);
408 // Get the day
409 itoa(Day, TempString, 10);
410 // Get the day postfix
411 if (1 == Day || 21 == Day || 31 == Day)
412 {
413 strcat(TempString, "st");
414 }
415 else if (2 == Day || 22 == Day)
416 {
417 strcat(TempString, "nd");
418 }
419 else if (3 == Day || 23 == Day)
420 {
421 strcat(TempString, "rd");
422 }
423 else
424 {
425 strcat(TempString, "th");
426 }
427
428 // Add the day to the date
429 strcat(DateString, TempString);
430 strcat(DateString, " ");
431
432 // Get the year and add it to the date
433 itoa(Year, TempString, 10);
434 strcat(DateString, TempString);
435
436 // Draw the date
437 TuiDrawText(UiScreenWidth-strlen(DateString)-2, 1, DateString, ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor));
438
439 // Get the hour and change from 24-hour mode to 12-hour
440 if (Hour > 12)
441 {
442 Hour -= 12;
443 PMHour = TRUE;
444 }
445 if (Hour == 0)
446 {
447 Hour = 12;
448 }
449 itoa(Hour, TempString, 10);
450 strcpy(TimeString, " ");
451 strcat(TimeString, TempString);
452 strcat(TimeString, ":");
453 itoa(Minute, TempString, 10);
454 if (Minute < 10)
455 {
456 strcat(TimeString, "0");
457 }
458 strcat(TimeString, TempString);
459 strcat(TimeString, ":");
460 itoa(Second, TempString, 10);
461 if (Second < 10)
462 {
463 strcat(TimeString, "0");
464 }
465 strcat(TimeString, TempString);
466 if (PMHour)
467 {
468 strcat(TimeString, " PM");
469 }
470 else
471 {
472 strcat(TimeString, " AM");
473 }
474
475 // Draw the time
476 TuiDrawText(UiScreenWidth-strlen(TimeString)-2, 2, TimeString, ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor));
477 }
478
479 VOID TuiSaveScreen(PUCHAR Buffer)
480 {
481 PUCHAR ScreenMemory = (PUCHAR)TextVideoBuffer;
482 ULONG i;
483
484 for (i=0; i < (UiScreenWidth * UiScreenHeight * 2); i++)
485 {
486 Buffer[i] = ScreenMemory[i];
487 }
488 }
489
490 VOID TuiRestoreScreen(PUCHAR Buffer)
491 {
492 PUCHAR ScreenMemory = (PUCHAR)TextVideoBuffer;
493 ULONG i;
494
495 for (i=0; i < (UiScreenWidth * UiScreenHeight * 2); i++)
496 {
497 ScreenMemory[i] = Buffer[i];
498 }
499 }
500
501 VOID TuiMessageBox(PUCHAR MessageText)
502 {
503 PVOID ScreenBuffer;
504
505 // Save the screen contents
506 ScreenBuffer = MmAllocateMemory(UiScreenWidth * UiScreenHeight * 2);
507 TuiSaveScreen(ScreenBuffer);
508
509 // Display the message box
510 TuiMessageBoxCritical(MessageText);
511
512 // Restore the screen contents
513 TuiRestoreScreen(ScreenBuffer);
514 MmFreeMemory(ScreenBuffer);
515 }
516
517 VOID TuiMessageBoxCritical(PUCHAR MessageText)
518 {
519 int width = 8;
520 int height = 1;
521 int curline = 0;
522 int i , j, k;
523 int x1, x2, y1, y2;
524 char temp[260];
525 char key;
526
527 // Find the height
528 for (i=0; i<strlen(MessageText); i++)
529 {
530 if (MessageText[i] == '\n')
531 height++;
532 }
533
534 // Find the width
535 for (i=0,j=0,k=0; i<height; i++)
536 {
537 while ((MessageText[j] != '\n') && (MessageText[j] != 0))
538 {
539 j++;
540 k++;
541 }
542
543 if (k > width)
544 width = k;
545
546 k = 0;
547 j++;
548 }
549
550 // Calculate box area
551 x1 = (UiScreenWidth - (width+2))/2;
552 x2 = x1 + width + 3;
553 y1 = ((UiScreenHeight - height - 2)/2) + 1;
554 y2 = y1 + height + 4;
555
556 // Draw the box
557 TuiDrawBox(x1, y1, x2, y2, D_VERT, D_HORZ, TRUE, TRUE, ATTR(UiMessageBoxFgColor, UiMessageBoxBgColor));
558
559 // Draw the text
560 for (i=0,j=0; i<strlen(MessageText)+1; i++)
561 {
562 if ((MessageText[i] == '\n') || (MessageText[i] == 0))
563 {
564 temp[j] = 0;
565 j = 0;
566 UiDrawText(x1+2, y1+1+curline, temp, ATTR(UiMessageBoxFgColor, UiMessageBoxBgColor));
567 curline++;
568 }
569 else
570 temp[j++] = MessageText[i];
571 }
572
573 // Draw OK button
574 strcpy(temp, " OK ");
575 UiDrawText(x1+((x2-x1)/2)-3, y2-2, temp, ATTR(COLOR_BLACK, COLOR_GRAY));
576
577 // Draw status text
578 UiDrawStatusText("Press ENTER to continue");
579
580 VideoCopyOffScreenBufferToVRAM();
581
582 for (;;)
583 {
584 if (MachConsKbHit())
585 {
586 key = MachConsGetCh();
587 if(key == KEY_EXTENDED)
588 key = MachConsGetCh();
589
590 if(key == KEY_ENTER)
591 break;
592 else if(key == KEY_SPACE)
593 break;
594 else if(key == KEY_ESC)
595 break;
596 }
597
598 TuiUpdateDateTime();
599
600 VideoCopyOffScreenBufferToVRAM();
601 }
602
603 }
604
605
606 VOID TuiDrawProgressBarCenter(ULONG Position, ULONG Range, PUCHAR ProgressText)
607 {
608 ULONG Left, Top, Right, Bottom;
609 ULONG Width = 50; // Allow for 50 "bars"
610 ULONG Height = 2;
611
612 Left = (UiScreenWidth - Width - 4) / 2;
613 Right = Left + Width + 3;
614 Top = (UiScreenHeight - Height - 2) / 2;
615 Top += 2;
616 Bottom = Top + Height + 1;
617
618 TuiDrawProgressBar(Left, Top, Right, Bottom, Position, Range, ProgressText);
619 }
620
621 VOID TuiDrawProgressBar(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, ULONG Position, ULONG Range, PUCHAR ProgressText)
622 {
623 ULONG i;
624 ULONG ProgressBarWidth = (Right - Left) - 3;
625
626 // First make sure the progress bar text fits
627 UiTruncateStringEllipsis(ProgressText, ProgressBarWidth - 4);
628
629 if (Position > Range)
630 {
631 Position = Range;
632 }
633
634 // Draw the box
635 TuiDrawBox(Left, Top, Right, Bottom, VERT, HORZ, TRUE, TRUE, ATTR(UiMenuFgColor, UiMenuBgColor));
636
637 // Draw the "Loading..." text
638 //TuiDrawText(70/2, Top+1, "Loading...", ATTR(UiTextColor, UiMenuBgColor));
639 TuiDrawCenteredText(Left + 2, Top + 2, Right - 2, Top + 2, ProgressText, ATTR(UiTextColor, UiMenuBgColor));
640
641 // Draw the percent complete
642 for (i=0; i<(Position*ProgressBarWidth)/Range; i++)
643 {
644 TuiDrawText(Left+2+i, Top+2, "\xDB", ATTR(UiTextColor, UiMenuBgColor));
645 }
646
647 // Draw the rest
648 for (; i<ProgressBarWidth; i++)
649 {
650 TuiDrawText(Left+2+i, Top+2, "\xB2", ATTR(UiTextColor, UiMenuBgColor));
651 }
652
653 TuiUpdateDateTime();
654
655 VideoCopyOffScreenBufferToVRAM();
656 }
657
658 UCHAR TuiTextToColor(PUCHAR ColorText)
659 {
660 if (stricmp(ColorText, "Black") == 0)
661 return COLOR_BLACK;
662 else if (stricmp(ColorText, "Blue") == 0)
663 return COLOR_BLUE;
664 else if (stricmp(ColorText, "Green") == 0)
665 return COLOR_GREEN;
666 else if (stricmp(ColorText, "Cyan") == 0)
667 return COLOR_CYAN;
668 else if (stricmp(ColorText, "Red") == 0)
669 return COLOR_RED;
670 else if (stricmp(ColorText, "Magenta") == 0)
671 return COLOR_MAGENTA;
672 else if (stricmp(ColorText, "Brown") == 0)
673 return COLOR_BROWN;
674 else if (stricmp(ColorText, "Gray") == 0)
675 return COLOR_GRAY;
676 else if (stricmp(ColorText, "DarkGray") == 0)
677 return COLOR_DARKGRAY;
678 else if (stricmp(ColorText, "LightBlue") == 0)
679 return COLOR_LIGHTBLUE;
680 else if (stricmp(ColorText, "LightGreen") == 0)
681 return COLOR_LIGHTGREEN;
682 else if (stricmp(ColorText, "LightCyan") == 0)
683 return COLOR_LIGHTCYAN;
684 else if (stricmp(ColorText, "LightRed") == 0)
685 return COLOR_LIGHTRED;
686 else if (stricmp(ColorText, "LightMagenta") == 0)
687 return COLOR_LIGHTMAGENTA;
688 else if (stricmp(ColorText, "Yellow") == 0)
689 return COLOR_YELLOW;
690 else if (stricmp(ColorText, "White") == 0)
691 return COLOR_WHITE;
692
693 return COLOR_BLACK;
694 }
695
696 UCHAR TuiTextToFillStyle(PUCHAR FillStyleText)
697 {
698 if (stricmp(FillStyleText, "Light") == 0)
699 {
700 return LIGHT_FILL;
701 }
702 else if (stricmp(FillStyleText, "Medium") == 0)
703 {
704 return MEDIUM_FILL;
705 }
706 else if (stricmp(FillStyleText, "Dark") == 0)
707 {
708 return DARK_FILL;
709 }
710
711 return LIGHT_FILL;
712 }
713
714 VOID TuiFadeInBackdrop(VOID)
715 {
716 PPALETTE_ENTRY TuiFadePalette = NULL;
717
718 if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed())
719 {
720 TuiFadePalette = (PPALETTE_ENTRY)MmAllocateMemory(sizeof(PALETTE_ENTRY) * 64);
721
722 if (TuiFadePalette != NULL)
723 {
724 VideoSavePaletteState(TuiFadePalette, 64);
725 VideoSetAllColorsToBlack(64);
726 }
727 }
728
729 // Draw the backdrop and title box
730 TuiDrawBackdrop();
731
732 if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed() && TuiFadePalette != NULL)
733 {
734 VideoFadeIn(TuiFadePalette, 64);
735 MmFreeMemory(TuiFadePalette);
736 }
737 }
738
739 VOID TuiFadeOut(VOID)
740 {
741 PPALETTE_ENTRY TuiFadePalette = NULL;
742
743 if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed())
744 {
745 TuiFadePalette = (PPALETTE_ENTRY)MmAllocateMemory(sizeof(PALETTE_ENTRY) * 64);
746
747 if (TuiFadePalette != NULL)
748 {
749 VideoSavePaletteState(TuiFadePalette, 64);
750 }
751 }
752
753 if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed() && TuiFadePalette != NULL)
754 {
755 VideoFadeOut(64);
756 }
757
758 MachVideoSetDisplayMode(NULL, FALSE);
759
760 if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed() && TuiFadePalette != NULL)
761 {
762 VideoRestorePaletteState(TuiFadePalette, 64);
763 MmFreeMemory(TuiFadePalette);
764 }
765
766 }
767
768 BOOL TuiEditBox(PUCHAR MessageText, PUCHAR EditTextBuffer, ULONG Length)
769 {
770 int width = 8;
771 int height = 1;
772 int curline = 0;
773 int i , j, k;
774 int x1, x2, y1, y2;
775 char temp[260];
776 char key;
777 int EditBoxLine;
778 int EditBoxStartX, EditBoxEndX;
779 int EditBoxCursorX;
780 int EditBoxTextCount;
781 int EditBoxTextDisplayIndex;
782 BOOL ReturnCode;
783 PVOID ScreenBuffer;
784
785 // Save the screen contents
786 ScreenBuffer = MmAllocateMemory(UiScreenWidth * UiScreenHeight * 2);
787 TuiSaveScreen(ScreenBuffer);
788
789 // Find the height
790 for (i=0; i<strlen(MessageText); i++)
791 {
792 if (MessageText[i] == '\n')
793 height++;
794 }
795
796 // Find the width
797 for (i=0,j=0,k=0; i<height; i++)
798 {
799 while ((MessageText[j] != '\n') && (MessageText[j] != 0))
800 {
801 j++;
802 k++;
803 }
804
805 if (k > width)
806 width = k;
807
808 k = 0;
809 j++;
810 }
811
812 // Calculate box area
813 x1 = (UiScreenWidth - (width+2))/2;
814 x2 = x1 + width + 3;
815 y1 = ((UiScreenHeight - height - 2)/2) + 1;
816 y2 = y1 + height + 4;
817
818 // Draw the box
819 TuiDrawBox(x1, y1, x2, y2, D_VERT, D_HORZ, TRUE, TRUE, ATTR(UiMessageBoxFgColor, UiMessageBoxBgColor));
820
821 // Draw the text
822 for (i=0,j=0; i<strlen(MessageText)+1; i++)
823 {
824 if ((MessageText[i] == '\n') || (MessageText[i] == 0))
825 {
826 temp[j] = 0;
827 j = 0;
828 UiDrawText(x1+2, y1+1+curline, temp, ATTR(UiMessageBoxFgColor, UiMessageBoxBgColor));
829 curline++;
830 }
831 else
832 temp[j++] = MessageText[i];
833 }
834
835 EditBoxTextCount = 0;
836 EditBoxLine = y2 - 2;
837 EditBoxStartX = x1 + 3;
838 EditBoxEndX = x2 - 3;
839 UiFillArea(EditBoxStartX, EditBoxLine, EditBoxEndX, EditBoxLine, ' ', ATTR(UiEditBoxTextColor, UiEditBoxBgColor));
840
841 // Show the cursor
842 EditBoxCursorX = EditBoxStartX;
843 MachVideoSetTextCursorPosition(EditBoxCursorX, EditBoxLine);
844 MachVideoHideShowTextCursor(TRUE);
845
846 // Draw status text
847 UiDrawStatusText("Press ENTER to continue, or ESC to cancel");
848
849 VideoCopyOffScreenBufferToVRAM();
850
851 for (;;)
852 {
853 if (MachConsKbHit())
854 {
855 key = MachConsGetCh();
856 if(key == KEY_EXTENDED)
857 {
858 key = MachConsGetCh();
859 }
860
861 if(key == KEY_ENTER)
862 {
863 ReturnCode = TRUE;
864 break;
865 }
866 else if(key == KEY_ESC)
867 {
868 ReturnCode = FALSE;
869 break;
870 }
871 else if (key == KEY_BACKSPACE) // Remove a character
872 {
873 if (EditBoxTextCount)
874 {
875 EditBoxTextCount--;
876 EditTextBuffer[EditBoxTextCount] = 0;
877 }
878 else
879 {
880 beep();
881 }
882 }
883 else // Add this key to the buffer
884 {
885 if (EditBoxTextCount < Length - 1)
886 {
887 EditTextBuffer[EditBoxTextCount] = key;
888 EditBoxTextCount++;
889 EditTextBuffer[EditBoxTextCount] = 0;
890 }
891 else
892 {
893 beep();
894 }
895 }
896 }
897
898 // Draw the edit box background
899 UiFillArea(EditBoxStartX, EditBoxLine, EditBoxEndX, EditBoxLine, ' ', ATTR(UiEditBoxTextColor, UiEditBoxBgColor));
900
901 // Fill the text in
902 if (EditBoxTextCount > (EditBoxEndX - EditBoxStartX))
903 {
904 EditBoxTextDisplayIndex = EditBoxTextCount - (EditBoxEndX - EditBoxStartX);
905 EditBoxCursorX = EditBoxEndX;
906 }
907 else
908 {
909 EditBoxTextDisplayIndex = 0;
910 EditBoxCursorX = EditBoxStartX + EditBoxTextCount;
911 }
912 UiDrawText(EditBoxStartX, EditBoxLine, &EditTextBuffer[EditBoxTextDisplayIndex], ATTR(UiEditBoxTextColor, UiEditBoxBgColor));
913
914 // Move the cursor
915 MachVideoSetTextCursorPosition(EditBoxCursorX, EditBoxLine);
916
917 TuiUpdateDateTime();
918
919 VideoCopyOffScreenBufferToVRAM();
920 }
921
922 // Hide the cursor again
923 MachVideoHideShowTextCursor(FALSE);
924
925 // Restore the screen contents
926 TuiRestoreScreen(ScreenBuffer);
927 MmFreeMemory(ScreenBuffer);
928
929 return ReturnCode;
930 }