exectos/xtldr2/textui.c
Rafal Kupiec 83e555043a
All checks were successful
Builds / ExectOS (amd64) (push) Successful in 29s
Builds / ExectOS (i686) (push) Successful in 26s
Add documentation to private TUI-related routines
2023-12-16 11:06:56 +01:00

774 lines
23 KiB
C

/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/textui.c
* DESCRIPTION: Text console User Interface (TUI) support for XT Boot Loader
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtldr.h>
/* TUI dialog box attributes */
#define TUI_DIALOG_GENERIC_BOX 1
#define TUI_DIALOG_ERROR_BOX 2
#define TUI_DIALOG_ACTIVE_BUTTON 4
#define TUI_DIALOG_INACTIVE_BUTTON 8
#define TUI_DIALOG_ACTIVE_INPUT_FIELD 16
#define TUI_DIALOG_INACTIVE_INPUT_FIELD 32
#define TUI_DIALOG_PROGRESS_BAR 64
#define TUI_MAX_DIALOG_WIDTH 100
typedef struct _XTBL_DIALOG_HANDLE
{
UCHAR Attributes;
UCHAR DialogColor;
UCHAR TextColor;
UINT_PTR ResX;
UINT_PTR ResY;
UINT_PTR PosX;
UINT_PTR PosY;
UINT_PTR Width;
UINT_PTR Height;
} XTBL_DIALOG_HANDLE, *PXTBL_DIALOG_HANDLE;
/**
* Determines dialog box size based on enabled components and message length.
*
* @param Handle
* Supplies a pointer to the dialog box handle.
*
* @param Message
* Supplies a pointer to the message string put on the dialog box.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
BlpDetermineDialogBoxSize(IN OUT PXTBL_DIALOG_HANDLE Handle,
IN PWCHAR Message)
{
UINT_PTR Width, Height, LineLength;
SIZE_T Index, MessageLength;
UCHAR Attributes;
ULONG Mask;
/* Set minimum dialog window size */
Height = 4;
Width = 36;
/* Zero line length */
LineLength = 0;
/* Adjust window height according to enabled components */
Mask = 1;
Attributes = Handle->Attributes;
while(Mask)
{
/* Check enabled components that affect dialog window size */
switch(Attributes & Mask)
{
case TUI_DIALOG_ACTIVE_BUTTON:
case TUI_DIALOG_INACTIVE_BUTTON:
Height += 1;
break;
case TUI_DIALOG_ACTIVE_INPUT_FIELD:
case TUI_DIALOG_INACTIVE_INPUT_FIELD:
case TUI_DIALOG_PROGRESS_BAR:
Height += 2;
break;
}
/* Update component attributes mask */
Attributes &= ~Mask;
Mask <<= 1;
}
/* Check if input field is active */
if(Handle->Attributes & (TUI_DIALOG_ACTIVE_INPUT_FIELD | TUI_DIALOG_INACTIVE_INPUT_FIELD))
{
/* Set maximum dialog window width to fit input field */
Width = TUI_MAX_DIALOG_WIDTH;
}
/* Get message length and count dialog window dimensions */
MessageLength = RtlWideStringLength(Message, 0);
for(Index = 0; Index < MessageLength; Index++)
{
/* Check if this is multiline message */
if(Message[Index] == L'\n' || Index == MessageLength - 1)
{
/* Check if this line exceeds current dialog window width */
if(LineLength > Width)
{
/* Update dialog window width */
Width = LineLength;
}
/* Increase dialog window height to fit next line */
Height++;
LineLength = 0;
}
else
{
/* Increase dialog window width to fit next character */
LineLength++;
}
}
/* Add more space to dialog window to fit side borders */
Width += 4;
/* Get console resolution */
BlConsoleQueryMode(&Handle->ResX, &Handle->ResY);
/* Make sure dialog window fits in the buffer */
if(Width > TUI_MAX_DIALOG_WIDTH)
{
/* Set maximum dialog window width */
Width = TUI_MAX_DIALOG_WIDTH;
}
/* Make sure dialog window fits on the screen (X axis) and it is not too small for input field */
if(Width > (Handle->ResX - 2))
{
/* Set maximum dialog window width */
Width = Handle->ResX - 2;
}
/* Make sure dialog window fits on the screen (Y axis)*/
if(Height > (Handle->ResY - 2))
{
/* Set maximum dialog window height */
Height = Handle->ResY - 2;
}
/* Set dialog window final dimensions */
Handle->PosX = (Handle->ResX - Width) / 2;
Handle->PosY = (Handle->ResY - Height) / 2;
Handle->Width = Width;
Handle->Height = Height;
}
/**
* Draws dialog box with caption and message.
*
* @param Handle
* Supplies a pointer to the dialog box handle.
*
* @param Caption
* Specifies a caption string put on the dialog box.
*
* @param Message
* Specifies a message string put on the dialog box.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
BlpDrawDialogBox(IN OUT PXTBL_DIALOG_HANDLE Handle,
IN PWCHAR Caption,
IN PWCHAR Message)
{
WCHAR BoxLine[TUI_MAX_DIALOG_WIDTH];
PWCHAR MsgLine, LastMsgLine;
UINT_PTR Line, PosX, PosY;
SIZE_T CaptionLength;
/* Set dialog colors */
if(Handle->Attributes & TUI_DIALOG_ERROR_BOX)
{
/* Error dialog with red background and brown button */
Handle->DialogColor = EFI_TEXT_BGCOLOR_RED;
Handle->TextColor = EFI_TEXT_FGCOLOR_WHITE;
}
else
{
/* Generic dialog with blue background and cyan button */
Handle->DialogColor = EFI_TEXT_BGCOLOR_BLUE;
Handle->TextColor = EFI_TEXT_FGCOLOR_WHITE;
}
/* Get caption length */
CaptionLength = RtlWideStringLength(Caption, 0);
/* Set dialog box colors */
BlSetConsoleAttributes(Handle->DialogColor | 0x0F);
/* Iterate through dialog box lines */
for(PosY = Handle->PosY; PosY < Handle->PosY + Handle->Height; PosY++)
{
/* Set cursor position in the appropriate place */
BlSetCursorPosition(Handle->PosX, PosY);
/* Draw dialog box */
if(PosY == Handle->PosY)
{
/* Draw top line of the dialog box, starting from the left corner */
BoxLine[0] = EFI_TEXT_BOX_DOWN_RIGHT;
BoxLine[1] = EFI_TEXT_BOX_VERTICAL_LEFT;
/* Fill caption area with spaces */
for(PosX = 2; PosX < CaptionLength + 4; PosX++)
{
BoxLine[PosX] = ' ';
}
/* End caption area with vertical line */
BoxLine[CaptionLength + 4] = EFI_TEXT_BOX_VERTICAL_RIGHT;
/* Draw bottom line */
for(PosX = CaptionLength + 5; PosX < Handle->Width - 1; PosX++)
{
BoxLine[PosX] = EFI_TEXT_BOX_HORIZONTAL;
}
/* End with top right corner */
BoxLine[Handle->Width - 1] = EFI_TEXT_BOX_DOWN_LEFT;
}
else if(PosY == Handle->PosY + Handle->Height - 1)
{
/* Draw bottom line of the dialog box, starting from the left corner */
BoxLine[0] = EFI_TEXT_BOX_UP_LEFT;
/* Fill bottom with horizontal line */
for(PosX = 1; PosX < Handle->Width - 1; PosX++)
{
BoxLine[PosX] = EFI_TEXT_BOX_HORIZONTAL;
}
/* End with bottom right corner */
BoxLine[Handle->Width - 1] = EFI_TEXT_BOX_UP_RIGHT;
}
else
{
/* Draw the middle of the dialog box */
BoxLine[0] = EFI_TEXT_BOX_VERTICAL;
/* Fill dialog box with spaces */
for(PosX = 1; PosX < Handle->Width - 1; PosX++)
{
BoxLine[PosX] = ' ';
}
/* End with vertical line */
BoxLine[Handle->Width - 1] = EFI_TEXT_BOX_VERTICAL;
}
/* Add null terminator to the end of the line */
BoxLine[Handle->Width] = 0;
/* Write the line to the console */
BlConsoleWrite(BoxLine);
}
/* Write dialog box caption */
BlSetCursorPosition(Handle->PosX + 3, Handle->PosY);
BlConsolePrint(L"%S", Caption);
/* Tokenize dialog box message */
MsgLine = RtlTokenizeWideString(Message, L"\n", &LastMsgLine);
/* Iterate through message lines */
Line = 0;
while(MsgLine)
{
/* Write line in the dialog box */
BlSetCursorPosition(Handle->PosX + 2, Handle->PosY + 2 + Line);
BlConsolePrint(L"%S", MsgLine);
/* Get next line */
MsgLine = RtlTokenizeWideString(NULL, L"\n", &LastMsgLine);
Line++;
}
}
/**
* Draws an active or inactive button in the dialog box, depending on the attributes.
*
* @param Handle
* Supplies a pointer to the dialog box handle.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
BlpDrawDialogButton(IN PXTBL_DIALOG_HANDLE Handle)
{
ULONG ButtonColor, TextColor;
/* Set dialog button colors */
if(Handle->Attributes & TUI_DIALOG_ACTIVE_BUTTON)
{
/* This is an active button */
if(Handle->Attributes & TUI_DIALOG_ERROR_BOX)
{
/* This is an error dialog box */
ButtonColor = EFI_TEXT_BGCOLOR_BROWN;
TextColor = EFI_TEXT_FGCOLOR_WHITE;
}
else
{
/* This is a generic dialog box */
ButtonColor = EFI_TEXT_BGCOLOR_CYAN;
TextColor = EFI_TEXT_FGCOLOR_WHITE;
}
}
else
{
/* This is an inactive button */
ButtonColor = EFI_TEXT_BGCOLOR_LIGHTGRAY;
TextColor = EFI_TEXT_FGCOLOR_BLACK;
}
/* Disable cursor and draw dialog button */
BlConsoleDisableCursor();
BlSetConsoleAttributes(ButtonColor | TextColor);
BlSetCursorPosition(Handle->ResX / 2 - 4, Handle->PosY + Handle->Height - 2);
BlConsolePrint(L"[ OK ]");
}
/**
* Draws an active or inactive input field in the dialog box, depending on the attributes.
*
* @param Handle
* Supplies a pointer to the dialog box handle.
*
* @param InputFieldText
* Supplies a pointer to the wide char string that will be displayed in the input field.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
BlpDrawDialogInputField(IN PXTBL_DIALOG_HANDLE Handle,
IN PWCHAR InputFieldText)
{
WCHAR InputField[TUI_MAX_DIALOG_WIDTH];
ULONG InputColor, TextColor;
UINT_PTR Index, Position;
/* Set dialog button colors */
if(Handle->Attributes & TUI_DIALOG_ACTIVE_INPUT_FIELD)
{
/* This is an active input field */
if(Handle->Attributes & TUI_DIALOG_ERROR_BOX)
{
/* This is an error dialog box */
InputColor = EFI_TEXT_BGCOLOR_BROWN;
TextColor = EFI_TEXT_FGCOLOR_WHITE;
}
else
{
/* This is a generic dialog box */
InputColor = EFI_TEXT_BGCOLOR_CYAN;
TextColor = EFI_TEXT_FGCOLOR_WHITE;
}
}
else
{
/* This is an inactive input field */
InputColor = EFI_TEXT_BGCOLOR_LIGHTGRAY;
TextColor = EFI_TEXT_FGCOLOR_BLACK;
}
/* Set progress bar color and position */
BlSetConsoleAttributes(InputColor | TextColor);
Position = (Handle->Attributes & (TUI_DIALOG_ACTIVE_BUTTON | TUI_DIALOG_INACTIVE_BUTTON)) ? 4 : 3;
BlSetCursorPosition(Handle->PosX + 4, Handle->PosY + Handle->Height - Position);
/* Draw input field */
for(Index = 0; Index < Handle->Width - 8; Index++)
{
/* Fill input field with spaces */
InputField[Index] = L' ';
}
/* Disable cursor and write input field to console */
BlConsoleDisableCursor();
BlConsoleWrite(InputField);
/* Write input field text */
BlSetCursorPosition(Handle->PosX + 4, Handle->PosY + Handle->Height - Position);
BlConsoleWrite(InputFieldText);
/* Check if this is an active input field */
if(Handle->Attributes & TUI_DIALOG_ACTIVE_INPUT_FIELD)
{
/* Enable cursor for active input field */
BlConsoleEnableCursor();
}
}
/**
* Draws a progress bar component in the dialog box.
*
* @param Handle
* Supplies a pointer to the dialog box handle.
*
* @param Percentage
* Specifies the percentage progress of the progress bar.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
BlpDrawDialogProgressBar(IN PXTBL_DIALOG_HANDLE Handle,
IN UCHAR Percentage)
{
UINT_PTR Index, ProgressLength, ProgressBarLength;
WCHAR ProgressBar[TUI_MAX_DIALOG_WIDTH];
UINT_PTR Position;
/* Determine progress bar length and calculate progress */
ProgressBarLength = Handle->Width - 8;
ProgressLength = (ProgressBarLength * Percentage) / 100;
/* Set progress bar color and position */
BlSetConsoleAttributes(EFI_TEXT_FGCOLOR_YELLOW);
Position = (Handle->Attributes & (TUI_DIALOG_ACTIVE_BUTTON | TUI_DIALOG_INACTIVE_BUTTON)) ? 4 : 3;
BlSetCursorPosition(Handle->PosX + 4, Handle->PosY + Handle->Height - Position);
/* Draw progress bar */
for(Index = 0; Index < ProgressBarLength; Index++)
{
/* Fill progress bar */
if(Index < ProgressLength)
{
/* Fill with full block */
ProgressBar[Index] = EFI_TEXT_BOX_FULL_BLOCK;
}
else
{
/* Fill with light block */
ProgressBar[Index] = EFI_TEXT_BOX_LIGHT_BLOCK;
}
}
/* Terminate progress bar string */
ProgressBar[Index] = 0;
/* Disable cursor and write progress bar to console */
BlConsoleDisableCursor();
BlConsoleWrite(ProgressBar);
}
XTCDECL
VOID
BlDisplayErrorDialog(IN PWCHAR Caption,
IN PWCHAR Message)
{
XTBL_DIALOG_HANDLE Handle;
EFI_INPUT_KEY Key;
UINT_PTR Index;
/* Set dialog window attributes */
Handle.Attributes = TUI_DIALOG_ERROR_BOX | TUI_DIALOG_ACTIVE_BUTTON;
/* Determine dialog window size and position */
BlpDetermineDialogBoxSize(&Handle, Message);
/* Disable cursor and draw dialog box */
BlConsoleDisableCursor();
BlpDrawDialogBox(&Handle, Caption, Message);
/* Draw active button */
BlpDrawDialogButton(&Handle);
/* Initialize key stroke */
Key.ScanCode = 0;
Key.UnicodeChar = 0;
/* Wait until ENTER or ESC key is pressed */
while(Key.ScanCode != 0x17 && Key.UnicodeChar != 0x0D)
{
/* Wait for key press and read key stroke */
EfiSystemTable->BootServices->WaitForEvent(1, &EfiSystemTable->ConIn->WaitForKey, &Index);
EfiSystemTable->ConIn->ReadKeyStroke(EfiSystemTable->ConIn, &Key);
EfiSystemTable->ConIn->Reset(EfiSystemTable->ConIn, FALSE);
}
/* Clear screen to remove dialog box */
BlSetConsoleAttributes(EFI_TEXT_BGCOLOR_BLACK | EFI_TEXT_FGCOLOR_LIGHTGRAY);
BlConsoleClearScreen();
}
XTCDECL
VOID
BlDisplayInfoDialog(IN PWCHAR Caption,
IN PWCHAR Message)
{
XTBL_DIALOG_HANDLE Handle;
EFI_INPUT_KEY Key;
UINT_PTR Index;
/* Set dialog window attributes */
Handle.Attributes = TUI_DIALOG_GENERIC_BOX | TUI_DIALOG_ACTIVE_BUTTON;
/* Determine dialog window size and position */
BlpDetermineDialogBoxSize(&Handle, Message);
/* Disable cursor and draw dialog box */
BlConsoleDisableCursor();
BlpDrawDialogBox(&Handle, Caption, Message);
/* Draw active button */
BlpDrawDialogButton(&Handle);
/* Initialize key stroke */
Key.ScanCode = 0;
Key.UnicodeChar = 0;
/* Wait until ENTER or ESC key is pressed */
while(Key.ScanCode != 0x17 && Key.UnicodeChar != 0x0D)
{
/* Wait for key press and read key stroke */
EfiSystemTable->BootServices->WaitForEvent(1, &EfiSystemTable->ConIn->WaitForKey, &Index);
EfiSystemTable->ConIn->ReadKeyStroke(EfiSystemTable->ConIn, &Key);
EfiSystemTable->ConIn->Reset(EfiSystemTable->ConIn, FALSE);
}
/* Clear screen to remove dialog box */
BlSetConsoleAttributes(EFI_TEXT_BGCOLOR_BLACK | EFI_TEXT_FGCOLOR_LIGHTGRAY);
BlConsoleClearScreen();
}
XTCDECL
VOID
BlDisplayInputDialog(IN PWCHAR Caption,
IN PWCHAR Message,
IN PWCHAR InputFieldBuffer)
{
XTBL_DIALOG_HANDLE Handle;
SIZE_T InputFieldLength, TextCursorPosition, TextIndex, TextPosition;
EFI_INPUT_KEY Key;
UINT_PTR Index;
/* Set dialog window attributes */
Handle.Attributes = TUI_DIALOG_GENERIC_BOX | TUI_DIALOG_ACTIVE_INPUT_FIELD | TUI_DIALOG_INACTIVE_BUTTON;
/* Determine dialog window size and position */
BlpDetermineDialogBoxSize(&Handle, Message);
/* Disable cursor and draw dialog box */
BlConsoleDisableCursor();
BlpDrawDialogBox(&Handle, Caption, Message);
/* Draw inactive button */
BlpDrawDialogButton(&Handle);
/* Draw active input field */
BlpDrawDialogInputField(&Handle, InputFieldBuffer);
/* Initialize key stroke */
Key.ScanCode = 0;
Key.UnicodeChar = 0;
/* Determine input field length */
InputFieldLength = RtlWideStringLength(InputFieldBuffer, 0);
if(InputFieldLength > Handle.Width - 8)
{
InputFieldLength = Handle.Width - 8;
}
/* Start at first character */
TextPosition = 0;
BlSetCursorPosition(Handle.PosX + 4 + TextPosition, Handle.PosY + Handle.Height - 4);
/* Wait until ENTER or ESC key is pressed */
while(TRUE)
{
/* Wait for key press and read key stroke */
EfiSystemTable->BootServices->WaitForEvent(1, &EfiSystemTable->ConIn->WaitForKey, &Index);
EfiSystemTable->ConIn->ReadKeyStroke(EfiSystemTable->ConIn, &Key);
EfiSystemTable->ConIn->Reset(EfiSystemTable->ConIn, FALSE);
/* Check key press scan code */
if(Key.ScanCode == 0x17)
{
/* ESC key pressed, return */
break;
}
else if(Key.UnicodeChar == 0x09)
{
/* TAB key pressed, toggle input field and button */
Handle.Attributes ^= (TUI_DIALOG_ACTIVE_INPUT_FIELD | TUI_DIALOG_INACTIVE_INPUT_FIELD);
Handle.Attributes ^= (TUI_DIALOG_ACTIVE_BUTTON | TUI_DIALOG_INACTIVE_BUTTON);
}
else if(Key.ScanCode == 0x03)
{
/* RIGHT key pressed, move cursor forward */
if(Handle.Attributes & TUI_DIALOG_ACTIVE_INPUT_FIELD && TextPosition < InputFieldLength)
{
TextPosition++;
}
}
else if(Key.ScanCode == 0x04)
{
/* LEFT key pressed, move cursor back */
if(Handle.Attributes & TUI_DIALOG_ACTIVE_INPUT_FIELD && TextPosition > 0)
{
TextPosition--;
}
}
else if(Key.ScanCode == 0x05)
{
/* HOME key pressed, move cursor to the beginning */
if(Handle.Attributes & TUI_DIALOG_ACTIVE_INPUT_FIELD)
{
TextPosition = 0;
}
}
else if(Key.ScanCode == 0x06)
{
/* END key pressed, move cursor to the end */
if(Handle.Attributes & TUI_DIALOG_ACTIVE_INPUT_FIELD)
{
TextPosition = InputFieldLength;
}
}
else if(Key.ScanCode == 0x08)
{
/* DELETE key pressed, delete character */
if(Handle.Attributes & TUI_DIALOG_ACTIVE_INPUT_FIELD)
{
if(InputFieldLength > 0 && TextPosition < InputFieldLength)
{
RtlMoveMemory(InputFieldBuffer + TextPosition, InputFieldBuffer + TextPosition + 1, InputFieldLength - TextPosition);
InputFieldLength--;
InputFieldBuffer[InputFieldLength] = 0;
}
}
}
else if(Key.UnicodeChar == 0x08)
{
/* BACKSPACE key pressed, delete character */
if(Handle.Attributes & TUI_DIALOG_ACTIVE_INPUT_FIELD)
{
if(InputFieldLength > 0 && TextPosition > 0 && TextPosition <= InputFieldLength)
{
TextPosition--;
RtlMoveMemory(InputFieldBuffer + TextPosition, InputFieldBuffer + TextPosition + 1, InputFieldLength - TextPosition);
InputFieldLength--;
InputFieldBuffer[InputFieldLength] = 0;
}
}
}
else if(Key.UnicodeChar == 0x0D)
{
/* ENTER key pressed */
}
else
{
/* Other key pressed, add character to the buffer */
if(Handle.Attributes & TUI_DIALOG_ACTIVE_INPUT_FIELD && Key.UnicodeChar != 0)
{
if(InputFieldLength < Handle.Width - 8 - 1 && TextPosition < Handle.Width - 8 - 1)
{
RtlMoveMemory(InputFieldBuffer + TextPosition + 1, InputFieldBuffer + TextPosition, InputFieldLength - TextPosition);
InputFieldBuffer[TextPosition] = Key.UnicodeChar;
TextPosition++;
InputFieldLength++;
InputFieldBuffer[InputFieldLength] = 0;
}
}
}
if(TextPosition > (Handle.Width - 8))
{
TextIndex = TextPosition - (Handle.Width - 8);
TextCursorPosition = Handle.Width - 8;
}
else
{
TextIndex = 0;
TextCursorPosition = TextPosition;
}
/* Redraw input field and button */
BlpDrawDialogButton(&Handle);
BlpDrawDialogInputField(&Handle, &InputFieldBuffer[TextIndex]);
if(Handle.Attributes & TUI_DIALOG_ACTIVE_INPUT_FIELD)
{
BlSetCursorPosition(Handle.PosX + 4 + TextCursorPosition, Handle.PosY + Handle.Height - 4);
}
}
/* Clear screen to remove dialog box */
BlSetConsoleAttributes(EFI_TEXT_BGCOLOR_BLACK | EFI_TEXT_FGCOLOR_LIGHTGRAY);
BlConsoleClearScreen();
}
XTCDECL
XTBL_DIALOG_HANDLE
BlDisplayProgressDialog(IN PWCHAR Caption,
IN PWCHAR Message,
IN UCHAR Percentage)
{
XTBL_DIALOG_HANDLE Handle;
/* Set dialog window attributes */
Handle.Attributes = TUI_DIALOG_GENERIC_BOX | TUI_DIALOG_PROGRESS_BAR;
/* Determine dialog window size and position */
BlpDetermineDialogBoxSize(&Handle, Message);
/* Disable cursor and draw dialog box */
BlConsoleDisableCursor();
BlpDrawDialogBox(&Handle, Caption, Message);
/* Draw active button */
BlpDrawDialogProgressBar(&Handle, Percentage);
/* Return dialog handle */
return Handle;
}
// TODO: Common routine for printing text on dialog window
XTCDECL
VOID
BlUpdateProgressBar(IN PXTBL_DIALOG_HANDLE Handle,
IN PWCHAR Message,
IN UCHAR Percentage)
{
SIZE_T Index, Length;
/* Check if message needs an update */
if(Message != NULL)
{
/* Determine message length */
Length = RtlWideStringLength(Message, 0);
/* Update message in the dialog box */
BlSetCursorPosition(Handle->PosX + 2, Handle->PosY + 2);
BlSetConsoleAttributes(Handle->DialogColor | Handle->TextColor);
BlConsolePrint(L"%S", Message);
if(Length < Handle->Width - 4)
{
for(Index = Length; Index < Handle->Width - 4; Index++)
{
BlConsolePrint(L" ");
}
}
}
/* Update progress bar */
BlpDrawDialogProgressBar(Handle, Percentage);
}