+++ /dev/null
-/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: FreeLoader
- * FILE: boot/freeldr/freeldr/ui/tuimenu.c
- * PURPOSE: UI Menu Functions
- * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
- * Brian Palmer (brianp@sginet.com)
- */
-
-/* INCLUDES ******************************************************************/
-#ifndef _M_ARM
-#include <freeldr.h>
-
-/* FUNCTIONS *****************************************************************/
-
-BOOLEAN
-TuiDisplayMenu(PCSTR MenuHeader,
- PCSTR MenuFooter,
- BOOLEAN ShowBootOptions,
- PCSTR MenuItemList[],
- ULONG MenuItemCount,
- ULONG DefaultMenuItem,
- LONG MenuTimeOut,
- ULONG* SelectedMenuItem,
- BOOLEAN CanEscape,
- UiMenuKeyPressFilterCallback KeyPressFilter)
-{
- UI_MENU_INFO MenuInformation;
- ULONG LastClockSecond;
- ULONG CurrentClockSecond;
- ULONG KeyPress;
-
- //
- // Check if there's no timeout
- if (!MenuTimeOut)
- {
- //
- // Return the default selected item
- //
- if (SelectedMenuItem) *SelectedMenuItem = DefaultMenuItem;
- return TRUE;
- }
-
- //
- // Setup the MENU_INFO structure
- //
- MenuInformation.MenuHeader = MenuHeader;
- MenuInformation.MenuFooter = MenuFooter;
- MenuInformation.ShowBootOptions = ShowBootOptions;
- MenuInformation.MenuItemList = MenuItemList;
- MenuInformation.MenuItemCount = MenuItemCount;
- MenuInformation.MenuTimeRemaining = MenuTimeOut;
- MenuInformation.SelectedMenuItem = DefaultMenuItem;
-
- //
- // Calculate the size of the menu box
- //
- TuiCalcMenuBoxSize(&MenuInformation);
-
- //
- // Draw the menu
- //
- UiVtbl.DrawMenu(&MenuInformation);
-
- //
- // Get the current second of time
- //
- LastClockSecond = ArcGetTime()->Second;
-
- //
- // Process keys
- //
- while (TRUE)
- {
- //
- // Process key presses
- //
- KeyPress = TuiProcessMenuKeyboardEvent(&MenuInformation,
- KeyPressFilter);
-
- //
- // Check for ENTER or ESC
- //
- if (KeyPress == KEY_ENTER) break;
- if (CanEscape && KeyPress == KEY_ESC) return FALSE;
-
- //
- // Update the date & time
- //
- TuiUpdateDateTime();
- VideoCopyOffScreenBufferToVRAM();
-
- //
- // Check if there is a countdown
- //
- if (MenuInformation.MenuTimeRemaining > 0)
- {
- //
- // Get the updated time, seconds only
- //
- CurrentClockSecond = ArcGetTime()->Second;
-
- //
- // Check if more then a second has now elapsed
- //
- if (CurrentClockSecond != LastClockSecond)
- {
- //
- // Update the time information
- //
- LastClockSecond = CurrentClockSecond;
- MenuInformation.MenuTimeRemaining--;
-
- //
- // Update the menu
- //
- TuiDrawMenuBox(&MenuInformation);
- VideoCopyOffScreenBufferToVRAM();
- }
- }
- else if (MenuInformation.MenuTimeRemaining == 0)
- {
- //
- // A time out occurred, exit this loop and return default OS
- //
- break;
- }
-
- MachHwIdle();
- }
-
- //
- // Return the selected item
- //
- if (SelectedMenuItem) *SelectedMenuItem = MenuInformation.SelectedMenuItem;
- return TRUE;
-}
-
-VOID
-NTAPI
-TuiCalcMenuBoxSize(PUI_MENU_INFO MenuInfo)
-{
- ULONG i;
- ULONG Width = 0;
- ULONG Height;
- ULONG Length;
-
- //
- // Height is the menu item count plus 2 (top border & bottom border)
- //
- Height = MenuInfo->MenuItemCount + 2;
- Height -= 1; // Height is zero-based
-
- //
- // Loop every item
- //
- for(i = 0; i < MenuInfo->MenuItemCount; i++)
- {
- //
- // Get the string length and make it become the new width if necessary
- //
- if (MenuInfo->MenuItemList[i])
- {
- Length = (ULONG)strlen(MenuInfo->MenuItemList[i]);
- if (Length > Width) Width = Length;
- }
- }
-
- //
- // Allow room for left & right borders, plus 8 spaces on each side
- //
- Width += 18;
-
- //
- // Check if we're drawing a centered menu
- //
- if (UiCenterMenu)
- {
- //
- // Calculate the menu box area for a centered menu
- //
- MenuInfo->Left = (UiScreenWidth - Width) / 2;
- MenuInfo->Top = (((UiScreenHeight - TUI_TITLE_BOX_CHAR_HEIGHT) -
- Height) / 2) + TUI_TITLE_BOX_CHAR_HEIGHT;
- }
- else
- {
- //
- // Put the menu in the default left-corner position
- //
- MenuInfo->Left = -1;
- MenuInfo->Top = 4;
- }
-
- //
- // The other margins are the same
- //
- MenuInfo->Right = (MenuInfo->Left) + Width;
- MenuInfo->Bottom = (MenuInfo->Top) + Height;
-}
-
-VOID
-TuiDrawMenu(PUI_MENU_INFO MenuInfo)
-{
- ULONG i;
-
- //
- // Draw the backdrop
- //
- UiDrawBackdrop();
-
- //
- // Update the status bar
- //
- UiVtbl.DrawStatusText("Use \x18 and \x19 to select, then press ENTER.");
-
- //
- // Draw the menu box
- //
- TuiDrawMenuBox(MenuInfo);
-
- //
- // Draw each line of the menu
- //
- for (i = 0; i < MenuInfo->MenuItemCount; i++)
- {
- TuiDrawMenuItem(MenuInfo, i);
- }
-
- /* Display the boot options if needed */
- if (MenuInfo->ShowBootOptions)
- {
- DisplayBootTimeOptions();
- }
-
- VideoCopyOffScreenBufferToVRAM();
-}
-
-VOID
-NTAPI
-TuiDrawMenuBox(PUI_MENU_INFO MenuInfo)
-{
- CHAR MenuLineText[80], TempString[80];
- ULONG i;
-
- //
- // Draw the menu box if requested
- //
- if (UiMenuBox)
- {
- UiDrawBox(MenuInfo->Left,
- MenuInfo->Top,
- MenuInfo->Right,
- MenuInfo->Bottom,
- D_VERT,
- D_HORZ,
- FALSE, // Filled
- TRUE, // Shadow
- ATTR(UiMenuFgColor, UiMenuBgColor));
- }
-
- //
- // If there is a timeout draw the time remaining
- //
- if (MenuInfo->MenuTimeRemaining >= 0)
- {
- //
- // Copy the integral time text string, and remove the last 2 chars
- //
- strcpy(TempString, UiTimeText);
- i = (ULONG)strlen(TempString);
- TempString[i - 2] = 0;
-
- //
- // Display the first part of the string and the remaining time
- //
- strcpy(MenuLineText, TempString);
- _itoa(MenuInfo->MenuTimeRemaining, TempString, 10);
- strcat(MenuLineText, TempString);
-
- //
- // Add the last 2 chars
- //
- strcat(MenuLineText, &UiTimeText[i - 2]);
-
- //
- // Check if this is a centered menu
- //
- if (UiCenterMenu)
- {
- //
- // Display it in the center of the menu
- //
- UiDrawText(MenuInfo->Right - (ULONG)strlen(MenuLineText) - 1,
- MenuInfo->Bottom,
- MenuLineText,
- ATTR(UiMenuFgColor, UiMenuBgColor));
- }
- else
- {
- //
- // Display under the menu directly
- //
- UiDrawText(0,
- MenuInfo->Bottom + 4,
- MenuLineText,
- ATTR(UiMenuFgColor, UiMenuBgColor));
- }
- }
- else
- {
- //
- // Erase the timeout string with spaces, and 0-terminate for sure
- //
- for (i=0; i<sizeof(MenuLineText)-1; i++)
- {
- MenuLineText[i] = ' ';
- }
- MenuLineText[sizeof(MenuLineText)-1] = 0;
-
- //
- // Draw this "empty" string to erase
- //
- if (UiCenterMenu)
- {
- UiDrawText(MenuInfo->Right - (ULONG)strlen(MenuLineText) - 1,
- MenuInfo->Bottom,
- MenuLineText,
- ATTR(UiMenuFgColor, UiMenuBgColor));
- }
- else
- {
- UiDrawText(0,
- MenuInfo->Bottom + 4,
- MenuLineText,
- ATTR(UiMenuFgColor, UiMenuBgColor));
- }
- }
-
- //
- // Loop each item
- //
- for (i = 0; i < MenuInfo->MenuItemCount; i++)
- {
- //
- // Check if it's a separator
- //
- if (MenuInfo->MenuItemList[i] == NULL)
- {
- //
- // Draw the separator line
- //
- UiDrawText(MenuInfo->Left,
- MenuInfo->Top + i + 1,
- "\xC7",
- ATTR(UiMenuFgColor, UiMenuBgColor));
- UiDrawText(MenuInfo->Right,
- MenuInfo->Top + i + 1,
- "\xB6",
- ATTR(UiMenuFgColor, UiMenuBgColor));
- }
- }
-}
-
-VOID
-NTAPI
-TuiDrawMenuItem(PUI_MENU_INFO MenuInfo,
- ULONG MenuItemNumber)
-{
- ULONG i;
- CHAR MenuLineText[80];
- ULONG SpaceTotal;
- ULONG SpaceLeft;
- ULONG SpaceRight = 0;
- UCHAR Attribute = ATTR(UiTextColor, UiMenuBgColor);
-
- //
- // Check if using centered menu
- //
- if (UiCenterMenu)
- {
- //
- // We will want the string centered so calculate
- // how many spaces will be to the left and right
- //
- SpaceTotal = (MenuInfo->Right - MenuInfo->Left - 2) -
- (ULONG)(MenuInfo->MenuItemList[MenuItemNumber] ?
- strlen(MenuInfo->MenuItemList[MenuItemNumber]) : 0);
- SpaceLeft = (SpaceTotal / 2) + 1;
- SpaceRight = (SpaceTotal - SpaceLeft) + 1;
-
- //
- // Insert the spaces on the left
- //
- for (i = 0; i < SpaceLeft; i++) MenuLineText[i] = ' ';
- MenuLineText[i] = '\0';
- }
- else
- {
- //
- // Simply left-align it
- //
- MenuLineText[0] = '\0';
- strcat(MenuLineText, " ");
- }
-
- //
- // Now append the text string
- //
- if (MenuInfo->MenuItemList[MenuItemNumber])
- strcat(MenuLineText, MenuInfo->MenuItemList[MenuItemNumber]);
-
- //
- // Check if using centered menu, and add spaces on the right if so
- //
- if (UiCenterMenu) for (i=0; i < SpaceRight; i++) strcat(MenuLineText, " ");
-
- //
- // If it is a separator
- //
- if (MenuInfo->MenuItemList[MenuItemNumber] == NULL)
- {
- //
- // Make it a separator line and use menu colors
- //
- memset(MenuLineText, 0, 80);
- memset(MenuLineText, 0xC4, (MenuInfo->Right - MenuInfo->Left - 1));
- Attribute = ATTR(UiMenuFgColor, UiMenuBgColor);
- }
- else if (MenuItemNumber == MenuInfo->SelectedMenuItem)
- {
- //
- // If this is the selected item, use the selected colors
- //
- Attribute = ATTR(UiSelectedTextColor, UiSelectedTextBgColor);
- }
-
- //
- // Draw the item
- //
- UiDrawText(MenuInfo->Left + 1,
- MenuInfo->Top + 1 + MenuItemNumber,
- MenuLineText,
- Attribute);
-}
-
-ULONG
-NTAPI
-TuiProcessMenuKeyboardEvent(PUI_MENU_INFO MenuInfo,
- UiMenuKeyPressFilterCallback KeyPressFilter)
-{
- ULONG KeyEvent = 0;
- ULONG Selected, Count;
-
- //
- // Check for a keypress
- //
- if (MachConsKbHit())
- {
- //
- // Check if the timeout is not already complete
- //
- if (MenuInfo->MenuTimeRemaining != -1)
- {
- //
- // Cancel it and remove it
- //
- MenuInfo->MenuTimeRemaining = -1;
- TuiDrawMenuBox(MenuInfo); // FIXME: Remove for minimal UI too
- }
-
- //
- // Get the key
- //
- KeyEvent = MachConsGetCh();
-
- //
- // Is it extended? Then get the extended key
- //
- if (!KeyEvent) KeyEvent = MachConsGetCh();
-
- //
- // Call the supplied key filter callback function to see
- // if it is going to handle this keypress.
- //
- if ((KeyPressFilter) && (KeyPressFilter(KeyEvent)))
- {
- //
- // It processed the key character, so redraw and exit
- //
- UiVtbl.DrawMenu(MenuInfo);
- return 0;
- }
-
- //
- // Process the key
- //
- if ((KeyEvent == KEY_UP ) || (KeyEvent == KEY_DOWN) ||
- (KeyEvent == KEY_HOME) || (KeyEvent == KEY_END ))
- {
- //
- // Get the current selected item and count
- //
- Selected = MenuInfo->SelectedMenuItem;
- Count = MenuInfo->MenuItemCount - 1;
-
- //
- // Check the key and change the selected menu item
- //
- if ((KeyEvent == KEY_UP) && (Selected > 0))
- {
- //
- // Deselect previous item and go up
- //
- MenuInfo->SelectedMenuItem--;
- TuiDrawMenuItem(MenuInfo, Selected);
- Selected--;
-
- // Skip past any separators
- if ((Selected > 0) &&
- (MenuInfo->MenuItemList[Selected] == NULL))
- {
- MenuInfo->SelectedMenuItem--;
- }
- }
- else if ( ((KeyEvent == KEY_UP) && (Selected == 0)) ||
- (KeyEvent == KEY_END) )
- {
- //
- // Go to the end
- //
- MenuInfo->SelectedMenuItem = Count;
- TuiDrawMenuItem(MenuInfo, Selected);
- }
- else if ((KeyEvent == KEY_DOWN) && (Selected < Count))
- {
- //
- // Deselect previous item and go down
- //
- MenuInfo->SelectedMenuItem++;
- TuiDrawMenuItem(MenuInfo, Selected);
- Selected++;
-
- // Skip past any separators
- if ((Selected < Count) &&
- (MenuInfo->MenuItemList[Selected] == NULL))
- {
- MenuInfo->SelectedMenuItem++;
- }
- }
- else if ( ((KeyEvent == KEY_DOWN) && (Selected == Count)) ||
- (KeyEvent == KEY_HOME) )
- {
- //
- // Go to the beginning
- //
- MenuInfo->SelectedMenuItem = 0;
- TuiDrawMenuItem(MenuInfo, Selected);
- }
-
- //
- // Select new item and update video buffer
- //
- TuiDrawMenuItem(MenuInfo, MenuInfo->SelectedMenuItem);
- VideoCopyOffScreenBufferToVRAM();
- }
- }
-
- //
- // Return the pressed key
- //
- return KeyEvent;
-}
-#endif