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