[FREELDR] Improve progress bar support, adapted from Inbv.

- Improve accuracy/progression smoothness when loading drivers.
- Allow changing text and percentage independently.
This commit is contained in:
Hermès Bélusca-Maïto 2022-02-14 02:28:53 +01:00
parent c14440ee57
commit c322610f6e
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
14 changed files with 500 additions and 226 deletions

View file

@ -111,13 +111,12 @@ RamDiskLoadVirtualFile(
ULONG RamFileId;
ULONG ChunkSize, Count;
ULONGLONG TotalRead;
PCHAR MsgBuffer = "Loading RamDisk...";
ULONG PercentPerChunk, Percent;
FILEINFORMATION Information;
LARGE_INTEGER Position;
/* Display progress */
UiDrawProgressBarCenter(1, 100, MsgBuffer);
UiDrawProgressBarCenter("Loading RamDisk...");
/* Try opening the Ramdisk file */
Status = FsOpenFile(FileName, DefaultPath, OpenReadOnly, &RamFileId);
@ -135,8 +134,8 @@ RamDiskLoadVirtualFile(
/* FIXME: For now, limit RAM disks to 4GB */
if (Information.EndingAddress.HighPart != 0)
{
UiMessageBox("RAM disk too big.");
ArcClose(RamFileId);
UiMessageBox("RAM disk too big.");
return ENOMEM;
}
RamDiskFileSize = Information.EndingAddress.QuadPart;
@ -145,20 +144,22 @@ RamDiskLoadVirtualFile(
/* Allocate memory for it */
ChunkSize = 8 * 1024 * 1024;
if (RamDiskFileSize < ChunkSize)
Percent = PercentPerChunk = 0;
PercentPerChunk = 0;
else
Percent = PercentPerChunk = 100 / (RamDiskFileSize / ChunkSize);
PercentPerChunk = 100 * ChunkSize / RamDiskFileSize;
RamDiskBase = MmAllocateMemoryWithType(RamDiskFileSize, LoaderXIPRom);
if (!RamDiskBase)
{
UiMessageBox("Failed to allocate memory for RAM disk.");
RamDiskFileSize = 0;
ArcClose(RamFileId);
UiMessageBox("Failed to allocate memory for RAM disk.");
return ENOMEM;
}
/*
* Read it in chunks
*/
Percent = 0;
for (TotalRead = 0; TotalRead < RamDiskFileSize; TotalRead += ChunkSize)
{
/* Check if we're at the last chunk */
@ -168,8 +169,8 @@ RamDiskLoadVirtualFile(
ChunkSize = (ULONG)(RamDiskFileSize - TotalRead);
}
/* Draw progress */
UiDrawProgressBarCenter(Percent, 100, MsgBuffer);
/* Update progress */
UiUpdateProgressBar(Percent, NULL);
Percent += PercentPerChunk;
/* Copy the contents */
@ -194,6 +195,7 @@ RamDiskLoadVirtualFile(
return ((Status != ESUCCESS) ? Status : EIO);
}
}
UiUpdateProgressBar(100, NULL);
ArcClose(RamFileId);

View file

@ -95,12 +95,74 @@ VOID UiInfoBox(PCSTR MessageText); // Displays a i
VOID UiMessageBox(PCSTR Format, ...); // Displays a message box on the screen with an ok button
VOID UiMessageBoxCritical(PCSTR MessageText); // Displays a message box on the screen with an ok button using no system resources
/* Loading Progress-Bar Functions ********************************************/
/*
* Loading progress bar, based on the one from NTOS Inbv.
* Supports progress within sub-ranges, used when loading
* with an unknown number of steps.
*/
typedef struct _UI_PROGRESS_BAR
{
// UI_PROGRESS_STATE
struct
{
ULONG Floor;
// ULONG Ceiling;
ULONG Bias;
} State;
// BT_PROGRESS_INDICATOR
struct
{
ULONG Count;
ULONG Expected;
ULONG Percentage;
} Indicator;
ULONG Left;
ULONG Top;
ULONG Right;
ULONG Bottom;
// ULONG Width; // == Right - Left + 1;
BOOLEAN Show;
} UI_PROGRESS_BAR, *PUI_PROGRESS_BAR;
extern UI_PROGRESS_BAR UiProgressBar;
VOID
UiInitProgressBar(
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ PCSTR ProgressText);
/* Indicate loading progress without any specific number of steps */
VOID
UiIndicateProgress(VOID);
/* Set a progress loading percentage range */
VOID
UiSetProgressBarSubset(
_In_ ULONG Floor,
_In_ ULONG Ceiling);
/* Update the loading progress percentage within a selected range */
VOID
UiUpdateProgressBar(
_In_ ULONG Percentage,
_In_opt_ PCSTR ProgressText);
VOID
UiSetProgressBarText(
_In_ PCSTR ProgressText);
/* Draws the progress bar showing nPos percent filled */
VOID
UiDrawProgressBarCenter(
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText);
_In_ PCSTR ProgressText);
/* Draws the progress bar showing nPos percent filled */
VOID
@ -109,9 +171,8 @@ UiDrawProgressBar(
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText);
_In_ PCSTR ProgressText);
// Displays all the message boxes in a given section.
VOID
@ -123,14 +184,11 @@ UiShowMessageBoxesInArgv(
IN ULONG Argc,
IN PCHAR Argv[]);
VOID UiEscapeString(PCHAR String); // Processes a string and changes all occurrences of "\n" to '\n'
BOOLEAN UiEditBox(PCSTR MessageText, PCHAR EditTextBuffer, ULONG Length);
UCHAR UiTextToColor(PCSTR ColorText); // Converts the text color into it's equivalent color value
UCHAR UiTextToFillStyle(PCSTR FillStyleText); // Converts the text fill into it's equivalent fill value
VOID UiTruncateStringEllipsis(PCHAR StringText, ULONG MaxChars); // Truncates a string to MaxChars by adding an ellipsis on the end '...'
VOID UiFadeInBackdrop(VOID); // Draws the backdrop and fades the screen in
VOID UiFadeOut(VOID); // Fades the screen out
@ -200,8 +258,23 @@ typedef struct tagUIVTBL
VOID (*UpdateDateTime)(VOID);
VOID (*MessageBox)(PCSTR MessageText);
VOID (*MessageBoxCritical)(PCSTR MessageText);
VOID (*DrawProgressBarCenter)(ULONG Position, ULONG Range, PCHAR ProgressText);
VOID (*DrawProgressBar)(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, ULONG Position, ULONG Range, PCHAR ProgressText);
VOID (*DrawProgressBarCenter)(
_In_ PCSTR ProgressText);
VOID (*DrawProgressBar)(
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ PCSTR ProgressText);
VOID (*SetProgressBarText)(
_In_ PCSTR ProgressText);
VOID (*TickProgressBar)(
_In_ ULONG SubPercentTimes100);
BOOLEAN (*EditBox)(PCSTR MessageText, PCHAR EditTextBuffer, ULONG Length);
UCHAR (*TextToColor)(PCSTR ColorText);
UCHAR (*TextToFillStyle)(PCSTR FillStyleText);

View file

@ -13,12 +13,18 @@
VOID MiniTuiDrawBackdrop(VOID);
VOID MiniTuiDrawStatusText(PCSTR StatusText);
VOID
MiniTuiSetProgressBarText(
_In_ PCSTR ProgressText);
VOID
MiniTuiTickProgressBar(
_In_ ULONG SubPercentTimes100);
/* Draws the progress bar showing nPos percent filled */
VOID
MiniTuiDrawProgressBarCenter(
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText);
_In_ PCSTR ProgressText);
/* Draws the progress bar showing nPos percent filled */
VOID
@ -27,9 +33,7 @@ MiniTuiDrawProgressBar(
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText);
_In_ PCSTR ProgressText);
/* Menu Functions ************************************************************/

View file

@ -50,12 +50,20 @@ VOID NoUiUpdateDateTime(VOID);
VOID NoUiMessageBox(PCSTR MessageText);
VOID NoUiMessageBoxCritical(PCSTR MessageText);
/* Loading Progress-Bar Functions ********************************************/
VOID
NoUiSetProgressBarText(
_In_ PCSTR ProgressText);
VOID
NoUiTickProgressBar(
_In_ ULONG SubPercentTimes100);
/* Draws the progress bar showing nPos percent filled */
VOID
NoUiDrawProgressBarCenter(
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText);
_In_ PCSTR ProgressText);
/* Draws the progress bar showing nPos percent filled */
VOID
@ -64,9 +72,8 @@ NoUiDrawProgressBar(
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText);
_In_ PCSTR ProgressText);
BOOLEAN NoUiEditBox(PCSTR MessageText, PCHAR EditTextBuffer, ULONG Length);
UCHAR NoUiTextToColor(PCSTR ColorText);

View file

@ -25,6 +25,10 @@ INT
TuiPrintf(
_In_ PCSTR Format, ...);
VOID
TuiTruncateStringEllipsis(
_Inout_z_ PSTR StringText,
_In_ ULONG MaxChars);
#define TUI_TITLE_BOX_CHAR_HEIGHT 5
@ -72,24 +76,6 @@ VOID TuiRestoreScreen(PUCHAR Buffer); // Restores the
VOID TuiMessageBox(PCSTR MessageText); // Displays a message box on the screen with an ok button
VOID TuiMessageBoxCritical(PCSTR MessageText); // Displays a message box on the screen with an ok button using no system resources
/* Draws the progress bar showing nPos percent filled */
VOID
TuiDrawProgressBarCenter(
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText);
/* Draws the progress bar showing nPos percent filled */
VOID
TuiDrawProgressBar(
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText);
BOOLEAN TuiEditBox(PCSTR MessageText, PCHAR EditTextBuffer, ULONG Length);
UCHAR TuiTextToColor(PCSTR ColorText); // Converts the text color into it's equivalent color value
UCHAR TuiTextToFillStyle(PCSTR FillStyleText); // Converts the text fill into it's equivalent fill value

View file

@ -107,7 +107,7 @@ LoadAndBootLinux(
UiDrawBackdrop();
UiDrawStatusText(LinuxBootDescription);
UiDrawProgressBarCenter(0, 100, LinuxBootDescription);
UiDrawProgressBarCenter(LinuxBootDescription);
/* Find all the message box settings and run them */
UiShowMessageBoxesInArgv(Argc, Argv);
@ -445,7 +445,7 @@ static BOOLEAN LinuxReadKernel(ULONG LinuxKernelFile)
BytesLoaded += LINUX_READ_CHUNK_SIZE;
LoadAddress = (PVOID)((ULONG_PTR)LoadAddress + LINUX_READ_CHUNK_SIZE);
UiDrawProgressBarCenter(BytesLoaded, LinuxKernelSize + LinuxInitrdSize, LinuxBootDescription);
UiUpdateProgressBar(BytesLoaded * 100 / (LinuxKernelSize + LinuxInitrdSize), NULL);
}
return TRUE;
@ -540,7 +540,7 @@ static BOOLEAN LinuxReadInitrd(ULONG LinuxInitrdFile)
BytesLoaded += LINUX_READ_CHUNK_SIZE;
LinuxInitrdLoadAddress = (PVOID)((ULONG_PTR)LinuxInitrdLoadAddress + LINUX_READ_CHUNK_SIZE);
UiDrawProgressBarCenter(BytesLoaded + LinuxKernelSize, LinuxInitrdSize + LinuxKernelSize, LinuxBootDescription);
UiUpdateProgressBar((BytesLoaded + LinuxKernelSize) * 100 / (LinuxInitrdSize + LinuxKernelSize), NULL);
}
return TRUE;

View file

@ -493,7 +493,7 @@ LoadReactOSSetup(
/* Let the user know we started loading */
UiDrawBackdrop();
UiDrawStatusText("Setup is loading...");
UiDrawProgressBarCenter(1, 100, "Loading ReactOS Setup...");
UiDrawProgressBarCenter("Loading ReactOS Setup...");
/* Retrieve the system path */
*BootPath = ANSI_NULL;
@ -743,7 +743,7 @@ LoadReactOSSetup(
SetupBlock->Flags = SETUPLDR_TEXT_MODE;
/* Load the "setupreg.hiv" setup system hive */
if (!SosEnabled) UiDrawProgressBarCenter(15, 100, "Loading setup system hive...");
UiUpdateProgressBar(15, "Loading setup system hive...");
Success = WinLdrInitSystemHive(LoaderBlock, BootPath, TRUE);
TRACE("Setup SYSTEM hive %s\n", (Success ? "loaded" : "not loaded"));
/* Bail out if failure */

View file

@ -66,7 +66,8 @@ NtLdrOutputLoadMsg(
RtlStringCbPrintfA(ProgressString, sizeof(ProgressString),
"Loading %s...",
(Description ? Description : FileName));
// UiDrawProgressBarCenter(1, 100, ProgressString);
// UiSetProgressBarText(ProgressString);
// UiIndicateProgress();
UiDrawStatusText(ProgressString);
}
}
@ -379,12 +380,12 @@ WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
// Paths are relative (FIXME: Are they always relative?)
// Load it
UiIndicateProgress();
Success = WinLdrLoadDeviceDriver(&LoaderBlock->LoadOrderListHead,
BootPath,
&BootDriver->FilePath,
0,
&BootDriver->LdrEntry);
if (Success)
{
// Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore
@ -503,7 +504,7 @@ LoadModule(
PVOID BaseAddress;
RtlStringCbPrintfA(ProgressString, sizeof(ProgressString), "Loading %s...", File);
if (!SosEnabled) UiDrawProgressBarCenter(Percentage, 100, ProgressString);
UiUpdateProgressBar(Percentage, ProgressString);
RtlStringCbCopyA(FullFileName, sizeof(FullFileName), Path);
RtlStringCbCatA(FullFileName, sizeof(FullFileName), File);
@ -609,7 +610,7 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion,
/* Load the HAL */
HalBase = LoadModule(LoaderBlock, DirPath, HalFileName,
"hal.dll", LoaderHalCode, &HalDTE, 45);
"hal.dll", LoaderHalCode, &HalDTE, 35);
if (!HalBase)
{
ERR("LoadModule('%s') failed\n", HalFileName);
@ -684,7 +685,7 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion,
/* Load the KD DLL. Override its base DLL name to the default "KDCOM.DLL". */
KdDllBase = LoadModule(LoaderBlock, DirPath, KdDllName,
"kdcom.dll", LoaderSystemCode, &KdDllDTE, 60);
"kdcom.dll", LoaderSystemCode, &KdDllDTE, 40);
if (!KdDllBase)
{
/* If we failed to load a custom KD DLL, fall back to the standard one */
@ -697,7 +698,7 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion,
RtlStringCbCopyA(KdDllName, sizeof(KdDllName), "kdcom.dll");
KdDllBase = LoadModule(LoaderBlock, DirPath, KdDllName,
"kdcom.dll", LoaderSystemCode, &KdDllDTE, 60);
"kdcom.dll", LoaderSystemCode, &KdDllDTE, 40);
}
if (!KdDllBase)
@ -939,7 +940,7 @@ LoadAndBootWindows(
/* Let the user know we started loading */
UiDrawBackdrop();
UiDrawStatusText("Loading...");
UiDrawProgressBarCenter(1, 100, "Loading NT...");
UiDrawProgressBarCenter("Loading NT...");
/* Retrieve the system path */
*BootPath = ANSI_NULL;
@ -1043,7 +1044,7 @@ LoadAndBootWindows(
AllocateAndInitLPB(OperatingSystemVersion, &LoaderBlock);
/* Load the system hive */
if (!SosEnabled) UiDrawProgressBarCenter(15, 100, "Loading system hive...");
UiUpdateProgressBar(15, "Loading system hive...");
Success = WinLdrInitSystemHive(LoaderBlock, BootPath, FALSE);
TRACE("SYSTEM hive %s\n", (Success ? "loaded" : "not loaded"));
/* Bail out if failure */
@ -1101,7 +1102,7 @@ LoadAndBootWindowsCommon(
SystemRoot = strstr(BootPath, "\\");
/* Detect hardware */
if (!SosEnabled) UiDrawProgressBarCenter(20, 100, "Detecting hardware...");
UiUpdateProgressBar(20, "Detecting hardware...");
LoaderBlock->ConfigurationRoot = MachHwDetect();
/* Initialize the PE loader import-DLL callback, so that we can obtain
@ -1130,11 +1131,15 @@ LoadAndBootWindowsCommon(
**** WE HAVE NOW REACHED THE POINT OF NO RETURN !!
****/
UiSetProgressBarSubset(40, 90); // NTOS goes from 25 to 75%
/* Load boot drivers */
if (!SosEnabled) UiDrawProgressBarCenter(100, 100, "Loading boot drivers...");
UiSetProgressBarText("Loading boot drivers...");
Success = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
TRACE("Boot drivers loading %s\n", Success ? "successful" : "failed");
UiSetProgressBarSubset(0, 100);
/* Reset the PE loader import-DLL callback */
PeLdrImportDllLoadCallback = NULL;
@ -1145,6 +1150,8 @@ LoadAndBootWindowsCommon(
BootPath,
OperatingSystemVersion);
UiUpdateProgressBar(100, NULL);
/* Save entry-point pointer and Loader block VAs */
KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint;
LoaderBlockVA = PaToVa(LoaderBlock);

View file

@ -88,6 +88,8 @@ UiResetForSOS(VOID)
UiVtbl = MiniTuiVtbl;
UiVtbl.Initialize();
#endif
/* Disable the progress bar */
UiProgressBar.Show = FALSE;
}
VOID

View file

@ -111,28 +111,6 @@ UiMessageBoxCritical(IN PCSTR MessageText)
TuiPrintf(MessageText);
}
VOID
UiDrawProgressBarCenter(
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText)
{
MiniTuiDrawProgressBarCenter(Position, Range, ProgressText);
}
VOID
UiDrawProgressBar(
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText)
{
MiniTuiDrawProgressBar(Left, Top, Right, Bottom, Position, Range, ProgressText);
}
VOID
UiShowMessageBoxesInSection(
IN ULONG_PTR SectionId)
@ -148,15 +126,6 @@ UiShowMessageBoxesInArgv(
return;
}
VOID
UiTruncateStringEllipsis(IN PCHAR StringText,
IN ULONG MaxChars)
{
/* If it's too large, just add some ellipsis past the maximum */
if (strlen(StringText) > MaxChars)
strcpy(&StringText[MaxChars - 3], "...");
}
VOID
UiDrawMenu(
_In_ PUI_MENU_INFO MenuInfo)

View file

@ -31,11 +31,85 @@ VOID MiniTuiDrawStatusText(PCSTR StatusText)
#endif // _M_ARM
/*static*/ VOID
MiniTuiSetProgressBarText(
_In_ PCSTR ProgressText)
{
ULONG ProgressBarWidth;
CHAR ProgressString[256];
/* Make sure the progress bar is enabled */
ASSERT(UiProgressBar.Show);
/* Calculate the width of the bar proper */
ProgressBarWidth = UiProgressBar.Right - UiProgressBar.Left + 1;
/* First make sure the progress bar text fits */
RtlStringCbCopyA(ProgressString, sizeof(ProgressString), ProgressText);
TuiTruncateStringEllipsis(ProgressString, ProgressBarWidth);
/* Clear the text area */
TuiFillArea(UiProgressBar.Left, UiProgressBar.Top,
UiProgressBar.Right,
#ifdef NTLDR_PROGRESSBAR
UiProgressBar.Bottom - 1,
#else // BTMGR_PROGRESSBAR
UiProgressBar.Bottom - 2, // One empty line between text and bar.
#endif
' ', ATTR(UiTextColor, UiMenuBgColor));
/* Draw the "Loading..." text */
TuiDrawCenteredText(UiProgressBar.Left, UiProgressBar.Top,
UiProgressBar.Right,
#ifdef NTLDR_PROGRESSBAR
UiProgressBar.Bottom - 1,
#else // BTMGR_PROGRESSBAR
UiProgressBar.Bottom - 2, // One empty line between text and bar.
#endif
ProgressString, ATTR(UiTextColor, UiMenuBgColor));
}
/*static*/ VOID
MiniTuiTickProgressBar(
_In_ ULONG SubPercentTimes100)
{
ULONG ProgressBarWidth;
ULONG FillCount;
/* Make sure the progress bar is enabled */
ASSERT(UiProgressBar.Show);
ASSERT(SubPercentTimes100 <= (100 * 100));
/* Calculate the width of the bar proper */
ProgressBarWidth = UiProgressBar.Right - UiProgressBar.Left + 1;
/* Compute fill count */
// FillCount = (ProgressBarWidth * Position) / Range;
FillCount = ProgressBarWidth * SubPercentTimes100 / (100 * 100);
/* Fill the progress bar */
/* Draw the percent complete -- Use the fill character */
if (FillCount > 0)
{
TuiFillArea(UiProgressBar.Left, UiProgressBar.Bottom,
UiProgressBar.Left + FillCount - 1, UiProgressBar.Bottom,
'\xDB', ATTR(UiTextColor, UiMenuBgColor));
}
/* Fill the remaining with blanks */
TuiFillArea(UiProgressBar.Left + FillCount, UiProgressBar.Bottom,
UiProgressBar.Right, UiProgressBar.Bottom,
' ', ATTR(UiTextColor, UiMenuBgColor));
#ifndef _M_ARM
TuiUpdateDateTime();
VideoCopyOffScreenBufferToVRAM();
#endif
}
VOID
MiniTuiDrawProgressBarCenter(
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText)
_In_ PCSTR ProgressText)
{
ULONG Left, Top, Right, Bottom, Width, Height;
@ -55,7 +129,7 @@ MiniTuiDrawProgressBarCenter(
Bottom = Top + Height - 1;
/* Draw the progress bar */
MiniTuiDrawProgressBar(Left, Top, Right, Bottom, Position, Range, ProgressText);
MiniTuiDrawProgressBar(Left, Top, Right, Bottom, ProgressText);
}
VOID
@ -64,54 +138,9 @@ MiniTuiDrawProgressBar(
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText)
_In_ PCSTR ProgressText)
{
ULONG ProgressBarWidth, i;
/* Calculate the width of the bar proper */
ProgressBarWidth = Right - Left + 1;
/* Clip the position */
if (Position > Range)
Position = Range;
/* First make sure the progress bar text fits */
UiTruncateStringEllipsis(ProgressText, ProgressBarWidth);
/* Clear the text area */
TuiFillArea(Left, Top, Right,
#ifdef NTLDR_PROGRESSBAR
Bottom - 1,
#else // BTMGR_PROGRESSBAR
Bottom - 2, // One empty line between text and bar.
#endif
' ', ATTR(UiTextColor, UiMenuBgColor));
/* Draw the "Loading..." text */
TuiDrawCenteredText(Left, Top, Right,
#ifdef NTLDR_PROGRESSBAR
Bottom - 1,
#else // BTMGR_PROGRESSBAR
Bottom - 2, // One empty line between text and bar.
#endif
ProgressText, ATTR(UiTextColor, UiMenuBgColor));
/* Draw the percent complete -- Use the fill character */
for (i = 0; i < (Position * ProgressBarWidth) / Range; i++)
{
TuiDrawText(Left + i, Bottom,
"\xDB", ATTR(UiTextColor, UiMenuBgColor));
}
/* Fill the remaining with blanks */
TuiFillArea(Left + i, Bottom, Right, Bottom,
' ', ATTR(UiTextColor, UiMenuBgColor));
#ifndef _M_ARM
TuiUpdateDateTime();
VideoCopyOffScreenBufferToVRAM();
#endif
UiInitProgressBar(Left, Top, Right, Bottom, ProgressText);
}
VOID
@ -192,6 +221,8 @@ const UIVTBL MiniTuiVtbl =
TuiMessageBoxCritical,
MiniTuiDrawProgressBarCenter,
MiniTuiDrawProgressBar,
MiniTuiSetProgressBarText,
MiniTuiTickProgressBar,
TuiEditBox,
TuiTextToColor,
TuiTextToFillStyle,

View file

@ -100,11 +100,23 @@ VOID NoUiMessageBoxCritical(PCSTR MessageText)
MachConsGetCh();
}
/* Loading Progress-Bar Functions ********************************************/
VOID
NoUiSetProgressBarText(
_In_ PCSTR ProgressText)
{
}
VOID
NoUiTickProgressBar(
_In_ ULONG SubPercentTimes100)
{
}
VOID
NoUiDrawProgressBarCenter(
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText)
_In_ PCSTR ProgressText)
{
}
@ -114,12 +126,11 @@ NoUiDrawProgressBar(
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText)
_In_ PCSTR ProgressText)
{
}
BOOLEAN NoUiEditBox(PCSTR MessageText, PCHAR EditTextBuffer, ULONG Length)
{
return FALSE;

View file

@ -53,6 +53,16 @@ TuiPrintf(
return Length;
}
VOID
TuiTruncateStringEllipsis(
_Inout_z_ PSTR StringText,
_In_ ULONG MaxChars)
{
/* If it's too large, just add some ellipsis past the maximum */
if (strlen(StringText) > MaxChars)
strcpy(&StringText[MaxChars - 3], "...");
}
/*
* DrawText()
* Displays a string on a single screen line.
@ -690,11 +700,83 @@ VOID TuiMessageBoxCritical(PCSTR MessageText)
}
}
VOID
static VOID
TuiSetProgressBarText(
_In_ PCSTR ProgressText)
{
ULONG ProgressBarWidth;
CHAR ProgressString[256];
/* Make sure the progress bar is enabled */
ASSERT(UiProgressBar.Show);
/* Calculate the width of the bar proper */
ProgressBarWidth = UiProgressBar.Right - UiProgressBar.Left + 1;
/* First make sure the progress bar text fits */
RtlStringCbCopyA(ProgressString, sizeof(ProgressString), ProgressText);
TuiTruncateStringEllipsis(ProgressString, ProgressBarWidth);
/* Clear the text area */
TuiFillArea(UiProgressBar.Left, UiProgressBar.Top,
UiProgressBar.Right, UiProgressBar.Bottom - 1,
' ', ATTR(UiTextColor, UiMenuBgColor));
/* Draw the "Loading..." text */
TuiDrawCenteredText(UiProgressBar.Left, UiProgressBar.Top,
UiProgressBar.Right, UiProgressBar.Bottom - 1,
ProgressString, ATTR(UiTextColor, UiMenuBgColor));
}
static VOID
TuiTickProgressBar(
_In_ ULONG SubPercentTimes100)
{
ULONG ProgressBarWidth;
ULONG FillCount;
/* Make sure the progress bar is enabled */
ASSERT(UiProgressBar.Show);
ASSERT(SubPercentTimes100 <= (100 * 100));
/* Calculate the width of the bar proper */
ProgressBarWidth = UiProgressBar.Right - UiProgressBar.Left + 1;
/* Compute fill count */
// FillCount = (ProgressBarWidth * Position) / Range;
FillCount = ProgressBarWidth * SubPercentTimes100 / (100 * 100);
/* Fill the progress bar */
/* Draw the percent complete -- Use the fill character */
if (FillCount > 0)
{
TuiFillArea(UiProgressBar.Left, UiProgressBar.Bottom,
UiProgressBar.Left + FillCount - 1, UiProgressBar.Bottom,
'\xDB', ATTR(UiTextColor, UiMenuBgColor));
}
/* Fill the remaining with shadow blanks */
TuiFillArea(UiProgressBar.Left + FillCount, UiProgressBar.Bottom,
UiProgressBar.Right, UiProgressBar.Bottom,
'\xB2', ATTR(UiTextColor, UiMenuBgColor));
#ifndef _M_ARM
TuiUpdateDateTime();
VideoCopyOffScreenBufferToVRAM();
#endif
}
static VOID
TuiDrawProgressBar(
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ PCSTR ProgressText);
static VOID
TuiDrawProgressBarCenter(
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText)
_In_ PCSTR ProgressText)
{
ULONG Left, Top, Right, Bottom, Width, Height;
@ -713,23 +795,21 @@ TuiDrawProgressBarCenter(
Bottom += 1;
/* Draw the progress bar */
TuiDrawProgressBar(Left, Top, Right, Bottom, Position, Range, ProgressText);
TuiDrawProgressBar(Left, Top, Right, Bottom, ProgressText);
}
VOID
static VOID
TuiDrawProgressBar(
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText)
_In_ PCSTR ProgressText)
{
ULONG ProgressBarWidth, i;
/* Draw the box */
TuiDrawBox(Left, Top, Right, Bottom, VERT, HORZ, TRUE, TRUE, ATTR(UiMenuFgColor, UiMenuBgColor));
TuiDrawBox(Left, Top, Right, Bottom,
VERT, HORZ, TRUE, TRUE,
ATTR(UiMenuFgColor, UiMenuBgColor));
/* Exclude the box margins */
Left += 2;
@ -737,34 +817,7 @@ TuiDrawProgressBar(
Top += 1;
Bottom -= 1;
/* Calculate the width of the bar proper */
ProgressBarWidth = Right - Left + 1;
/* Clip the position */
if (Position > Range)
Position = Range;
/* First make sure the progress bar text fits */
UiTruncateStringEllipsis(ProgressText, ProgressBarWidth);
/* Draw the "Loading..." text */
TuiDrawCenteredText(Left, Top, Right, Bottom - 1,
ProgressText, ATTR(UiTextColor, UiMenuBgColor));
/* Draw the percent complete -- Use the fill character */
for (i = 0; i < (Position * ProgressBarWidth) / Range; i++)
{
TuiDrawText(Left + i, Bottom,
"\xDB", ATTR(UiTextColor, UiMenuBgColor));
}
/* Fill the remaining with shadow blanks */
TuiFillArea(Left + i, Bottom, Right, Bottom,
'\xB2', ATTR(UiTextColor, UiMenuBgColor));
#ifndef _M_ARM
TuiUpdateDateTime();
VideoCopyOffScreenBufferToVRAM();
#endif
UiInitProgressBar(Left, Top, Right, Bottom, ProgressText);
}
UCHAR TuiTextToColor(PCSTR ColorText)
@ -1135,6 +1188,8 @@ const UIVTBL TuiVtbl =
TuiMessageBoxCritical,
TuiDrawProgressBarCenter,
TuiDrawProgressBar,
TuiSetProgressBarText,
TuiTickProgressBar,
TuiEditBox,
TuiTextToColor,
TuiTextToFillStyle,

View file

@ -16,13 +16,14 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _M_ARM
#include <freeldr.h>
#include <debug.h>
DBG_DEFAULT_CHANNEL(UI);
#ifndef _M_ARM
#define TAG_UI_TEXT 'xTiU'
ULONG UiScreenWidth; // Screen Width
@ -55,6 +56,17 @@ CHAR UiTimeText[260] = "[Time Remaining: ] ";
const CHAR UiMonthNames[12][15] = { "January ", "February ", "March ", "April ", "May ", "June ", "July ", "August ", "September ", "October ", "November ", "December " };
#endif // _M_ARM
/*
* Loading progress bar, based on the NTOS Inbv one.
* Supports progress within sub-ranges, used when loading
* with an unknown number of steps.
*/
UI_PROGRESS_BAR UiProgressBar = {{0}};
#ifndef _M_ARM
UIVTBL UiVtbl =
{
NoUiInitialize,
@ -72,6 +84,8 @@ UIVTBL UiVtbl =
NoUiMessageBoxCritical,
NoUiDrawProgressBarCenter,
NoUiDrawProgressBar,
NoUiSetProgressBarText,
NoUiTickProgressBar,
NoUiEditBox,
NoUiTextToColor,
NoUiTextToFillStyle,
@ -369,13 +383,128 @@ UCHAR UiTextToFillStyle(PCSTR FillStyleText)
return UiVtbl.TextToFillStyle(FillStyleText);
}
#endif // _M_ARM
VOID
UiInitProgressBar(
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ PCSTR ProgressText)
{
/* Progress bar area */
UiProgressBar.Left = Left;
UiProgressBar.Top = Top;
UiProgressBar.Right = Right;
UiProgressBar.Bottom = Bottom;
// UiProgressBar.Width = Right - Left + 1;
/* Set the progress bar ranges */
UiSetProgressBarSubset(0, 100);
UiProgressBar.Indicator.Count = 0;
UiProgressBar.Indicator.Expected = 25;
UiProgressBar.Indicator.Percentage = 0;
/* Enable the progress bar */
UiProgressBar.Show = TRUE;
/* Initial drawing: set the "Loading..." text and the original position */
#ifndef _M_ARM
UiVtbl.SetProgressBarText(ProgressText);
UiVtbl.TickProgressBar(0);
#else
MiniTuiSetProgressBarText(ProgressText);
MiniTuiTickProgressBar(0);
#endif
}
VOID
UiIndicateProgress(VOID)
{
ULONG Percentage;
/* Increase progress */
UiProgressBar.Indicator.Count++;
/* Compute the new percentage - Don't go over 100% */
Percentage = 100 * UiProgressBar.Indicator.Count /
UiProgressBar.Indicator.Expected;
Percentage = min(Percentage, 99);
if (Percentage != UiProgressBar.Indicator.Percentage)
{
/* Percentage has changed, update the progress bar */
UiProgressBar.Indicator.Percentage = Percentage;
UiUpdateProgressBar(Percentage, NULL);
}
}
VOID
UiSetProgressBarSubset(
_In_ ULONG Floor,
_In_ ULONG Ceiling)
{
/* Sanity checks */
ASSERT(Floor < Ceiling);
ASSERT(Ceiling <= 100);
/* Update the progress bar state */
UiProgressBar.State.Floor = Floor * 100;
// UiProgressBar.State.Ceiling = Ceiling * 100;
UiProgressBar.State.Bias = Ceiling - Floor;
}
VOID
UiUpdateProgressBar(
_In_ ULONG Percentage,
_In_opt_ PCSTR ProgressText)
{
ULONG TotalProgress;
/* Make sure the progress bar is enabled */
if (!UiProgressBar.Show)
return;
/* Set the progress text if specified */
if (ProgressText)
UiSetProgressBarText(ProgressText);
/* Compute the total progress and tick the progress bar */
TotalProgress = UiProgressBar.State.Floor + (Percentage * UiProgressBar.State.Bias);
// TotalProgress /= (100 * 100);
#ifndef _M_ARM
UiVtbl.TickProgressBar(TotalProgress);
#else
MiniTuiTickProgressBar(TotalProgress);
#endif
}
VOID
UiSetProgressBarText(
_In_ PCSTR ProgressText)
{
/* Make sure the progress bar is enabled */
if (!UiProgressBar.Show)
return;
#ifndef _M_ARM
UiVtbl.SetProgressBarText(ProgressText);
#else
MiniTuiSetProgressBarText(ProgressText);
#endif
}
VOID
UiDrawProgressBarCenter(
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText)
_In_ PCSTR ProgressText)
{
UiVtbl.DrawProgressBarCenter(Position, Range, ProgressText);
#ifndef _M_ARM
UiVtbl.DrawProgressBarCenter(ProgressText);
#else
MiniTuiDrawProgressBarCenter(ProgressText);
#endif
}
VOID
@ -384,11 +513,34 @@ UiDrawProgressBar(
_In_ ULONG Top,
_In_ ULONG Right,
_In_ ULONG Bottom,
_In_ ULONG Position,
_In_ ULONG Range,
_Inout_z_ PSTR ProgressText)
_In_ PCSTR ProgressText)
{
UiVtbl.DrawProgressBar(Left, Top, Right, Bottom, Position, Range, ProgressText);
#ifndef _M_ARM
UiVtbl.DrawProgressBar(Left, Top, Right, Bottom, ProgressText);
#else
MiniTuiDrawProgressBar(Left, Top, Right, Bottom, ProgressText);
#endif
}
#ifndef _M_ARM
static VOID
UiEscapeString(PCHAR String)
{
ULONG Idx;
for (Idx=0; Idx<strlen(String); Idx++)
{
// Escape the new line characters
if (String[Idx] == '\\' && String[Idx+1] == 'n')
{
// Escape the character
String[Idx] = '\n';
// Move the rest of the string up
strcpy(&String[Idx+1], &String[Idx+2]);
}
}
}
VOID
@ -472,31 +624,6 @@ UiShowMessageBoxesInArgv(
}
}
VOID UiEscapeString(PCHAR String)
{
ULONG Idx;
for (Idx=0; Idx<strlen(String); Idx++)
{
// Escape the new line characters
if (String[Idx] == '\\' && String[Idx+1] == 'n')
{
// Escape the character
String[Idx] = '\n';
// Move the rest of the string up
strcpy(&String[Idx+1], &String[Idx+2]);
}
}
}
VOID UiTruncateStringEllipsis(PCHAR StringText, ULONG MaxChars)
{
/* If it's too large, just add some ellipsis past the maximum */
if (strlen(StringText) > MaxChars)
strcpy(&StringText[MaxChars - 3], "...");
}
BOOLEAN
UiDisplayMenu(
IN PCSTR MenuHeader,