📄 tui.c
字号:
/*
* FreeLoader
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <freeldr.h>
PVOID TextVideoBuffer = NULL;
extern BOOLEAN UiMinimal;
/*
* printf() - prints formatted text to stdout
* originally from GRUB
*/
int printf(const char *format, ... )
{
va_list ap;
va_start(ap,format);
char c, *ptr, str[16];
while ((c = *(format++)))
{
if (c != '%')
{
MachConsPutChar(c);
}
else
{
switch (c = *(format++))
{
case 'd': case 'u': case 'x':
if (c == 'x')
_itoa(va_arg(ap, unsigned long), str, 16);
else
_itoa(va_arg(ap, unsigned long), str, 10);
ptr = str;
while (*ptr)
{
MachConsPutChar(*(ptr++));
}
break;
case 'c': MachConsPutChar((va_arg(ap,int))&0xff); break;
case 's':
ptr = va_arg(ap,char *);
while ((c = *(ptr++)))
{
MachConsPutChar(c);
}
break;
case '%':
MachConsPutChar(c);
break;
default:
printf("\nprintf() invalid format specifier - %%%c\n", c);
break;
}
}
}
va_end(ap);
return 0;
}
BOOLEAN TuiInitialize(VOID)
{
MachVideoClearScreen(ATTR(COLOR_WHITE, COLOR_BLACK));
MachVideoHideShowTextCursor(FALSE);
TextVideoBuffer = VideoAllocateOffScreenBuffer();
if (TextVideoBuffer == NULL)
{
return FALSE;
}
return TRUE;
}
VOID TuiUnInitialize(VOID)
{
if (UiUseSpecialEffects)
{
TuiFadeOut();
}
else
{
MachVideoSetDisplayMode(NULL, FALSE);
}
//VideoClearScreen();
MachVideoHideShowTextCursor(TRUE);
}
VOID TuiDrawBackdrop(VOID)
{
if (UiMinimal)
{
//
// Fill in a black background
//
TuiFillArea(0,
0,
UiScreenWidth - 1,
UiScreenHeight - 1,
0,
0);
//
// Update the screen buffer
//
VideoCopyOffScreenBufferToVRAM();
return;
}
//
// Fill in the background (excluding title box & status bar)
//
TuiFillArea(0,
TUI_TITLE_BOX_CHAR_HEIGHT,
UiScreenWidth - 1,
UiScreenHeight - 2,
UiBackdropFillStyle,
ATTR(UiBackdropFgColor, UiBackdropBgColor));
//
// Draw the title box
//
TuiDrawBox(0,
0,
UiScreenWidth - 1,
TUI_TITLE_BOX_CHAR_HEIGHT - 1,
D_VERT,
D_HORZ,
TRUE,
FALSE,
ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor));
//
// Draw version text
//
TuiDrawText(2,
1,
GetFreeLoaderVersionString(),
ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor));
//
// Draw copyright
//
TuiDrawText(2,
2,
BY_AUTHOR,
ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor));
TuiDrawText(2,
3,
AUTHOR_EMAIL,
ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor));
//
// Draw help text
//
TuiDrawText(UiScreenWidth - 16, 3, /*"F1 for Help"*/"F8 for Options", ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor));
//
// Draw title text
//
TuiDrawText( (UiScreenWidth / 2) - (strlen(UiTitleBoxTitleText) / 2),
2,
UiTitleBoxTitleText,
ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor));
//
// Draw status bar
//
TuiDrawStatusText("Welcome to FreeLoader!");
//
// Update the date & time
//
TuiUpdateDateTime();
VideoCopyOffScreenBufferToVRAM();
}
/*
* FillArea()
* This function assumes coordinates are zero-based
*/
VOID TuiFillArea(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, CHAR FillChar, UCHAR Attr /* Color Attributes */)
{
PUCHAR ScreenMemory = (PUCHAR)TextVideoBuffer;
ULONG i, j;
// Clip the area to the screen
if ((Left >= UiScreenWidth) || (Top >= UiScreenHeight))
{
return;
}
if (Right >= UiScreenWidth)
{
Right = UiScreenWidth - 1;
}
if (Bottom >= UiScreenHeight)
{
Bottom = UiScreenHeight - 1;
}
// Loop through each line and fill it in
for (i=Top; i<=Bottom; i++)
{
// Loop through each character (column) in the line and fill it in
for (j=Left; j<=Right; j++)
{
ScreenMemory[((i*2)*UiScreenWidth)+(j*2)] = (UCHAR)FillChar;
ScreenMemory[((i*2)*UiScreenWidth)+(j*2)+1] = Attr;
}
}
}
/*
* DrawShadow()
* This function assumes coordinates are zero-based
*/
VOID TuiDrawShadow(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom)
{
PUCHAR ScreenMemory = (PUCHAR)TextVideoBuffer;
ULONG Idx;
// Shade the bottom of the area
if (Bottom < (UiScreenHeight - 1))
{
if (UiScreenHeight < 34)
{
Idx=Left + 2;
}
else
{
Idx=Left + 1;
}
for (; Idx<=Right; Idx++)
{
ScreenMemory[(((Bottom+1)*2)*UiScreenWidth)+(Idx*2)+1] = ATTR(COLOR_GRAY, COLOR_BLACK);
}
}
// Shade the right of the area
if (Right < (UiScreenWidth - 1))
{
for (Idx=Top+1; Idx<=Bottom; Idx++)
{
ScreenMemory[((Idx*2)*UiScreenWidth)+((Right+1)*2)+1] = ATTR(COLOR_GRAY, COLOR_BLACK);
}
}
if (UiScreenHeight < 34)
{
if ((Right + 1) < (UiScreenWidth - 1))
{
for (Idx=Top+1; Idx<=Bottom; Idx++)
{
ScreenMemory[((Idx*2)*UiScreenWidth)+((Right+2)*2)+1] = ATTR(COLOR_GRAY, COLOR_BLACK);
}
}
}
// Shade the bottom right corner
if ((Right < (UiScreenWidth - 1)) && (Bottom < (UiScreenHeight - 1)))
{
ScreenMemory[(((Bottom+1)*2)*UiScreenWidth)+((Right+1)*2)+1] = ATTR(COLOR_GRAY, COLOR_BLACK);
}
if (UiScreenHeight < 34)
{
if (((Right + 1) < (UiScreenWidth - 1)) && (Bottom < (UiScreenHeight - 1)))
{
ScreenMemory[(((Bottom+1)*2)*UiScreenWidth)+((Right+2)*2)+1] = ATTR(COLOR_GRAY, COLOR_BLACK);
}
}
}
/*
* DrawBox()
* This function assumes coordinates are zero-based
*/
VOID TuiDrawBox(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, UCHAR VertStyle, UCHAR HorzStyle, BOOLEAN Fill, BOOLEAN Shadow, UCHAR Attr)
{
UCHAR ULCorner, URCorner, LLCorner, LRCorner;
// Calculate the corner values
if (HorzStyle == HORZ)
{
if (VertStyle == VERT)
{
ULCorner = UL;
URCorner = UR;
LLCorner = LL;
LRCorner = LR;
}
else // VertStyle == D_VERT
{
ULCorner = VD_UL;
URCorner = VD_UR;
LLCorner = VD_LL;
LRCorner = VD_LR;
}
}
else // HorzStyle == D_HORZ
{
if (VertStyle == VERT)
{
ULCorner = HD_UL;
URCorner = HD_UR;
LLCorner = HD_LL;
LRCorner = HD_LR;
}
else // VertStyle == D_VERT
{
ULCorner = D_UL;
URCorner = D_UR;
LLCorner = D_LL;
LRCorner = D_LR;
}
}
// Fill in box background
if (Fill)
{
TuiFillArea(Left, Top, Right, Bottom, ' ', Attr);
}
// Fill in corners
TuiFillArea(Left, Top, Left, Top, ULCorner, Attr);
TuiFillArea(Right, Top, Right, Top, URCorner, Attr);
TuiFillArea(Left, Bottom, Left, Bottom, LLCorner, Attr);
TuiFillArea(Right, Bottom, Right, Bottom, LRCorner, Attr);
// Fill in left line
TuiFillArea(Left, Top+1, Left, Bottom-1, VertStyle, Attr);
// Fill in top line
TuiFillArea(Left+1, Top, Right-1, Top, HorzStyle, Attr);
// Fill in right line
TuiFillArea(Right, Top+1, Right, Bottom-1, VertStyle, Attr);
// Fill in bottom line
TuiFillArea(Left+1, Bottom, Right-1, Bottom, HorzStyle, Attr);
// Draw the shadow
if (Shadow)
{
TuiDrawShadow(Left, Top, Right, Bottom);
}
}
/*
* DrawText()
* This function assumes coordinates are zero-based
*/
VOID TuiDrawText(ULONG X, ULONG Y, PCSTR Text, UCHAR Attr)
{
PUCHAR ScreenMemory = (PUCHAR)TextVideoBuffer;
ULONG i, j;
// Draw the text
for (i=X, j=0; Text[j] && i<UiScreenWidth; i++,j++)
{
ScreenMemory[((Y*2)*UiScreenWidth)+(i*2)] = (UCHAR)Text[j];
ScreenMemory[((Y*2)*UiScreenWidth)+(i*2)+1] = Attr;
}
}
VOID TuiDrawCenteredText(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, PCSTR TextString, UCHAR Attr)
{
ULONG TextLength;
ULONG BoxWidth;
ULONG BoxHeight;
ULONG LineBreakCount;
ULONG Index;
ULONG LastIndex;
ULONG RealLeft;
ULONG RealTop;
ULONG X;
ULONG Y;
CHAR Temp[2];
TextLength = strlen(TextString);
// Count the new lines and the box width
LineBreakCount = 0;
BoxWidth = 0;
LastIndex = 0;
for (Index=0; Index<TextLength; Index++)
{
if (TextString[Index] == '\n')
{
LastIndex = Index;
LineBreakCount++;
}
else
{
if ((Index - LastIndex) > BoxWidth)
{
BoxWidth = (Index - LastIndex);
}
}
}
BoxHeight = LineBreakCount + 1;
RealLeft = (((Right - Left) - BoxWidth) / 2) + Left;
RealTop = (((Bottom - Top) - BoxHeight) / 2) + Top;
LastIndex = 0;
for (Index=0; Index<TextLength; Index++)
{
if (TextString[Index] == '\n')
{
RealTop++;
LastIndex = 0;
}
else
{
X = RealLeft + LastIndex;
Y = RealTop;
LastIndex++;
Temp[0] = TextString[Index];
Temp[1] = 0;
TuiDrawText(X, Y, Temp, Attr);
}
}
}
VOID TuiDrawStatusText(PCSTR StatusText)
{
ULONG i;
//
// Minimal UI doesn't have a status bar
//
if (UiMinimal) return;
TuiDrawText(0, UiScreenHeight-1, " ", ATTR(UiStatusBarFgColor, UiStatusBarBgColor));
TuiDrawText(1, UiScreenHeight-1, StatusText, ATTR(UiStatusBarFgColor, UiStatusBarBgColor));
for (i=strlen(StatusText)+1; i<UiScreenWidth; i++)
{
TuiDrawText(i, UiScreenHeight-1, " ", ATTR(UiStatusBarFgColor, UiStatusBarBgColor));
}
VideoCopyOffScreenBufferToVRAM();
}
VOID TuiUpdateDateTime(VOID)
{
ULONG Year, Month, Day;
ULONG Hour, Minute, Second;
CHAR DateString[40];
CHAR TimeString[40];
CHAR TempString[20];
BOOLEAN PMHour = FALSE;
/* Don't draw the time if this has been disabled */
if (!UiDrawTime) return;
MachRTCGetCurrentDateTime(&Year, &Month, &Day, &Hour, &Minute, &Second);
if (Year < 1 || 9999 < Year || Month < 1 || 12 < Month || Day < 1 ||
31 < Day || 23 < Hour || 59 < Minute || 59 < Second)
{
/* This happens on QEmu sometimes. We just skip updating */
return;
}
// Get the month name
strcpy(DateString, UiMonthNames[Month - 1]);
// Get the day
_itoa(Day, TempString, 10);
// Get the day postfix
if (1 == Day || 21 == Day || 31 == Day)
{
strcat(TempString, "st");
}
else if (2 == Day || 22 == Day)
{
strcat(TempString, "nd");
}
else if (3 == Day || 23 == Day)
{
strcat(TempString, "rd");
}
else
{
strcat(TempString, "th");
}
// Add the day to the date
strcat(DateString, TempString);
strcat(DateString, " ");
// Get the year and add it to the date
_itoa(Year, TempString, 10);
strcat(DateString, TempString);
// Draw the date
TuiDrawText(UiScreenWidth-strlen(DateString)-2, 1, DateString, ATTR(UiTitleBoxFgColor, UiTitleBoxBgColor));
// Get the hour and change from 24-hour mode to 12-hour
if (Hour > 12)
{
Hour -= 12;
PMHour = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -