From b9feb4bdf281bcd9c61d9b089c379f265664674b Mon Sep 17 00:00:00 2001 From: Eric Dong Date: Fri, 9 Aug 2013 05:26:47 +0000 Subject: [PATCH] Update Browser to provide the customization possibilities. Signed-off-by: Eric Dong Reviewed-by: Liming Gao MdeModulePkg Patch Tested-by: Laszlo Ersek OvmfPkg Patch Tested-by: Laszlo Ersek Reviewed-by: Laszlo Ersek git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14537 6f19259b-4bc3-4df7-8a09-765794883524 --- DuetPkg/DuetPkg.fdf | 1 + DuetPkg/DuetPkgIa32.dsc | 2 + DuetPkg/DuetPkgX64.dsc | 2 + .../Include/Library/CustomizedDisplayLib.h | 356 ++ .../Include/Protocol/DisplayProtocol.h | 350 ++ .../Include/Protocol/FormBrowserEx2.h | 90 + .../CustomizedDisplayLib}/Colors.h | 0 .../CustomizedDisplayLib.c | 921 ++++ .../CustomizedDisplayLib.inf | 74 + .../CustomizedDisplayLib.uni | Bin 0 -> 7256 bytes .../CustomizedDisplayLibInternal.c | 914 ++++ .../CustomizedDisplayLibInternal.h | 295 ++ MdeModulePkg/MdeModulePkg.dec | 10 + MdeModulePkg/MdeModulePkg.dsc | 2 + .../DisplayEngineDxe/DisplayEngineDxe.inf | 66 + .../Universal/DisplayEngineDxe/FormDisplay.c | 3255 +++++++++++++ .../Universal/DisplayEngineDxe/FormDisplay.h | 589 +++ .../FormDisplayStr.uni} | Bin 14784 -> 8660 bytes .../InputHandler.c | 621 +-- .../DisplayEngineDxe/ProcessOptions.c | 1286 ++++++ .../Universal/SetupBrowserDxe/Expression.c | 6 +- .../Universal/SetupBrowserDxe/Expression.h | 265 ++ .../Universal/SetupBrowserDxe/IfrParse.c | 65 +- .../Universal/SetupBrowserDxe/Presentation.c | 2581 +++++++---- .../Universal/SetupBrowserDxe/Print.c | 272 -- .../SetupBrowserDxe/ProcessOptions.c | 1075 ----- .../Universal/SetupBrowserDxe/Setup.c | 2368 ++++++---- .../Universal/SetupBrowserDxe/Setup.h | 821 ++-- .../SetupBrowserDxe/SetupBrowserDxe.inf | 26 +- MdeModulePkg/Universal/SetupBrowserDxe/Ui.c | 4027 ----------------- MdeModulePkg/Universal/SetupBrowserDxe/Ui.h | 1067 ----- Nt32Pkg/Nt32Pkg.dsc | 2 + Nt32Pkg/Nt32Pkg.fdf | 1 + OvmfPkg/OvmfPkgIa32.dsc | 2 + OvmfPkg/OvmfPkgIa32.fdf | 1 + OvmfPkg/OvmfPkgIa32X64.dsc | 2 + OvmfPkg/OvmfPkgIa32X64.fdf | 1 + OvmfPkg/OvmfPkgX64.dsc | 2 + OvmfPkg/OvmfPkgX64.fdf | 1 + 39 files changed, 12424 insertions(+), 8995 deletions(-) create mode 100644 MdeModulePkg/Include/Library/CustomizedDisplayLib.h create mode 100644 MdeModulePkg/Include/Protocol/DisplayProtocol.h create mode 100644 MdeModulePkg/Include/Protocol/FormBrowserEx2.h rename MdeModulePkg/{Universal/SetupBrowserDxe => Library/CustomizedDisplayLib}/Colors.h (100%) create mode 100644 MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c create mode 100644 MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf create mode 100644 MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni create mode 100644 MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c create mode 100644 MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h create mode 100644 MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf create mode 100644 MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c create mode 100644 MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h rename MdeModulePkg/Universal/{SetupBrowserDxe/SetupBrowserStr.uni => DisplayEngineDxe/FormDisplayStr.uni} (51%) rename MdeModulePkg/Universal/{SetupBrowserDxe => DisplayEngineDxe}/InputHandler.c (68%) create mode 100644 MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Expression.h delete mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Print.c delete mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c delete mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Ui.c delete mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Ui.h diff --git a/DuetPkg/DuetPkg.fdf b/DuetPkg/DuetPkg.fdf index f6bcdd9fdb..66f8b68ed8 100644 --- a/DuetPkg/DuetPkg.fdf +++ b/DuetPkg/DuetPkg.fdf @@ -59,6 +59,7 @@ INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf +INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf diff --git a/DuetPkg/DuetPkgIa32.dsc b/DuetPkg/DuetPkgIa32.dsc index b35ba913ff..117bffb0ec 100644 --- a/DuetPkg/DuetPkgIa32.dsc +++ b/DuetPkg/DuetPkgIa32.dsc @@ -85,6 +85,7 @@ SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf # # Platform # @@ -191,6 +192,7 @@ } MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf diff --git a/DuetPkg/DuetPkgX64.dsc b/DuetPkg/DuetPkgX64.dsc index 65c0d14019..70b159dd82 100644 --- a/DuetPkg/DuetPkgX64.dsc +++ b/DuetPkg/DuetPkgX64.dsc @@ -85,6 +85,7 @@ SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf # # Platform # @@ -192,6 +193,7 @@ } MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf diff --git a/MdeModulePkg/Include/Library/CustomizedDisplayLib.h b/MdeModulePkg/Include/Library/CustomizedDisplayLib.h new file mode 100644 index 0000000000..31e1091e88 --- /dev/null +++ b/MdeModulePkg/Include/Library/CustomizedDisplayLib.h @@ -0,0 +1,356 @@ +/** @file + This library class defines a set of interfaces to customize Display module + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __CUSTOMIZED_DISPLAY_LIB_H__ +#define __CUSTOMIZED_DISPLAY_LIB_H__ + +#include + +/** ++------------------------------------------------------------------------------+ +| Setup Page | ++------------------------------------------------------------------------------+ + +Statement +Statement +Statement + + + + + ++------------------------------------------------------------------------------+ +| F9=Reset to Defaults F10=Save | +| ^"=Move Highlight Toggles Checkbox Esc=Exit | ++------------------------------------------------------------------------------+ + StatusBar +**/ + +/** + This funtion defines Page Frame and Backgroud. + + Based on the above layout, it will be responsible for HeaderHeight, FooterHeight, + StatusBarHeight and Backgroud. And, it will reserve Screen for Statement. + + @param[in] FormData Form Data to be shown in Page. + @param[out] ScreenForStatement Screen to be used for Statement. (Prompt, Value and Help) + + @return Status +**/ +EFI_STATUS +EFIAPI +DisplayPageFrame ( + IN FORM_DISPLAY_ENGINE_FORM *FormData, + OUT EFI_SCREEN_DESCRIPTOR *ScreenForStatement + ); + +/** + Clear Screen to the initial state. +**/ +VOID +EFIAPI +ClearDisplayPage ( + VOID + ); + +/** + This function updates customized key panel's help information. + The library will prepare those Strings for the basic key, ESC, Enter, Up/Down/Left/Right, +/-. + and arrange them in Footer panel. + + @param[in] FormData Form Data to be shown in Page. FormData has the highlighted statement. + @param[in] Statement The statement current selected. + @param[in] Selected Whether or not a tag be selected. TRUE means Enter has hit this question. +**/ +VOID +EFIAPI +RefreshKeyHelp ( + IN FORM_DISPLAY_ENGINE_FORM *FormData, + IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, + IN BOOLEAN Selected + ); + +/** + Update status bar. + + This function updates the status bar on the bottom of menu screen. It just shows StatusBar. + Original logic in this function should be splitted out. + + @param[in] MessageType The type of message to be shown. InputError or Configuration Changed. + @param[in] State Show or Clear Message. +**/ +VOID +EFIAPI +UpdateStatusBar ( + IN UINTN MessageType, + IN BOOLEAN State + ); + +/** + Create popup window. + + This function draws OEM/Vendor specific pop up windows. + + @param[out] Key User Input Key + @param ... String to be shown in Popup. The variable argument list is terminated by a NULL. + +**/ +VOID +EFIAPI +CreateDialog ( + OUT EFI_INPUT_KEY *Key, OPTIONAL + ... + ); + +/** + Confirm how to handle the changed data. + + @return Action BROWSER_ACTION_SUBMIT, BROWSER_ACTION_DISCARD or other values. +**/ +UINTN +EFIAPI +ConfirmDataChange ( + VOID + ); + +/** + OEM specifies whether Setup exits Page by ESC key. + + This function customized the behavior that whether Setup exits Page so that + system able to boot when configuration is not changed. + + @retval TRUE Exits FrontPage + @retval FALSE Don't exit FrontPage. +**/ +BOOLEAN +EFIAPI +FormExitPolicy ( + VOID + ); + +/** + Set Timeout value for a ceratain Form to get user response. + + This function allows to set timeout value on a ceratain form if necessary. + If timeout is not zero, the form will exit if user has no response in timeout. + + @param[in] FormData Form Data to be shown in Page + + @return 0 No timeout for this form. + @return > 0 Timeout value in 100 ns units. +**/ +UINT64 +EFIAPI +FormExitTimeout ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ); + +// +// Print Functions +// +/** + Prints a unicode string to the default console, at + the supplied cursor position, using L"%s" format. + + @param Column The cursor position to print the string at. When it is -1, use current Position. + @param Row The cursor position to print the string at. When it is -1, use current Position. + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +EFIAPI +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *String + ); + + +/** + Prints a unicode string with the specified width to the default console, at + the supplied cursor position, using L"%s" format. + + @param Column The cursor position to print the string at. When it is -1, use current Position. + @param Row The cursor position to print the string at. When it is -1, use current Position. + @param String String pointer. + @param Width Width for String to be printed. If the print length of String < Width, + Space char (L' ') will be used to append String. + + @return Length of string printed to the console + +**/ +UINTN +EFIAPI +PrintStringAtWithWidth ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *String, + IN UINTN Width + ); + +/** + Prints a chracter to the default console, at + the supplied cursor position, using L"%c" format. + + @param Column The cursor position to print the string at. When it is -1, use current Position. + @param Row The cursor position to print the string at. When it is -1, use current Position. + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +EFIAPI +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ); + +/** + Clear retangle with specified text attribute. + + @param LeftColumn Left column of retangle. + @param RightColumn Right column of retangle. + @param TopRow Start row of retangle. + @param BottomRow End row of retangle. + @param TextAttribute The character foreground and background. + +**/ +VOID +EFIAPI +ClearLines ( + IN UINTN LeftColumn, + IN UINTN RightColumn, + IN UINTN TopRow, + IN UINTN BottomRow, + IN UINTN TextAttribute + ); + +// +// Color Setting Functions +// +/** + Get OEM/Vendor specific popup attribute colors. + + @retval Byte code color setting for popup color. +**/ +UINT8 +EFIAPI +GetPopupColor ( + VOID + ); + +/** + Get OEM/Vendor specific popup attribute colors. + + @retval Byte code color setting for popup inverse color. +**/ +UINT8 +EFIAPI +GetPopupInverseColor ( + VOID + ); + +/** + Get OEM/Vendor specific PickList color attribute. + + @retval Byte code color setting for pick list color. +**/ +UINT8 +EFIAPI +GetPickListColor ( + VOID + ); + +/** + Get OEM/Vendor specific arrow color attribute. + + @retval Byte code color setting for arrow color. +**/ +UINT8 +EFIAPI +GetArrowColor ( + VOID + ); + +/** + Get OEM/Vendor specific info text color attribute. + + @retval Byte code color setting for info text color. +**/ +UINT8 +EFIAPI +GetInfoTextColor ( + VOID + ); + +/** + Get OEM/Vendor specific help text color attribute. + + @retval Byte code color setting for help text color. +**/ +UINT8 +EFIAPI +GetHelpTextColor ( + VOID + ); + +/** + Get OEM/Vendor specific grayed out text color attribute. + + @retval Byte code color setting for grayed out text color. +**/ +UINT8 +EFIAPI +GetGrayedTextColor ( + VOID + ); + +/** + Get OEM/Vendor specific highlighted text color attribute. + + @retval Byte code color setting for highlight text color. +**/ +UINT8 +EFIAPI +GetHighlightTextColor ( + VOID + ); + +/** + Get OEM/Vendor specific field text color attribute. + + @retval Byte code color setting for field text color. +**/ +UINT8 +EFIAPI +GetFieldTextColor ( + VOID + ); + +/** + Get OEM/Vendor specific subtitle text color attribute. + + @retval Byte code color setting for subtitle text color. +**/ +UINT8 +EFIAPI +GetSubTitleTextColor ( + VOID + ); + +#endif diff --git a/MdeModulePkg/Include/Protocol/DisplayProtocol.h b/MdeModulePkg/Include/Protocol/DisplayProtocol.h new file mode 100644 index 0000000000..3be85667d3 --- /dev/null +++ b/MdeModulePkg/Include/Protocol/DisplayProtocol.h @@ -0,0 +1,350 @@ +/** @file + FormDiplay protocol to show Form + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __DISPLAY_PROTOCOL_H__ +#define __DISPLAY_PROTOCOL_H__ + +#include + +#define EDKII_FORM_DISPLAY_ENGINE_PROTOCOL_GUID \ + { 0x9bbe29e9, 0xfda1, 0x41ec, { 0xad, 0x52, 0x45, 0x22, 0x13, 0x74, 0x2d, 0x2e } } + +// +// Do nothing. +// +#define BROWSER_ACTION_NONE BIT16 +// +// ESC Exit +// +#define BROWSER_ACTION_FORM_EXIT BIT17 + +#define BROWSER_SUCCESS 0x0 +#define BROWSER_ERROR BIT31 +#define BROWSER_SUBMIT_FAIL BROWSER_ERROR | 0x01 +#define BROWSER_NO_SUBMIT_IF BROWSER_ERROR | 0x02 +#define BROWSER_FORM_NOT_FOUND BROWSER_ERROR | 0x03 +#define BROWSER_FORM_SUPPRESS BROWSER_ERROR | 0x04 +#define BROWSER_PROTOCOL_NOT_FOUND BROWSER_ERROR | 0x05 + +#define FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1 0x10000 +#define FORM_DISPLAY_ENGINE_VERSION_1 0x10000 + +typedef struct { + // + // HII Data Type + // + UINT8 Type; + // + // Buffer Data and Length if Type is EFI_IFR_TYPE_BUFFER or EFI_IFR_TYPE_STRING + // + UINT8 *Buffer; + UINT16 BufferLen; + EFI_IFR_TYPE_VALUE Value; +} EFI_HII_VALUE; + +#define DISPLAY_QUESTION_OPTION_SIGNATURE SIGNATURE_32 ('Q', 'O', 'P', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + // + // OneOfOption Data + // + EFI_IFR_ONE_OF_OPTION *OptionOpCode; + // + // Option ImageId and AnimationId + // + EFI_IMAGE_ID ImageId; + EFI_ANIMATION_ID AnimationId; +} DISPLAY_QUESTION_OPTION; + +#define DISPLAY_QUESTION_OPTION_FROM_LINK(a) CR (a, DISPLAY_QUESTION_OPTION, Link, DISPLAY_QUESTION_OPTION_SIGNATURE) + +typedef struct _FORM_DISPLAY_ENGINE_STATEMENT FORM_DISPLAY_ENGINE_STATEMENT; +typedef struct _FORM_DISPLAY_ENGINE_FORM FORM_DISPLAY_ENGINE_FORM; + +#define STATEMENT_VALID 0x0 +#define STATEMENT_INVALID BIT31 + +#define INCOSISTENT_IF_TRUE STATEMENT_INVALID | 0x01 +#define WARNING_IF_TRUE STATEMENT_INVALID | 0x02 +#define STRING_TOO_LONG STATEMENT_INVALID | 0x03 +// ... to be extended. + +typedef struct { + // + // StringId for INCONSITENT_IF or WARNING_IF + // + EFI_STRING_ID StringId; + // + // TimeOut for WARNING_IF + // + UINT8 TimeOut; +} STATEMENT_ERROR_INFO; + +/** + Perform value check for a question. + + @param Form Form where Statement is in. + @param Statement Value will check for it. + @param Value New value will be checked. + + @retval Status Value Status + +**/ +typedef +UINT32 +(EFIAPI *VALIDATE_QUESTION) ( + IN FORM_DISPLAY_ENGINE_FORM *Form, + IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, + IN EFI_HII_VALUE *Value, + OUT STATEMENT_ERROR_INFO *ErrorInfo + ); + +/** + Perform Password check. + Passwork may be encrypted by driver that requires the specific check. + + @param Form Form where Password Statement is in. + @param Statement Password statement + @param PasswordString Password string to be checked. It may be NULL. + NULL means to restore password. + "" string can be used to checked whether old password does exist. + + @return Status Status of Password check. +**/ +typedef +EFI_STATUS +(EFIAPI *PASSWORD_CHECK) ( + IN FORM_DISPLAY_ENGINE_FORM *Form, + IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, + IN EFI_STRING PasswordString OPTIONAL + ); + +#define FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'A') + +// +// Attribute for Statement and Form +// +#define HII_DISPLAY_GRAYOUT BIT0 +#define HII_DISPLAY_LOCK BIT1 +#define HII_DISPLAY_READONLY BIT2 +#define HII_DISPLAY_MODAL BIT3 + +struct _FORM_DISPLAY_ENGINE_STATEMENT{ + UINTN Signature; + // + // Version for future structure extension + // + UINTN Version; + // + // link to all the statement which will show in the display form. + // + LIST_ENTRY DisplayLink; + // + // Pointer to statement opcode. + // for Guided Opcode. All buffers will be here if GUIDED opcode scope is set. + // + EFI_IFR_OP_HEADER *OpCode; + // + // Question CurrentValue + // + EFI_HII_VALUE CurrentValue; + // + // Flag to describe whether setting is changed or not. + // Displayer may depend on it to show it with the different color. + // + BOOLEAN SettingChangedFlag; + // + // nested Statement list inside of EFI_IFR_SUBTITLE + // + LIST_ENTRY NestStatementList; + // + // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION) + // + LIST_ENTRY OptionListHead; + // + // Statement attributes: GRAYOUT, LOCK and READONLY + // + UINT32 Attribute; + + // + // ValidateQuestion to do InconsistIf check + // It may be NULL if any value is valid. + // + VALIDATE_QUESTION ValidateQuestion; + + // + // Password additional check. It may be NULL when the additional check is not required. + // + PASSWORD_CHECK PasswordCheck; + + // + // Statement ImageId and AnimationId + // + EFI_IMAGE_ID ImageId; + EFI_ANIMATION_ID AnimationId; +}; + +#define FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK(a) CR (a, FORM_DISPLAY_ENGINE_STATEMENT, DisplayLink, FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE) + +#define BROWSER_HOT_KEY_SIGNATURE SIGNATURE_32 ('B', 'H', 'K', 'S') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_INPUT_KEY *KeyData; + // + // Action is Discard, Default, Submit, Reset and Exit. + // + UINT32 Action; + UINT16 DefaultId; + // + // HotKey Help String + // + EFI_STRING HelpString; +} BROWSER_HOT_KEY; + +#define BROWSER_HOT_KEY_FROM_LINK(a) CR (a, BROWSER_HOT_KEY, Link, BROWSER_HOT_KEY_SIGNATURE) + +#define FORM_DISPLAY_ENGINE_FORM_SIGNATURE SIGNATURE_32 ('F', 'F', 'R', 'M') + +struct _FORM_DISPLAY_ENGINE_FORM { + UINTN Signature; + // + // Version for future structure extension + // + UINTN Version; + // + // Statement List inside of Form + // + LIST_ENTRY StatementListHead; + // + // Statement List outside of Form + // + LIST_ENTRY StatementListOSF; + // + // The input screen dimenstions info. + // + EFI_SCREEN_DESCRIPTOR *ScreenDimensions; + // + // FormSet information + // + EFI_GUID FormSetGuid; + // + // HiiHandle can be used to get String, Image or Animation + // + EFI_HII_HANDLE HiiHandle; + + // + // Form ID and Title. + // + UINT16 FormId; + EFI_STRING_ID FormTitle; + // + // Form Attributes: Lock, Modal. + // + UINT32 Attribute; + // + // Flag to describe whether setting is changed or not. + // Displayer depends on it to show ChangedFlag. + // + BOOLEAN SettingChangedFlag; + + // + // Statement to be HighLighted + // + FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement; + // + // Event to notify Displayer that FormData is updated to be refreshed. + // + EFI_EVENT FormRefreshEvent; + // + // Additional Hotkey registered by BrowserEx protocol. + // + LIST_ENTRY HotKeyListHead; + + // + // Form ImageId and AnimationId + // + EFI_IMAGE_ID ImageId; + EFI_ANIMATION_ID AnimationId; + + // + // If Status is error, display needs to handle it. + // + UINT32 BrowserStatus; + // + // String for error status. It may be NULL. + // + EFI_STRING ErrorString; +}; + +#define FORM_DISPLAY_ENGINE_FORM_FROM_LINK(a) CR (a, FORM_DISPLAY_ENGINE_FORM, Link, FORM_DISPLAY_ENGINE_FORM_SIGNATURE) + +typedef struct { + FORM_DISPLAY_ENGINE_STATEMENT *SelectedStatement; // Selected Statement and InputValue + + EFI_HII_VALUE InputValue; + + UINT32 Action; // If SelectedStatement is NULL, Action will be used. + // Trig Action (Discard, Default, Submit, Reset and Exit) + UINT16 DefaultId; +} USER_INPUT; + +/** + Display one form, and return user input. + + @param FormData Form Data to be shown. + @param UserInputData User input data. + + @retval EFI_SUCCESS Form Data is shown, and user input is got. +**/ +typedef +EFI_STATUS +(EFIAPI *FORM_DISPLAY) ( + IN FORM_DISPLAY_ENGINE_FORM *FormData, + OUT USER_INPUT *UserInputData +); + +/** + Exit Display and Clear Screen to the original state. + +**/ +typedef +VOID +(EFIAPI *EXIT_DISPLAY) ( + VOID +); + +/** + Confirm how to handle the changed data. + + @return Action of Submit, Discard and None +**/ +typedef +UINTN +(EFIAPI *CONFIRM_DATA_CHANGE) ( + VOID +); + +typedef struct { + FORM_DISPLAY FormDisplay; + EXIT_DISPLAY ExitDisplay; + CONFIRM_DATA_CHANGE ConfirmDataChange; +} EDKII_FORM_DISPLAY_ENGINE_PROTOCOL; + +extern EFI_GUID gEdkiiFormDisplayEngineProtocolGuid; +#endif diff --git a/MdeModulePkg/Include/Protocol/FormBrowserEx2.h b/MdeModulePkg/Include/Protocol/FormBrowserEx2.h new file mode 100644 index 0000000000..0a8339d590 --- /dev/null +++ b/MdeModulePkg/Include/Protocol/FormBrowserEx2.h @@ -0,0 +1,90 @@ +/** @file + Extension Form Browser Protocol provides the services that can be used to + register the different hot keys for the standard Browser actions described in UEFI specification. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __FORM_BROWSER_EXTENSION2_H__ +#define __FORM_BROWSER_EXTENSION2_H__ + +#include + +#define EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL_GUID \ + { 0xa770c357, 0xb693, 0x4e6d, { 0xa6, 0xcf, 0xd2, 0x1c, 0x72, 0x8e, 0x55, 0xb }} + +typedef struct _EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL; + +#define BROWSER_EXTENSION2_VERSION_1 0x10000 + +/** + Check whether the browser data has been modified. + + @retval TRUE Browser data is modified. + @retval FALSE No browser data is modified. + +**/ +typedef +BOOLEAN +(EFIAPI *IS_BROWSER_DATA_MODIFIED) ( + VOID + ); + +/** + Execute the action requested by the Action parameter. + + @param[in] Action Execute the request action. + @param[in] DefaultId The default Id info when need to load default value. + + @retval EFI_SUCCESS Execute the request action succss. + +**/ +typedef +EFI_STATUS +(EFIAPI *EXECUTE_ACTION) ( + IN UINT32 Action, + IN UINT16 DefaultId + ); + +#define FORM_ENTRY_INFO_SIGNATURE SIGNATURE_32 ('f', 'e', 'i', 's') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_HII_HANDLE HiiHandle; + EFI_GUID FormSetGuid; + EFI_FORM_ID FormId; + EFI_QUESTION_ID QuestionId; +} FORM_ENTRY_INFO; + +#define FORM_ENTRY_INFO_FROM_LINK(a) CR (a, FORM_ENTRY_INFO, Link, FORM_ENTRY_INFO_SIGNATURE) + +struct _EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL { + /// + /// Version for protocol future extension. + /// + UINT32 Version; + SET_SCOPE SetScope; + REGISTER_HOT_KEY RegisterHotKey; + REGISTER_EXIT_HANDLER RegiserExitHandler; + IS_BROWSER_DATA_MODIFIED IsBrowserDataModified; + EXECUTE_ACTION ExecuteAction; + /// + /// A list of type FORMID_INFO is Browser View Form History List. + /// + LIST_ENTRY FormViewHistoryHead; +}; + +extern EFI_GUID gEdkiiFormBrowserEx2ProtocolGuid; + +#endif + diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Colors.h b/MdeModulePkg/Library/CustomizedDisplayLib/Colors.h similarity index 100% rename from MdeModulePkg/Universal/SetupBrowserDxe/Colors.h rename to MdeModulePkg/Library/CustomizedDisplayLib/Colors.h diff --git a/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c new file mode 100644 index 0000000000..aa28146b02 --- /dev/null +++ b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c @@ -0,0 +1,921 @@ +/** @file + + This library class defines a set of interfaces to customize Display module + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include "CustomizedDisplayLibInternal.h" + +EFI_GUID gCustomizedDisplayLibGuid = { 0x99fdc8fd, 0x849b, 0x4eba, { 0xad, 0x13, 0xfb, 0x96, 0x99, 0xc9, 0xa, 0x4d } }; + +EFI_HII_HANDLE mCDLStringPackHandle; +UINT16 gClassOfVfr; // Formset class information +BOOLEAN gLibIsFirstForm = TRUE; +BANNER_DATA *gBannerData; + +UINTN gFooterHeight; + +/** ++------------------------------------------------------------------------------+ +| Setup Page | ++------------------------------------------------------------------------------+ + +Statement +Statement +Statement + + + + + ++------------------------------------------------------------------------------+ +| F9=Reset to Defaults F10=Save | +| ^"=Move Highlight Toggles Checkbox Esc=Exit | ++------------------------------------------------------------------------------+ + StatusBar +**/ + +/** + This funtion defines Page Frame and Backgroud. + + Based on the above layout, it will be responsible for HeaderHeight, FooterHeight, + StatusBarHeight and Backgroud. And, it will reserve Screen for Statement. + + @param[in] FormData Form Data to be shown in Page. + @param[out] ScreenForStatement Screen to be used for Statement. (Prompt, Value and Help) + + @return Status +**/ +EFI_STATUS +EFIAPI +DisplayPageFrame ( + IN FORM_DISPLAY_ENGINE_FORM *FormData, + OUT EFI_SCREEN_DESCRIPTOR *ScreenForStatement + ) +{ + EFI_STATUS Status; + + ASSERT (FormData != NULL && ScreenForStatement != NULL); + if (FormData == NULL || ScreenForStatement == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = ScreenDiemensionInfoValidate (FormData); + if (EFI_ERROR (Status)) { + return Status; + } + + gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP; + + ProcessExternedOpcode(FormData); + + // + // Calculate the ScreenForStatement. + // + ScreenForStatement->BottomRow = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight; + if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) { + ScreenForStatement->TopRow = gScreenDimensions.TopRow + FRONT_PAGE_HEADER_HEIGHT; + } else { + ScreenForStatement->TopRow = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT; + } + ScreenForStatement->LeftColumn = gScreenDimensions.LeftColumn; + ScreenForStatement->RightColumn = gScreenDimensions.RightColumn; + + if ((gLibIsFirstForm) || ((FormData->Attribute & HII_DISPLAY_MODAL) != 0)) { + // + // Ensure we are in Text mode + // + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + ClearLines (0, gScreenDimensions.RightColumn, 0, gScreenDimensions.BottomRow, KEYHELP_BACKGROUND); + gLibIsFirstForm = FALSE; + } + + // + // Don't print frame for modal form. + // + if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) { + return EFI_SUCCESS; + } + + if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) { + PrintBannerInfo (FormData); + } + + PrintFramework (FormData); + + UpdateStatusBar(NV_UPDATE_REQUIRED, FormData->SettingChangedFlag); + + return EFI_SUCCESS; +} + +/** + This function updates customized key panel's help information. + The library will prepare those Strings for the basic key, ESC, Enter, Up/Down/Left/Right, +/-. + and arrange them in Footer panel. + + @param[in] FormData Form Data to be shown in Page. FormData has the highlighted statement. + @param[in] Statement The statement current selected. + @param[in] Selected Whether or not a tag be selected. TRUE means Enter has hit this question. +**/ +VOID +EFIAPI +RefreshKeyHelp ( + IN FORM_DISPLAY_ENGINE_FORM *FormData, + IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, + IN BOOLEAN Selected + ) +{ + UINTN SecCol; + UINTN ThdCol; + UINTN LeftColumnOfHelp; + UINTN RightColumnOfHelp; + UINTN TopRowOfHelp; + UINTN BottomRowOfHelp; + UINTN StartColumnOfHelp; + EFI_IFR_NUMERIC *NumericOp; + EFI_IFR_DATE *DateOp; + EFI_IFR_TIME *TimeOp; + BOOLEAN HexDisplay; + + ASSERT (FormData != NULL); + if (FormData == NULL) { + return; + } + + gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) { + return; + } + + SecCol = gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3; + ThdCol = gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3 * 2; + + StartColumnOfHelp = gScreenDimensions.LeftColumn + 2; + LeftColumnOfHelp = gScreenDimensions.LeftColumn + 1; + RightColumnOfHelp = gScreenDimensions.RightColumn - 2; + TopRowOfHelp = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1; + BottomRowOfHelp = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 2; + + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + if (Statement == NULL) { + // + // Print Key for Form without showable statement. + // + PrintHotKeyHelpString (FormData); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + return; + } + + HexDisplay = FALSE; + NumericOp = NULL; + DateOp = NULL; + TimeOp = NULL; + if (Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) { + NumericOp = (EFI_IFR_NUMERIC *) Statement->OpCode; + HexDisplay = (NumericOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX; + } else if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) { + DateOp = (EFI_IFR_DATE *) Statement->OpCode; + HexDisplay = (DateOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX; + } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) { + TimeOp = (EFI_IFR_TIME *) Statement->OpCode; + HexDisplay = (TimeOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX; + } + switch (Statement->OpCode->OpCode) { + case EFI_IFR_ORDERED_LIST_OP: + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_NUMERIC_OP: + case EFI_IFR_TIME_OP: + case EFI_IFR_DATE_OP: + if (!Selected) { + PrintHotKeyHelpString (FormData); + + if (gClassOfVfr == FORMSET_CLASS_PLATFORM_SETUP) { + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) || + (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) { + PrintAt ( + 0, + StartColumnOfHelp, + BottomRowOfHelp, + L"%c%c%c%c%s", + ARROW_UP, + ARROW_DOWN, + ARROW_RIGHT, + ARROW_LEFT, + gMoveHighlight + ); + PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber); + } else { + PrintAt (0, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + if (Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP && NumericOp != NULL && LibGetFieldFromNum(Statement->OpCode) != 0) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber); + } + PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); + } + } else { + PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString); + + // + // If it is a selected numeric with manual input, display different message + // + if ((Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) || + (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) || + (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) { + PrintStringAt ( + SecCol, + TopRowOfHelp, + HexDisplay ? gHexNumericInput : gDecNumericInput + ); + } else if (Statement->OpCode->OpCode != EFI_IFR_ORDERED_LIST_OP) { + PrintAt (0, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + } + + if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString); + PrintStringAt (ThdCol, TopRowOfHelp, gMinusString); + } + + PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString); + } + break; + + case EFI_IFR_CHECKBOX_OP: + PrintHotKeyHelpString (FormData); + + if (gClassOfVfr == FORMSET_CLASS_PLATFORM_SETUP) { + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + PrintAt (0, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox); + break; + + case EFI_IFR_REF_OP: + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + case EFI_IFR_TEXT_OP: + case EFI_IFR_ACTION_OP: + case EFI_IFR_RESET_BUTTON_OP: + case EFI_IFR_SUBTITLE_OP: + if (!Selected) { + PrintHotKeyHelpString (FormData); + + if (gClassOfVfr == FORMSET_CLASS_PLATFORM_SETUP) { + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + PrintAt (0, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + if (Statement->OpCode->OpCode != EFI_IFR_TEXT_OP && Statement->OpCode->OpCode != EFI_IFR_SUBTITLE_OP) { + PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); + } + } else { + if (Statement->OpCode->OpCode != EFI_IFR_REF_OP) { + PrintStringAt ( + (gScreenDimensions.RightColumn - LibGetStringWidth (gEnterCommitString) / 2) / 2, + BottomRowOfHelp, + gEnterCommitString + ); + PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString); + } + } + break; + + default: + break; + } +} + +/** + Update status bar. + + This function updates the status bar on the bottom of menu screen. It just shows StatusBar. + Original logic in this function should be splitted out. + + @param[in] MessageType The type of message to be shown. InputError or Configuration Changed. + @param[in] State Show or Clear Message. +**/ +VOID +EFIAPI +UpdateStatusBar ( + IN UINTN MessageType, + IN BOOLEAN State + ) +{ + UINTN Index; + CHAR16 OptionWidth; + + OptionWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3); + + switch (MessageType) { + case INPUT_ERROR: + if (State) { + gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT); + PrintStringAt ( + gScreenDimensions.LeftColumn + OptionWidth, + gScreenDimensions.BottomRow - 1, + gInputErrorMessage + ); + } else { + gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_BACKGROUND); + for (Index = 0; Index < (LibGetStringWidth (gInputErrorMessage) - 2) / 2; Index++) { + PrintStringAt (gScreenDimensions.LeftColumn + OptionWidth + Index, gScreenDimensions.BottomRow - 1, L" "); + } + } + break; + + case NV_UPDATE_REQUIRED: + // + // Global setting support. Show configuration change on every form. + // + if (State) { + gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT); + PrintStringAt ( + gScreenDimensions.LeftColumn + OptionWidth * 2, + gScreenDimensions.BottomRow - 1, + gNvUpdateMessage + ); + } else { + gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_BACKGROUND); + for (Index = 0; Index < (LibGetStringWidth (gNvUpdateMessage) - 2) / 2; Index++) { + PrintStringAt ( + (gScreenDimensions.LeftColumn + OptionWidth * 2 + Index), + gScreenDimensions.BottomRow - 1, + L" " + ); + } + } + break; + + default: + break; + } +} + +/** + Create popup window. It will replace CreateDialog(). + + This function draws OEM/Vendor specific pop up windows. + + @param[out] Key User Input Key + @param ... String to be shown in Popup. The variable argument list is terminated by a NULL. + +**/ +VOID +EFIAPI +CreateDialog ( + OUT EFI_INPUT_KEY *Key, OPTIONAL + ... + ) +{ + VA_LIST Marker; + EFI_INPUT_KEY KeyValue; + EFI_STATUS Status; + UINTN LargestString; + UINTN LineNum; + UINTN Index; + UINTN Count; + CHAR16 Character; + UINTN Start; + UINTN End; + UINTN Top; + UINTN Bottom; + CHAR16 *String; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + UINTN CurrentAttribute; + + // + // If screen dimension info is not ready, get it from console. + // + if (gScreenDimensions.RightColumn == 0 || gScreenDimensions.BottomRow == 0) { + ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &gScreenDimensions.RightColumn, + &gScreenDimensions.BottomRow + ); + } + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + LargestString = 0; + LineNum = 0; + VA_START (Marker, Key); + while ((String = VA_ARG (Marker, CHAR16 *)) != NULL) { + LineNum ++; + + if ((LibGetStringWidth (String) / 2) > LargestString) { + LargestString = (LibGetStringWidth (String) / 2); + } + } + VA_END (Marker); + + if ((LargestString + 2) > DimensionsWidth) { + LargestString = DimensionsWidth - 2; + } + + CurrentAttribute = gST->ConOut->Mode->Attribute; + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); + + // + // Subtract the PopUp width from total Columns, allow for one space extra on + // each end plus a border. + // + Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1; + End = Start + LargestString + 1; + + Top = ((DimensionsHeight - LineNum - 2) / 2) + gScreenDimensions.TopRow - 1; + Bottom = Top + LineNum + 2; + + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (Start, Top, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + } + + Character = BOXDRAW_DOWN_LEFT; + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + Character = BOXDRAW_VERTICAL; + + Count = 0; + VA_START (Marker, Key); + for (Index = Top; Index + 2 < Bottom; Index++, Count++) { + String = VA_ARG (Marker, CHAR16*); + + if (String[0] == CHAR_NULL) { + // + // Passing in a NULL results in a blank space + // + ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ()); + } else if (String[0] == L' ') { + // + // Passing in a space results in the assumption that this is where typing will occur + // + ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND); + PrintStringAt ( + ((DimensionsWidth - LibGetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1, + Index + 1, + String + 1 + ); + } else { + // + // This will clear the background of the line - we never know who might have been + // here before us. This differs from the next clear in that it used the non-reverse + // video for normal printing. + // + ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ()); + PrintStringAt ( + ((DimensionsWidth - LibGetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1, + Index + 1, + String + ); + } + + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); + PrintCharAt (Start, Index + 1, Character); + PrintCharAt (End - 1, Index + 1, Character); + } + VA_END (Marker); + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (Start, Bottom - 1, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintCharAt ((UINTN)-1, (UINTN) -1, Character); + } + + Character = BOXDRAW_UP_LEFT; + PrintCharAt ((UINTN)-1, (UINTN) -1, Character); + + if (Key != NULL) { + Status = WaitForKeyStroke (&KeyValue); + ASSERT_EFI_ERROR (Status); + CopyMem (Key, &KeyValue, sizeof (EFI_INPUT_KEY)); + } + + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); +} + +/** + Confirm how to handle the changed data. + + @return Action BROWSER_ACTION_SUBMIT, BROWSER_ACTION_DISCARD or other values. +**/ +UINTN +EFIAPI +ConfirmDataChange ( + VOID + ) +{ + CHAR16 YesResponse; + CHAR16 NoResponse; + EFI_INPUT_KEY Key; + + gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + + YesResponse = gYesResponse[0]; + NoResponse = gNoResponse[0]; + + // + // If NV flag is up, prompt user + // + do { + CreateDialog (&Key, gLibEmptyString, gSaveChanges, gAreYouSure, gLibEmptyString, NULL); + } while + ( + (Key.ScanCode != SCAN_ESC) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET)) + ); + + if (Key.ScanCode == SCAN_ESC) { + return BROWSER_ACTION_NONE; + } else if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) { + return BROWSER_ACTION_SUBMIT; + } else { + return BROWSER_ACTION_DISCARD; + } +} + +/** + OEM specifies whether Setup exits Page by ESC key. + + This function customized the behavior that whether Setup exits Page so that + system able to boot when configuration is not changed. + + @retval TRUE Exits FrontPage + @retval FALSE Don't exit FrontPage. +**/ +BOOLEAN +EFIAPI +FormExitPolicy ( + VOID + ) +{ + return gClassOfVfr == FORMSET_CLASS_FRONT_PAGE ? FALSE : TRUE; +} + +/** + Set Timeout value for a ceratain Form to get user response. + + This function allows to set timeout value on a ceratain form if necessary. + If timeout is not zero, the form will exit if user has no response in timeout. + + @param[in] FormData Form Data to be shown in Page + + @return 0 No timeout for this form. + @return > 0 Timeout value in 100 ns units. +**/ +UINT64 +EFIAPI +FormExitTimeout ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ) +{ + return 0; +} +// +// Print Functions +// +/** + Prints a unicode string to the default console, at + the supplied cursor position, using L"%s" format. + + @param Column The cursor position to print the string at. When it is -1, use current Position. + @param Row The cursor position to print the string at. When it is -1, use current Position. + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +EFIAPI +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *String + ) +{ + return PrintAt (0, Column, Row, L"%s", String); +} + +/** + Prints a unicode string to the default console, at + the supplied cursor position, using L"%s" format. + + @param Column The cursor position to print the string at. When it is -1, use current Position. + @param Row The cursor position to print the string at. When it is -1, use current Position. + @param String String pointer. + @param Width Width for String. + + @return Length of string printed to the console + +**/ +UINTN +EFIAPI +PrintStringAtWithWidth ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *String, + IN UINTN Width + ) +{ + return PrintAt (Width, Column, Row, L"%s", String); +} + +/** + Prints a chracter to the default console, at + the supplied cursor position, using L"%c" format. + + @param Column The cursor position to print the string at. When it is -1, use current Position. + @param Row The cursor position to print the string at. When it is -1, use current Position. + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +EFIAPI +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ) +{ + return PrintAt (0, Column, Row, L"%c", Character); +} + +/** + Clear retangle with specified text attribute. + + @param LeftColumn Left column of retangle. + @param RightColumn Right column of retangle. + @param TopRow Start row of retangle. + @param BottomRow End row of retangle. + @param TextAttribute The character foreground and background. + +**/ +VOID +EFIAPI +ClearLines ( + IN UINTN LeftColumn, + IN UINTN RightColumn, + IN UINTN TopRow, + IN UINTN BottomRow, + IN UINTN TextAttribute + ) +{ + CHAR16 *Buffer; + UINTN Row; + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + ASSERT (Buffer != NULL); + + // + // Set foreground and background as defined + // + gST->ConOut->SetAttribute (gST->ConOut, TextAttribute); + + // + // Much faster to buffer the long string instead of print it a character at a time + // + LibSetUnicodeMem (Buffer, RightColumn - LeftColumn, L' '); + + // + // Clear the desired area with the appropriate foreground/background + // + for (Row = TopRow; Row <= BottomRow; Row++) { + PrintStringAt (LeftColumn, Row, Buffer); + } + + gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow); + + FreePool (Buffer); +} + +// +// Color Setting Functions +// + +/** + Get OEM/Vendor specific popup attribute colors. + + @retval Byte code color setting for popup color. +**/ +UINT8 +EFIAPI +GetPopupColor ( + VOID + ) +{ + return POPUP_TEXT | POPUP_BACKGROUND; +} + +/** + Get OEM/Vendor specific popup attribute colors. + + @retval Byte code color setting for popup inverse color. +**/ +UINT8 +EFIAPI +GetPopupInverseColor ( + VOID + ) +{ + return POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND; +} + +/** + Get OEM/Vendor specific PickList color attribute. + + @retval Byte code color setting for pick list color. +**/ +UINT8 +EFIAPI +GetPickListColor ( + VOID + ) +{ + return PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND; +} + +/** + Get OEM/Vendor specific arrow color attribute. + + @retval Byte code color setting for arrow color. +**/ +UINT8 +EFIAPI +GetArrowColor ( + VOID + ) +{ + return ARROW_TEXT | ARROW_BACKGROUND; +} + +/** + Get OEM/Vendor specific info text color attribute. + + @retval Byte code color setting for info text color. +**/ +UINT8 +EFIAPI +GetInfoTextColor ( + VOID + ) +{ + return INFO_TEXT | FIELD_BACKGROUND; +} + +/** + Get OEM/Vendor specific help text color attribute. + + @retval Byte code color setting for help text color. +**/ +UINT8 +EFIAPI +GetHelpTextColor ( + VOID + ) +{ + return HELP_TEXT | FIELD_BACKGROUND; +} + +/** + Get OEM/Vendor specific grayed out text color attribute. + + @retval Byte code color setting for grayed out text color. +**/ +UINT8 +EFIAPI +GetGrayedTextColor ( + VOID + ) +{ + return FIELD_TEXT_GRAYED | FIELD_BACKGROUND; +} + +/** + Get OEM/Vendor specific highlighted text color attribute. + + @retval Byte code color setting for highlight text color. +**/ +UINT8 +EFIAPI +GetHighlightTextColor ( + VOID + ) +{ + return PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor); +} + +/** + Get OEM/Vendor specific field text color attribute. + + @retval Byte code color setting for field text color. +**/ +UINT8 +EFIAPI +GetFieldTextColor ( + VOID + ) +{ + return PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND; +} + +/** + Get OEM/Vendor specific subtitle text color attribute. + + @retval Byte code color setting for subtitle text color. +**/ +UINT8 +EFIAPI +GetSubTitleTextColor ( + VOID + ) +{ + return PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND; +} + +/** + Clear Screen to the initial state. +**/ +VOID +EFIAPI +ClearDisplayPage ( + VOID + ) +{ + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->ClearScreen (gST->ConOut); + gLibIsFirstForm = TRUE; +} + +/** + Constructor of Customized Display Library Instance. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +CustomizedDisplayLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + mCDLStringPackHandle = HiiAddPackages (&gCustomizedDisplayLibGuid, ImageHandle, CustomizedDisplayLibStrings, NULL); + ASSERT (mCDLStringPackHandle != NULL); + + InitializeLibStrings(); + + return EFI_SUCCESS; +} + +/** + Destructor of Customized Display Library Instance. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The destructor completed successfully. + @retval Other value The destructor did not complete successfully. + +**/ +EFI_STATUS +EFIAPI +CustomizedDisplayLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + HiiRemovePackages(mCDLStringPackHandle); + + FreeLibStrings (); + + return EFI_SUCCESS; +} + diff --git a/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf new file mode 100644 index 0000000000..ade45b6a51 --- /dev/null +++ b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf @@ -0,0 +1,74 @@ +## +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +## +## @file +# +# General BDS defines and produce general interfaces for platform BDS driver including: +# 1) BDS boot policy interface; +# 2) BDS boot device connect interface; +# 3) BDS Misc interfaces for mainting boot variable, ouput string, etc. +# +# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CustomizedDisplayLib + FILE_GUID = 80B92017-EC64-4923-938D-94FAEE85832E + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = CustomizedDisplayLib|DXE_DRIVER UEFI_APPLICATION + CONSTRUCTOR = CustomizedDisplayLibConstructor + DESTRUCTOR = CustomizedDisplayLibDestructor +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + CustomizedDisplayLib.c + Colors.h + CustomizedDisplayLibInternal.h + CustomizedDisplayLibInternal.c + CustomizedDisplayLib.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + PrintLib + HiiLib + DevicePathLib + PcdLib + +[Guids] + gEfiIfrTianoGuid + +[Protocols] + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserSubtitleTextColor ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextColor ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextHighlightColor ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldBackgroundHighlightColor ## CONSUMES \ No newline at end of file diff --git a/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni new file mode 100644 index 0000000000000000000000000000000000000000..18a5c3b56347a846506d113f47bbebf92645a1f0 GIT binary patch literal 7256 zcmd6s+fo}x5Qh6YRe6UsTsScX>^MgkI3l;wa#BwF>V}(=+<#?^&C*#Gcp`*O&GMrP<*#v8r|K%r32KEo<64>(llt zJFu^Leq+zLzU6ItP?!Xn)~4l=o$#&^x{RUw9$#C$wQYu)3iWD{j@=8TBkR$( zYah5D(sIrgY~5aEP;G*wMXQ8yyNuTiW1mvqW9&noeOera@&RZ&c1latUDB^j`-Cq- zqj_4qoiJLIUZZqF?-S|{cxwkl8aIxw-iL!3KJeaRggx8mu366m3XPp2@wrX|>Ntv! z32$r2i)8B9ai-sbZP+5^x7V2i%43y0k6OXhgB$d}*#8Wl6mc&a6HX6R*O5 zOpWVCs6WywkLo%z&gLbp_6Pkt0}h0#pJ7%O)JGRDgPqB?oL#l=2Ciq2zl(-uL6Bv? z$CrJuA7X9SYi1bb9lyv)d`g~WtAVP4{jAv%_lm7jUV+mDR`uNE>k1aO#ak^fy=8Tt zHNK}Kq*_?PqHDC+2qUlYCQH_Rf~UsSs1rOFLRqD!Lu`rtM!j&Yg&9?@Fq4qg`M$!a z8e=WYzD`Nl^-Xhb(n@VKtG9YhTlL)G`Gy)Hmj~7cv$zyB+a8XSj=lmH4eUyDF5+jA zxA;t`@4&ZgK~_;mm#4hFENGcfzd>D})@MjAue?B8@_`M$b{St@(JJU$33^o<*>8Wu z_-?oEzw*9g#?zS5ihH0q4)!DVvlxn`o5qr!45FQ6cDd(mGQ6oYiRALtX7F`+rL1)t z&56YccvGFMv4;gtgns|+a}1JcdmS`7!BcX!?Jw@?=e>Nk=$S5|Yg`)KWj?plI#w*M zZ@*F;=giau`E~TdKNlqM$n?tQg9fE*X+bumDBdMzI>y`Qyi1EBd|9T7@Ks^C6Ig43 zD}njPLzGwGjvBa`$11+F$|WBx$7&JItQ8dF^c6>3irt6FWyE+DFy4<(MW!kdsDU0n z9iKJ);sATBvG&Nj9|C_7(?*Cdia2*+?5-?jJ*kWZMs$&}ad~XSk!7jaD=Vxyzl2CC zPptE{O3e24Dl2{Qdl^oqi0#Tu=dsU2d(Zl#xRBVd#KRLxFu zY*Fh?Lgp)kM_}yU5Yx17YZWTzb9q^cFy>?0RA5dSfbwu(-Q(KeIeY?wv$3rWj&B`o zLM4pukHV^KSnI^c8`x9)m&M(WzcTE(-Hm2%5sVkCvE%a9=o|Z3n=%p4*0idY<8Td6 zQq*6D%_Z*2B=y`x1GimeIGhjpr(54L2(|xIuI2mCaj~XV$+=Q?q#c&_u)Y^OMWg4z z7L_NfzBu-2cTpWiJ;gljDt3caHn7Xl43^>UnLTHJ{({~4clN#gU_aVVpp5%kk1s7y zCrHr7i?tJsx#(@WyIXw`+I&1LM%#l;ap>$Sw?7PD+NNAjMF91{7N)OoYv`$PGS_Rx|{`V zVhK$yk5$?iXxH*P^_^kVA2sjY>xz)(?YIc(0*IB(#$B|p@YV2Dan>V;&d215eZFh2 zR&2|4BJM8np+WAXlK@5ERqh*H6?9Ph-(2got{wK(&5(VhCw9K7`fga~a^s4>cSSe} z``L2?t^6Kici~GXFFI=}%VUuhD+m_YgkGHo7q9u&vTkEE{iDk6`iWd zKX%aXR*-pX_{GoIM#X?KdfpkEmgCHM9p5Z-9TrB(tGY5W*T*JvoH;MEBA@4>T6=UB zsyL|gxiVK7nYFsaxTmZ`CC^IRL`&r-y}=j#TcMp&tk3tWJwTr939HVu68nSoK{EL1VU#4VotrGOjBd(VWFyF-j6C5q zaEG7%@91!kT1o%4iM;EC{4ti2w)Ou-BxyHjD6c8+;ip|`FST!nyyOJUk1PJA3>?{? x85WdN=mf!;@O?>hAfao!NRwG^JU7w4P +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include "CustomizedDisplayLibInternal.h" + +EFI_SCREEN_DESCRIPTOR gScreenDimensions; +CHAR16 *mLibUnknownString; +extern EFI_HII_HANDLE mCDLStringPackHandle; +CHAR16 *mSpaceBuffer; +#define SPACE_BUFFER_SIZE 1000 + +// +// Browser Global Strings +// +CHAR16 *gEnterString; +CHAR16 *gEnterCommitString; +CHAR16 *gEnterEscapeString; +CHAR16 *gEscapeString; +CHAR16 *gMoveHighlight; +CHAR16 *gDecNumericInput; +CHAR16 *gHexNumericInput; +CHAR16 *gToggleCheckBox; +CHAR16 *gLibEmptyString; +CHAR16 *gAreYouSure; +CHAR16 *gYesResponse; +CHAR16 *gNoResponse; +CHAR16 *gPlusString; +CHAR16 *gMinusString; +CHAR16 *gAdjustNumber; +CHAR16 *gSaveChanges; +CHAR16 *gNvUpdateMessage; +CHAR16 *gInputErrorMessage; + +/** + + Print banner info for front page. + + @param[in] FormData Form Data to be shown in Page + +**/ +VOID +PrintBannerInfo ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ) +{ + UINT8 Line; + UINT8 Alignment; + CHAR16 *StrFrontPageBanner; + UINT8 RowIdx; + UINT8 ColumnIdx; + + // + // ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND); + // + ClearLines ( + gScreenDimensions.LeftColumn, + gScreenDimensions.RightColumn, + gScreenDimensions.TopRow, + FRONT_PAGE_HEADER_HEIGHT - 1 + gScreenDimensions.TopRow, + BANNER_TEXT | BANNER_BACKGROUND + ); + + // + // for (Line = 0; Line < BANNER_HEIGHT; Line++) { + // + for (Line = (UINT8) gScreenDimensions.TopRow; Line < BANNER_HEIGHT + (UINT8) gScreenDimensions.TopRow; Line++) { + // + // for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) { + // + for (Alignment = (UINT8) gScreenDimensions.LeftColumn; + Alignment < BANNER_COLUMNS + (UINT8) gScreenDimensions.LeftColumn; + Alignment++ + ) { + RowIdx = (UINT8) (Line - (UINT8) gScreenDimensions.TopRow); + ColumnIdx = (UINT8) (Alignment - (UINT8) gScreenDimensions.LeftColumn); + + ASSERT (RowIdx < BANNER_HEIGHT && ColumnIdx < BANNER_COLUMNS); + + if (gBannerData!= NULL && gBannerData->Banner[RowIdx][ColumnIdx] != 0x0000) { + StrFrontPageBanner = LibGetToken (gBannerData->Banner[RowIdx][ColumnIdx], FormData->HiiHandle); + } else { + continue; + } + + switch (Alignment - gScreenDimensions.LeftColumn) { + case 0: + // + // Handle left column + // + PrintStringAt (gScreenDimensions.LeftColumn + BANNER_LEFT_COLUMN_INDENT, Line, StrFrontPageBanner); + break; + + case 1: + // + // Handle center column + // + PrintStringAt ( + gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3, + Line, + StrFrontPageBanner + ); + break; + + case 2: + // + // Handle right column + // + PrintStringAt ( + gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) * 2 / 3, + Line, + StrFrontPageBanner + ); + break; + } + + FreePool (StrFrontPageBanner); + } + } +} + +/** + Print framework and form title for a page. + + @param[in] FormData Form Data to be shown in Page +**/ +VOID +PrintFramework ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ) +{ + UINTN Index; + CHAR16 Character; + CHAR16 *Buffer; + UINTN Row; + CHAR16 *TitleStr; + + if (gClassOfVfr != FORMSET_CLASS_PLATFORM_SETUP) { + // + // Only Setup page needs Framework + // + ClearLines ( + gScreenDimensions.LeftColumn, + gScreenDimensions.RightColumn, + gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, + gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1, + KEYHELP_TEXT | KEYHELP_BACKGROUND + ); + return; + } + + Buffer = AllocateZeroPool (0x10000); + ASSERT (Buffer != NULL); + Character = BOXDRAW_HORIZONTAL; + for (Index = 0; Index + 2 < (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn); Index++) { + Buffer[Index] = Character; + } + + // + // Print Top border line + // +------------------------------------------------------------------------------+ + // ? ? + // +------------------------------------------------------------------------------+ + // + gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND); + Character = BOXDRAW_DOWN_RIGHT; + + PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.TopRow, Character); + PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer); + + Character = BOXDRAW_DOWN_LEFT; + PrintCharAt ((UINTN) -1, (UINTN) -1, Character); + + Character = BOXDRAW_VERTICAL; + for (Row = gScreenDimensions.TopRow + 1; Row <= gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) { + PrintCharAt (gScreenDimensions.LeftColumn, Row, Character); + PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character); + } + + // + // Print Form Title + // + ClearLines ( + gScreenDimensions.LeftColumn + 1, + gScreenDimensions.RightColumn - 1, + gScreenDimensions.TopRow + 1, + gScreenDimensions.TopRow + 1, + TITLE_TEXT | TITLE_BACKGROUND + ); + + TitleStr = LibGetToken (FormData->FormTitle, FormData->HiiHandle); + ASSERT (TitleStr != NULL); + PrintStringAt ( + (gScreenDimensions.RightColumn + gScreenDimensions.LeftColumn - LibGetStringWidth (TitleStr) / 2) / 2, + gScreenDimensions.TopRow + 1, + TitleStr + ); + FreePool (TitleStr); + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character); + PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer); + + Character = BOXDRAW_UP_LEFT; + PrintCharAt ((UINTN) -1, (UINTN) -1, Character); + + // + // Print Bottom border line + // +------------------------------------------------------------------------------+ + // ? ? + // +------------------------------------------------------------------------------+ + // + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, Character); + + PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer); + + Character = BOXDRAW_DOWN_LEFT; + PrintCharAt ((UINTN) -1, (UINTN) -1, Character); + Character = BOXDRAW_VERTICAL; + for (Row = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1; + Row <= gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 2; + Row++ + ) { + PrintCharAt (gScreenDimensions.LeftColumn, Row, Character); + PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1, Character); + + PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer); + + Character = BOXDRAW_UP_LEFT; + PrintCharAt ((UINTN) -1, (UINTN) -1, Character); + + FreePool (Buffer); +} + +/** + Process some op code which is not recognized by browser core. + + @param OpCodeData The pointer to the op code buffer. + + @return EFI_SUCCESS Pass the statement success. + +**/ +VOID +ProcessUserOpcode( + IN EFI_IFR_OP_HEADER *OpCodeData + ) +{ + switch (OpCodeData->OpCode) { + case EFI_IFR_GUID_OP: + if (CompareGuid (&gEfiIfrTianoGuid, (EFI_GUID *)((CHAR8*) OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { + // + // Tiano specific GUIDed opcodes + // + switch (((EFI_IFR_GUID_LABEL *) OpCodeData)->ExtendOpCode) { + case EFI_IFR_EXTEND_OP_LABEL: + // + // just ignore label + // + break; + + case EFI_IFR_EXTEND_OP_BANNER: + // + // Only in front page form set, we care about the banner data. + // + if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) { + // + // Initialize Driver private data + // + if (gBannerData == NULL) { + gBannerData = AllocateZeroPool (sizeof (BANNER_DATA)); + ASSERT (gBannerData != NULL); + } + + CopyMem ( + &gBannerData->Banner[((EFI_IFR_GUID_BANNER *) OpCodeData)->LineNumber][ + ((EFI_IFR_GUID_BANNER *) OpCodeData)->Alignment], + &((EFI_IFR_GUID_BANNER *) OpCodeData)->Title, + sizeof (EFI_STRING_ID) + ); + } + break; + + case EFI_IFR_EXTEND_OP_SUBCLASS: + if (((EFI_IFR_GUID_SUBCLASS *) OpCodeData)->SubClass == EFI_FRONT_PAGE_SUBCLASS) { + gClassOfVfr = FORMSET_CLASS_FRONT_PAGE; + } + break; + + default: + break; + } + } + break; + + default: + break; + } +} + +/** + Process some op codes which is out side of current form. + + @param FormData Pointer to the form data. + + @return EFI_SUCCESS Pass the statement success. + +**/ +VOID +ProcessExternedOpcode ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ) +{ + LIST_ENTRY *Link; + FORM_DISPLAY_ENGINE_STATEMENT *Statement; + + Link = GetFirstNode (&FormData->StatementListOSF); + while (!IsNull (&FormData->StatementListOSF, Link)) { + Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&FormData->StatementListOSF, Link); + + ProcessUserOpcode(Statement->OpCode); + } + + Link = GetFirstNode (&FormData->StatementListHead); + while (!IsNull (&FormData->StatementListHead, Link)) { + Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&FormData->StatementListHead, Link); + + ProcessUserOpcode(Statement->OpCode); + } +} + +/** + Validate the input screen diemenstion info. + + @param FormData The input form data info. + + @return EFI_SUCCESS The input screen info is acceptable. + @return EFI_INVALID_PARAMETER The input screen info is not acceptable. + +**/ +EFI_STATUS +ScreenDiemensionInfoValidate ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ) +{ + LIST_ENTRY *Link; + UINTN Index; + + // + // Calculate total number of Register HotKeys. + // + Index = 0; + if (!IsListEmpty (&FormData->HotKeyListHead)){ + Link = GetFirstNode (&FormData->HotKeyListHead); + while (!IsNull (&FormData->HotKeyListHead, Link)) { + Link = GetNextNode (&FormData->HotKeyListHead, Link); + Index ++; + } + } + + // + // Show three HotKeys help information on one row. + // + gFooterHeight = FOOTER_HEIGHT + (Index / 3); + + + ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &gScreenDimensions.RightColumn, + &gScreenDimensions.BottomRow + ); + + // + // Check local dimension vs. global dimension. + // + if (FormData->ScreenDimensions != NULL) { + if ((gScreenDimensions.RightColumn < FormData->ScreenDimensions->RightColumn) || + (gScreenDimensions.BottomRow < FormData->ScreenDimensions->BottomRow) + ) { + return EFI_INVALID_PARAMETER; + } else { + // + // Local dimension validation. + // + if ((FormData->ScreenDimensions->RightColumn > FormData->ScreenDimensions->LeftColumn) && + (FormData->ScreenDimensions->BottomRow > FormData->ScreenDimensions->TopRow) && + ((FormData->ScreenDimensions->RightColumn - FormData->ScreenDimensions->LeftColumn) > 2) && + ((FormData->ScreenDimensions->BottomRow - FormData->ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT + + FRONT_PAGE_HEADER_HEIGHT + gFooterHeight + 3)) { + CopyMem (&gScreenDimensions, (VOID *) FormData->ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + } else { + return EFI_INVALID_PARAMETER; + } + } + } + + return EFI_SUCCESS; +} + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The package list in the HII database to search for + the specified string. + + @return The output string. + +**/ +CHAR16 * +LibGetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STRING String; + + String = HiiGetString (HiiHandle, Token, NULL); + if (String == NULL) { + String = AllocateCopyPool (StrSize (mLibUnknownString), mLibUnknownString); + ASSERT (String != NULL); + } + + return (CHAR16 *) String; +} + + +/** + Count the storage space of a Unicode string. + + This function handles the Unicode string with NARROW_CHAR + and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR + does not count in the resultant output. If a WIDE_CHAR is + hit, then 2 Unicode character will consume an output storage + space with size of CHAR16 till a NARROW_CHAR is hit. + + If String is NULL, then ASSERT (). + + @param String The input string to be counted. + + @return Storage space for the input string. + +**/ +UINTN +LibGetStringWidth ( + IN CHAR16 *String + ) +{ + UINTN Index; + UINTN Count; + UINTN IncrementValue; + + ASSERT (String != NULL); + if (String == NULL) { + return 0; + } + + Index = 0; + Count = 0; + IncrementValue = 1; + + do { + // + // Advance to the null-terminator or to the first width directive + // + for (; + (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0); + Index++, Count = Count + IncrementValue + ) + ; + + // + // We hit the null-terminator, we now have a count + // + if (String[Index] == 0) { + break; + } + // + // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed + // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2) + // + if (String[Index] == NARROW_CHAR) { + // + // Skip to the next character + // + Index++; + IncrementValue = 1; + } else { + // + // Skip to the next character + // + Index++; + IncrementValue = 2; + } + } while (String[Index] != 0); + + // + // Increment by one to include the null-terminator in the size + // + Count++; + + return Count * sizeof (CHAR16); +} + +/** + Show all registered HotKey help strings on bottom Rows. + + @param FormData The curent input form data info. + +**/ +VOID +PrintHotKeyHelpString ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ) +{ + UINTN CurrentCol; + UINTN CurrentRow; + UINTN BottomRowOfHotKeyHelp; + UINTN ColumnWidth; + UINTN Index; + EFI_SCREEN_DESCRIPTOR LocalScreen; + LIST_ENTRY *Link; + BROWSER_HOT_KEY *HotKey; + + if (IsListEmpty (&FormData->HotKeyListHead)) { + return; + } + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + ColumnWidth = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3; + BottomRowOfHotKeyHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3; + + // + // Calculate total number of Register HotKeys. + // + Index = 0; + Link = GetFirstNode (&FormData->HotKeyListHead); + while (!IsNull (&FormData->HotKeyListHead, Link)) { + HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); + // + // Help string can't exceed ColumnWidth. One Row will show three Help information. + // + if (StrLen (HotKey->HelpString) > ColumnWidth) { + HotKey->HelpString[ColumnWidth] = L'\0'; + } + // + // Calculate help information Column and Row. + // + if ((Index % 3) != 2) { + CurrentCol = LocalScreen.LeftColumn + (2 - Index % 3) * ColumnWidth; + } else { + CurrentCol = LocalScreen.LeftColumn + 2; + } + CurrentRow = BottomRowOfHotKeyHelp - Index / 3; + // + // Print HotKey help string on bottom Row. + // + PrintStringAt (CurrentCol, CurrentRow, HotKey->HelpString); + + // + // Get Next Hot Key. + // + Link = GetNextNode (&FormData->HotKeyListHead, Link); + Index ++; + } + + return; +} + +/** + Get step info from numeric opcode. + + @param[in] OpCode The input numeric op code. + + @return step info for this opcode. +**/ +UINT64 +LibGetFieldFromNum ( + IN EFI_IFR_OP_HEADER *OpCode + ) +{ + EFI_IFR_NUMERIC *NumericOp; + UINT64 Step; + + NumericOp = (EFI_IFR_NUMERIC *) OpCode; + + switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + Step = NumericOp->data.u8.Step; + break; + + case EFI_IFR_NUMERIC_SIZE_2: + Step = NumericOp->data.u16.Step; + break; + + case EFI_IFR_NUMERIC_SIZE_4: + Step = NumericOp->data.u32.Step; + break; + + case EFI_IFR_NUMERIC_SIZE_8: + Step = NumericOp->data.u64.Step; + break; + + default: + Step = 0; + break; + } + + return Step; +} + +/** + Initialize the HII String Token to the correct values. + +**/ +VOID +InitializeLibStrings ( + VOID + ) +{ + mLibUnknownString = L"!"; + + gEnterString = LibGetToken (STRING_TOKEN (ENTER_STRING), mCDLStringPackHandle); + gEnterCommitString = LibGetToken (STRING_TOKEN (ENTER_COMMIT_STRING), mCDLStringPackHandle); + gEnterEscapeString = LibGetToken (STRING_TOKEN (ENTER_ESCAPE_STRING), mCDLStringPackHandle); + gEscapeString = LibGetToken (STRING_TOKEN (ESCAPE_STRING), mCDLStringPackHandle); + gMoveHighlight = LibGetToken (STRING_TOKEN (MOVE_HIGHLIGHT), mCDLStringPackHandle); + gDecNumericInput = LibGetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), mCDLStringPackHandle); + gHexNumericInput = LibGetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), mCDLStringPackHandle); + gToggleCheckBox = LibGetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), mCDLStringPackHandle); + + gAreYouSure = LibGetToken (STRING_TOKEN (ARE_YOU_SURE), mCDLStringPackHandle); + gYesResponse = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_YES), mCDLStringPackHandle); + gNoResponse = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_NO), mCDLStringPackHandle); + gPlusString = LibGetToken (STRING_TOKEN (PLUS_STRING), mCDLStringPackHandle); + gMinusString = LibGetToken (STRING_TOKEN (MINUS_STRING), mCDLStringPackHandle); + gAdjustNumber = LibGetToken (STRING_TOKEN (ADJUST_NUMBER), mCDLStringPackHandle); + gSaveChanges = LibGetToken (STRING_TOKEN (SAVE_CHANGES), mCDLStringPackHandle); + + gLibEmptyString = LibGetToken (STRING_TOKEN (EMPTY_STRING), mCDLStringPackHandle); + + gNvUpdateMessage = LibGetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), mCDLStringPackHandle); + gInputErrorMessage = LibGetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), mCDLStringPackHandle); + + // + // SpaceBuffer; + // + mSpaceBuffer = AllocatePool ((SPACE_BUFFER_SIZE + 1) * sizeof (CHAR16)); + ASSERT (mSpaceBuffer != NULL); + LibSetUnicodeMem (mSpaceBuffer, SPACE_BUFFER_SIZE, L' '); + mSpaceBuffer[SPACE_BUFFER_SIZE] = L'\0'; +} + + +/** + Free the HII String. + +**/ +VOID +FreeLibStrings ( + VOID + ) +{ + FreePool (gEnterString); + FreePool (gEnterCommitString); + FreePool (gEnterEscapeString); + FreePool (gEscapeString); + FreePool (gMoveHighlight); + FreePool (gDecNumericInput); + FreePool (gHexNumericInput); + FreePool (gToggleCheckBox); + + FreePool (gAreYouSure); + FreePool (gYesResponse); + FreePool (gNoResponse); + FreePool (gPlusString); + FreePool (gMinusString); + FreePool (gAdjustNumber); + FreePool (gSaveChanges); + + FreePool (gLibEmptyString); + + FreePool (gNvUpdateMessage); + FreePool (gInputErrorMessage); + + FreePool (mSpaceBuffer); +} + +/** + Wait for a key to be pressed by user. + + @param Key The key which is pressed by user. + + @retval EFI_SUCCESS The function always completed successfully. + +**/ +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ) +{ + EFI_STATUS Status; + UINTN Index; + + while (TRUE) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key); + if (!EFI_ERROR (Status)) { + break; + } + + if (Status != EFI_NOT_READY) { + continue; + } + + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index); + } + return Status; +} + + +/** + Set Buffer to Value for Size bytes. + + @param Buffer Memory to set. + @param Size Number of bytes to set + @param Value Value of the set operation. + +**/ +VOID +LibSetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ) +{ + CHAR16 *Ptr; + + Ptr = Buffer; + while ((Size--) != 0) { + *(Ptr++) = Value; + } +} + +/** + The internal function prints to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL + protocol instance. + + @param Width Width of string to be print. + @param Column The position of the output string. + @param Row The position of the output string. + @param Out The EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance. + @param Fmt The format string. + @param Args The additional argument for the variables in the format string. + + @return Number of Unicode character printed. + +**/ +UINTN +PrintInternal ( + IN UINTN Width, + IN UINTN Column, + IN UINTN Row, + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out, + IN CHAR16 *Fmt, + IN VA_LIST Args + ) +{ + CHAR16 *Buffer; + CHAR16 *BackupBuffer; + UINTN Index; + UINTN PreviousIndex; + UINTN Count; + UINTN PrintWidth; + UINTN CharWidth; + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + BackupBuffer = AllocateZeroPool (0x10000); + ASSERT (Buffer); + ASSERT (BackupBuffer); + + if (Column != (UINTN) -1) { + Out->SetCursorPosition (Out, Column, Row); + } + + UnicodeVSPrint (Buffer, 0x10000, Fmt, Args); + + Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; + + Out->SetAttribute (Out, Out->Mode->Attribute); + + Index = 0; + PreviousIndex = 0; + Count = 0; + PrintWidth = 0; + CharWidth = 1; + + do { + for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) { + BackupBuffer[Index] = Buffer[Index]; + } + + if (Buffer[Index] == 0) { + break; + } + // + // Null-terminate the temporary string + // + BackupBuffer[Index] = 0; + + // + // Print this out, we are about to switch widths + // + Out->OutputString (Out, &BackupBuffer[PreviousIndex]); + Count += StrLen (&BackupBuffer[PreviousIndex]); + PrintWidth += Count * CharWidth; + + // + // Preserve the current index + 1, since this is where we will start printing from next + // + PreviousIndex = Index + 1; + + // + // We are at a narrow or wide character directive. Set attributes and strip it and print it + // + if (Buffer[Index] == NARROW_CHAR) { + // + // Preserve bits 0 - 6 and zero out the rest + // + Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; + Out->SetAttribute (Out, Out->Mode->Attribute); + CharWidth = 1; + } else { + // + // Must be wide, set bit 7 ON + // + Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE; + Out->SetAttribute (Out, Out->Mode->Attribute); + CharWidth = 2; + } + + Index++; + + } while (Buffer[Index] != 0); + + // + // We hit the end of the string - print it + // + Out->OutputString (Out, &BackupBuffer[PreviousIndex]); + Count += StrLen (&BackupBuffer[PreviousIndex]); + PrintWidth += Count * CharWidth; + if (PrintWidth < Width) { + Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; + Out->SetAttribute (Out, Out->Mode->Attribute); + Out->OutputString (Out, &mSpaceBuffer[SPACE_BUFFER_SIZE - Width + PrintWidth]); + } + + FreePool (Buffer); + FreePool (BackupBuffer); + return Count; +} + +/** + Prints a formatted unicode string to the default console, at + the supplied cursor position. + + @param Width Width of String to be printed. + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at. + @param Fmt Format string. + @param ... Variable argument list for format string. + + @return Length of string printed to the console + +**/ +UINTN +EFIAPI +PrintAt ( + IN UINTN Width, + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *Fmt, + ... + ) +{ + VA_LIST Args; + UINTN LengthOfPrinted; + + VA_START (Args, Fmt); + LengthOfPrinted = PrintInternal (Width, Column, Row, gST->ConOut, Fmt, Args); + VA_END (Args); + return LengthOfPrinted; +} + diff --git a/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h new file mode 100644 index 0000000000..ccbd45f425 --- /dev/null +++ b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h @@ -0,0 +1,295 @@ +/** @file + + This library class defines a set of interfaces to customize Display module + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __CUSTOMIZED_DISPLAY_LIB_INTERNAL_H__ +#define __CUSTOMIZED_DISPLAY_LIB_INTERNAL_H__ + + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Colors.h" + + + +#define FORMSET_CLASS_PLATFORM_SETUP 0x0001 +#define FORMSET_CLASS_FRONT_PAGE 0x0002 + + +#define FRONT_PAGE_HEADER_HEIGHT 6 +#define NONE_FRONT_PAGE_HEADER_HEIGHT 3 +#define FOOTER_HEIGHT 4 +#define STATUS_BAR_HEIGHT 1 + +// +// Screen definitions +// +#define BANNER_HEIGHT 6 +#define BANNER_COLUMNS 3 +#define BANNER_LEFT_COLUMN_INDENT 1 + +// +// Character definitions +// +#define UPPER_LOWER_CASE_OFFSET 0x20 + +// +// This is the Input Error Message +// +#define INPUT_ERROR 1 + +// +// This is the NV RAM update required Message +// +#define NV_UPDATE_REQUIRED 2 + +typedef struct { + EFI_STRING_ID Banner[BANNER_HEIGHT][BANNER_COLUMNS]; +} BANNER_DATA; + +extern UINT16 gClassOfVfr; // Formset class information +extern BANNER_DATA *gBannerData; +extern EFI_SCREEN_DESCRIPTOR gScreenDimensions; +extern UINTN gFooterHeight; + +// +// Browser Global Strings +// +extern CHAR16 *gEnterString; +extern CHAR16 *gEnterCommitString; +extern CHAR16 *gEnterEscapeString; +extern CHAR16 *gEscapeString; +extern CHAR16 *gMoveHighlight; +extern CHAR16 *gDecNumericInput; +extern CHAR16 *gHexNumericInput; +extern CHAR16 *gToggleCheckBox; +extern CHAR16 *gLibEmptyString; +extern CHAR16 *gAreYouSure; +extern CHAR16 *gYesResponse; +extern CHAR16 *gNoResponse; +extern CHAR16 *gPlusString; +extern CHAR16 *gMinusString; +extern CHAR16 *gAdjustNumber; +extern CHAR16 *gSaveChanges; +extern CHAR16 *gNvUpdateMessage; +extern CHAR16 *gInputErrorMessage; +/** + + Print banner info for front page. + + @param[in] FormData Form Data to be shown in Page + +**/ +VOID +PrintBannerInfo ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ); + +/** + Print framework and form title for a page. + + @param[in] FormData Form Data to be shown in Page +**/ +VOID +PrintFramework ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ); + +/** + Validate the input screen diemenstion info. + + @param FormData The input form data info. + + @return EFI_SUCCESS The input screen info is acceptable. + @return EFI_INVALID_PARAMETER The input screen info is not acceptable. + +**/ +EFI_STATUS +ScreenDiemensionInfoValidate ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ); + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The package list in the HII database to search for + the specified string. + + @return The output string. + +**/ +CHAR16 * +LibGetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ); + +/** + Count the storage space of a Unicode string. + + This function handles the Unicode string with NARROW_CHAR + and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR + does not count in the resultant output. If a WIDE_CHAR is + hit, then 2 Unicode character will consume an output storage + space with size of CHAR16 till a NARROW_CHAR is hit. + + If String is NULL, then ASSERT (). + + @param String The input string to be counted. + + @return Storage space for the input string. + +**/ +UINTN +LibGetStringWidth ( + IN CHAR16 *String + ); + +/** + Show all registered HotKey help strings on bottom Rows. + + @param FormData The curent input form data info. + +**/ +VOID +PrintHotKeyHelpString ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ); + +/** + Get step info from numeric opcode. + + @param[in] OpCode The input numeric op code. + + @return step info for this opcode. +**/ +UINT64 +LibGetFieldFromNum ( + IN EFI_IFR_OP_HEADER *OpCode + ); + +/** + Initialize the HII String Token to the correct values. + +**/ +VOID +InitializeLibStrings ( + VOID + ); + +/** + Free the HII String. + +**/ +VOID +FreeLibStrings ( + VOID + ); + +/** + Wait for a key to be pressed by user. + + @param Key The key which is pressed by user. + + @retval EFI_SUCCESS The function always completed successfully. + +**/ +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ); + +/** + Set Buffer to Value for Size bytes. + + @param Buffer Memory to set. + @param Size Number of bytes to set + @param Value Value of the set operation. + +**/ +VOID +LibSetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ); + +/** + Prints a formatted unicode string to the default console, at + the supplied cursor position. + + @param Width Width of String to be printed. + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at. + @param Fmt Format string. + @param ... Variable argument list for format string. + + @return Length of string printed to the console + +**/ +UINTN +EFIAPI +PrintAt ( + IN UINTN Width, + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *Fmt, + ... + ); + +/** + Process some op codes which is out side of current form. + + @param FormData Pointer to the form data. + +**/ +VOID +ProcessExternedOpcode ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ); + +#endif diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 3105519297..4ae24eb80e 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -98,6 +98,10 @@ # CpuExceptionHandlerLib|Include/Library/CpuExceptionHandlerLib.h + ## @libraryclass Provides platform specific display interface. + # + CustomizedDisplayLib|Include/Library/CustomizedDisplayLib.h + [Guids] ## MdeModule package token space guid # Include/Guid/MdeModulePkgTokenSpace.h @@ -361,6 +365,12 @@ ## Include/Protocol/BootLogo.h gEfiBootLogoProtocolGuid = { 0xcdea2bd3, 0xfc25, 0x4c1c, { 0xb9, 0x7c, 0xb3, 0x11, 0x86, 0x6, 0x49, 0x90 } } + ## Include/Protocol/DisplayProtocol.h + gEdkiiFormDisplayEngineProtocolGuid = { 0x9bbe29e9, 0xfda1, 0x41ec, { 0xad, 0x52, 0x45, 0x22, 0x13, 0x74, 0x2d, 0x2e } } + + ## Include/Protocol/FormBrowserEx2.h + gEdkiiFormBrowserEx2ProtocolGuid = { 0xa770c357, 0xb693, 0x4e6d, { 0xa6, 0xcf, 0xd2, 0x1c, 0x72, 0x8e, 0x55, 0xb } } + [PcdsFeatureFlag] ## Indicate whether platform can support update capsule across a system reset gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset|FALSE|BOOLEAN|0x0001001d diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 781fbbf3b4..7895834c24 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -76,6 +76,7 @@ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf PalLib|MdePkg/Library/BasePalLibNull/BasePalLibNull.inf + CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf # # Misc # @@ -293,6 +294,7 @@ MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf MdeModulePkg/Application/VariableInfo/VariableInfo.inf MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf MdeModulePkg/Universal/Variable/Pei/VariablePei.inf diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf b/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf new file mode 100644 index 0000000000..323fcadb85 --- /dev/null +++ b/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf @@ -0,0 +1,66 @@ +## @file +# The DXE driver produces FORM BROWSER protocols defined in UEFI HII 2.1 specificatin. +# +# Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DisplayEngine + FILE_GUID = E660EA85-058E-4b55-A54B-F02F83A24707 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeDisplayEngine + UNLOAD_IMAGE = UnloadDisplayEngine +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + FormDisplayStr.uni + FormDisplay.c + FormDisplay.h + ProcessOptions.c + InputHandler.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + DebugLib + BaseMemoryLib + BaseLib + PrintLib + HiiLib + MemoryAllocationLib + CustomizedDisplayLib + +[Protocols] + gEdkiiFormDisplayEngineProtocolGuid + gEdkiiFormBrowserEx2ProtocolGuid + +[Guids] + gEfiIfrTianoGuid ## CONSUMES ## GUID + +[Depex] + gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid AND gEdkiiFormBrowserEx2ProtocolGuid + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserGrayOutTextStatement ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdBrowerGrayOutReadOnlyMenu ## CONSUMES + diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c new file mode 100644 index 0000000000..a07cc75a47 --- /dev/null +++ b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c @@ -0,0 +1,3255 @@ +/** @file +Entry and initialization module for the browser. + +Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "FormDisplay.h" + +// +// Search table for UiDisplayMenu() +// +SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = { + { + SCAN_UP, + UiUp, + }, + { + SCAN_DOWN, + UiDown, + }, + { + SCAN_PAGE_UP, + UiPageUp, + }, + { + SCAN_PAGE_DOWN, + UiPageDown, + }, + { + SCAN_ESC, + UiReset, + }, + { + SCAN_LEFT, + UiLeft, + }, + { + SCAN_RIGHT, + UiRight, + } +}; + +UINTN mScanCodeNumber = sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); + +SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = { + { + UiNoOperation, + CfUiNoOperation, + }, + { + UiSelect, + CfUiSelect, + }, + { + UiUp, + CfUiUp, + }, + { + UiDown, + CfUiDown, + }, + { + UiLeft, + CfUiLeft, + }, + { + UiRight, + CfUiRight, + }, + { + UiReset, + CfUiReset, + }, + { + UiPageUp, + CfUiPageUp, + }, + { + UiPageDown, + CfUiPageDown + }, + { + UiHotKey, + CfUiHotKey + } +}; + +EFI_GUID gDisplayEngineGuid = { + 0xE38C1029, 0xE38F, 0x45b9, {0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62} +}; + +FORM_ENTRY_INFO gFormEntryInfo; +UINTN gSequence; +EFI_SCREEN_DESCRIPTOR gStatementDimensions; +BOOLEAN mStatementLayoutIsChanged = TRUE; +USER_INPUT *gUserInput; +FORM_DISPLAY_ENGINE_FORM *gFormData; +EFI_HII_HANDLE gHiiHandle; +UINT16 gDirection; +LIST_ENTRY gMenuOption; +DISPLAY_HIGHLIGHT_MENU_INFO gHighligthMenuInfo = {0}; +BOOLEAN mIsFirstForm = TRUE; +FORM_ENTRY_INFO gOldFormEntry = {0}; + +// +// Browser Global Strings +// +CHAR16 *gFormNotFound; +CHAR16 *gNoSubmitIf; +CHAR16 *gBrwoserError; +CHAR16 *gSaveFailed; +CHAR16 *gPromptForData; +CHAR16 *gPromptForPassword; +CHAR16 *gPromptForNewPassword; +CHAR16 *gConfirmPassword; +CHAR16 *gConfirmError; +CHAR16 *gPassowordInvalid; +CHAR16 *gPressEnter; +CHAR16 *gEmptyString; +CHAR16 *gMiniString; +CHAR16 *gOptionMismatch; +CHAR16 *gFormSuppress; +CHAR16 *gProtocolNotFound; + +CHAR16 gPromptBlockWidth; +CHAR16 gOptionBlockWidth; +CHAR16 gHelpBlockWidth; +CHAR16 *mUnknownString; + +FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData = { + FORM_DISPLAY_DRIVER_SIGNATURE, + NULL, + { + FormDisplay, + DriverClearDisplayPage, + ConfirmDataChange + } +}; + + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The package list in the HII database to search for + the specified string. + + @return The output string. + +**/ +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STRING String; + + String = HiiGetString (HiiHandle, Token, NULL); + if (String == NULL) { + String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString); + ASSERT (String != NULL); + } + + return (CHAR16 *) String; +} + + +/** + Initialize the HII String Token to the correct values. + +**/ +VOID +InitializeDisplayStrings ( + VOID + ) +{ + mUnknownString = GetToken (STRING_TOKEN (UNKNOWN_STRING), gHiiHandle); + gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle); + gPromptForData = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle); + gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle); + gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle); + gConfirmPassword = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle); + gConfirmError = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle); + gPassowordInvalid = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle); + gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle); + gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle); + gOptionMismatch = GetToken (STRING_TOKEN (OPTION_MISMATCH), gHiiHandle); + gFormSuppress = GetToken (STRING_TOKEN (FORM_SUPPRESSED), gHiiHandle); + gProtocolNotFound = GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND), gHiiHandle); + gFormNotFound = GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND), gHiiHandle); + gNoSubmitIf = GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF), gHiiHandle); + gBrwoserError = GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR), gHiiHandle); +} + +/** + Free up the resource allocated for all strings required + by Setup Browser. + +**/ +VOID +FreeDisplayStrings ( + VOID + ) +{ + FreePool (mUnknownString); + FreePool (gEmptyString); + FreePool (gSaveFailed); + FreePool (gPromptForData); + FreePool (gPromptForPassword); + FreePool (gPromptForNewPassword); + FreePool (gConfirmPassword); + FreePool (gConfirmError); + FreePool (gPassowordInvalid); + FreePool (gPressEnter); + FreePool (gMiniString); + FreePool (gOptionMismatch); + FreePool (gFormSuppress); + FreePool (gProtocolNotFound); + FreePool (gBrwoserError); + FreePool (gNoSubmitIf); + FreePool (gFormNotFound); +} + +/** + Get prompt string id from the opcode data buffer. + + @param OpCode The input opcode buffer. + + @return The prompt string id. + +**/ +EFI_STRING_ID +GetPrompt ( + IN EFI_IFR_OP_HEADER *OpCode + ) +{ + EFI_IFR_STATEMENT_HEADER *Header; + + if (OpCode->Length <= sizeof (EFI_IFR_OP_HEADER)) { + return 0; + } + + Header = (EFI_IFR_STATEMENT_HEADER *) (OpCode + 1); + + return Header->Prompt; +} + +/** + Get the supported width for a particular op-code + + @param Statement The curent statement. + + @return Returns the number of CHAR16 characters that is support. + +**/ +UINT16 +GetWidth ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Statement + ) +{ + CHAR16 *String; + UINTN Size; + UINT16 Width; + EFI_IFR_TEXT *TestOp; + + Size = 0; + + // + // See if the second text parameter is really NULL + // + if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) { + TestOp = (EFI_IFR_TEXT *) Statement->OpCode; + if (TestOp->TextTwo != 0) { + String = GetToken (TestOp->TextTwo, gFormData->HiiHandle); + Size = StrLen (String); + FreePool (String); + } + } + + if ((Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) || + (Statement->OpCode->OpCode == EFI_IFR_REF_OP) || + (Statement->OpCode->OpCode == EFI_IFR_PASSWORD_OP) || + (Statement->OpCode->OpCode == EFI_IFR_ACTION_OP) || + (Statement->OpCode->OpCode == EFI_IFR_RESET_BUTTON_OP) || + // + // Allow a wide display if text op-code and no secondary text op-code + // + ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0)) + ) { + Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth); + } else { + Width = (UINT16) gPromptBlockWidth; + } + + return (UINT16) (Width - LEFT_SKIPPED_COLUMNS); +} + +/** + Will copy LineWidth amount of a string in the OutputString buffer and return the + number of CHAR16 characters that were copied into the OutputString buffer. + The output string format is: + Glyph Info + String info + '\0'. + + In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g. + + @param InputString String description for this option. + @param LineWidth Width of the desired string to extract in CHAR16 + characters + @param GlyphWidth The glyph width of the begin of the char in the string. + @param Index Where in InputString to start the copy process + @param OutputString Buffer to copy the string into + + @return Returns the number of CHAR16 characters that were copied into the OutputString + buffer, include extra glyph info and '\0' info. + +**/ +UINT16 +GetLineByWidth ( + IN CHAR16 *InputString, + IN UINT16 LineWidth, + IN OUT UINT16 *GlyphWidth, + IN OUT UINTN *Index, + OUT CHAR16 **OutputString + ) +{ + UINT16 StrOffset; + UINT16 GlyphOffset; + UINT16 OriginalGlyphWidth; + BOOLEAN ReturnFlag; + UINT16 LastSpaceOffset; + UINT16 LastGlyphWidth; + + if (InputString == NULL || Index == NULL || OutputString == NULL) { + return 0; + } + + if (LineWidth == 0 || *GlyphWidth == 0) { + return 0; + } + + // + // Save original glyph width. + // + OriginalGlyphWidth = *GlyphWidth; + LastGlyphWidth = OriginalGlyphWidth; + ReturnFlag = FALSE; + LastSpaceOffset = 0; + + // + // NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen. + // To avoid displaying this empty line in screen, just skip the two CHARs here. + // + if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) { + *Index = *Index + 2; + } + + // + // Fast-forward the string and see if there is a carriage-return in the string + // + for (StrOffset = 0, GlyphOffset = 0; GlyphOffset <= LineWidth; StrOffset++) { + switch (InputString[*Index + StrOffset]) { + case NARROW_CHAR: + *GlyphWidth = 1; + break; + + case WIDE_CHAR: + *GlyphWidth = 2; + break; + + case CHAR_CARRIAGE_RETURN: + case CHAR_LINEFEED: + case CHAR_NULL: + ReturnFlag = TRUE; + break; + + default: + GlyphOffset = GlyphOffset + *GlyphWidth; + + // + // Record the last space info in this line. Will be used in rewind. + // + if ((InputString[*Index + StrOffset] == CHAR_SPACE) && (GlyphOffset <= LineWidth)) { + LastSpaceOffset = StrOffset; + LastGlyphWidth = *GlyphWidth; + } + break; + } + + if (ReturnFlag) { + break; + } + } + + // + // Rewind the string from the maximum size until we see a space to break the line + // + if (GlyphOffset > LineWidth) { + // + // Rewind the string to last space char in this line. + // + if (LastSpaceOffset != 0) { + StrOffset = LastSpaceOffset; + *GlyphWidth = LastGlyphWidth; + } else { + // + // Roll back to last char in the line width. + // + StrOffset--; + } + } + + // + // The CHAR_NULL has process last time, this time just return 0 to stand for the end. + // + if (StrOffset == 0 && (InputString[*Index + StrOffset] == CHAR_NULL)) { + return 0; + } + + // + // Need extra glyph info and '\0' info, so +2. + // + *OutputString = AllocateZeroPool (((UINTN) (StrOffset + 2) * sizeof(CHAR16))); + if (*OutputString == NULL) { + return 0; + } + + // + // Save the glyph info at the begin of the string, will used by Print function. + // + if (OriginalGlyphWidth == 1) { + *(*OutputString) = NARROW_CHAR; + } else { + *(*OutputString) = WIDE_CHAR; + } + + CopyMem ((*OutputString) + 1, &InputString[*Index], StrOffset * sizeof(CHAR16)); + + if (InputString[*Index + StrOffset] == CHAR_SPACE) { + // + // Skip the space info at the begin of next line. + // + *Index = (UINT16) (*Index + StrOffset + 1); + } else if (InputString[*Index + StrOffset] == CHAR_LINEFEED) { + // + // Skip the /n or /n/r info. + // + if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) { + *Index = (UINT16) (*Index + StrOffset + 2); + } else { + *Index = (UINT16) (*Index + StrOffset + 1); + } + } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) { + // + // Skip the /r or /r/n info. + // + if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) { + *Index = (UINT16) (*Index + StrOffset + 2); + } else { + *Index = (UINT16) (*Index + StrOffset + 1); + } + } else { + *Index = (UINT16) (*Index + StrOffset); + } + + // + // Include extra glyph info and '\0' info, so +2. + // + return StrOffset + 2; +} + +/** + Add one menu option by specified description and context. + + @param Statement Statement of this Menu Option. + @param MenuItemCount The index for this Option in the Menu. + @param NestIn Whether this statement is nest in another statement. + +**/ +VOID +UiAddMenuOption ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, + IN UINT16 *MenuItemCount, + IN BOOLEAN NestIn + ) +{ + UI_MENU_OPTION *MenuOption; + UINTN Index; + UINTN Count; + CHAR16 *String; + UINT16 NumberOfLines; + UINT16 GlyphWidth; + UINT16 Width; + UINTN ArrayEntry; + CHAR16 *OutputString; + EFI_STRING_ID PromptId; + + NumberOfLines = 1; + ArrayEntry = 0; + GlyphWidth = 1; + Count = 1; + MenuOption = NULL; + + PromptId = GetPrompt (Statement->OpCode); + ASSERT (PromptId != 0); + + String = GetToken (PromptId, gFormData->HiiHandle); + ASSERT (String != NULL); + + Width = GetWidth (Statement); + for (; GetLineByWidth (String, Width, &GlyphWidth,&ArrayEntry, &OutputString) != 0x0000;) { + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&String[ArrayEntry]) != 0) { + NumberOfLines++; + } + FreePool (OutputString); + } + + if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) { + // + // Add three MenuOptions for Date/Time + // Data format : [01/02/2004] [11:22:33] + // Line number : 0 0 1 0 0 1 + // + NumberOfLines = 0; + Count = 3; + } + + for (Index = 0; Index < Count; Index++) { + MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION)); + ASSERT (MenuOption); + + MenuOption->Signature = UI_MENU_OPTION_SIGNATURE; + MenuOption->Description = String; + MenuOption->Handle = gFormData->HiiHandle; + MenuOption->ThisTag = Statement; + MenuOption->NestInStatement = NestIn; + MenuOption->EntryNumber = *MenuItemCount; + + if (Index == 2) { + // + // Override LineNumber for the MenuOption in Date/Time sequence + // + MenuOption->Skip = 1; + } else { + MenuOption->Skip = NumberOfLines; + } + MenuOption->Sequence = Index; + + if ((Statement->Attribute & HII_DISPLAY_GRAYOUT) != 0) { + MenuOption->GrayOut = TRUE; + } else { + MenuOption->GrayOut = FALSE; + } + + if ((Statement->Attribute & HII_DISPLAY_LOCK) != 0 || (gFormData->Attribute & HII_DISPLAY_LOCK) != 0) { + MenuOption->GrayOut = TRUE; + } + + // + // If the form or the question has the lock attribute, deal same as grayout. + // + if ((gFormData->Attribute & HII_DISPLAY_LOCK) != 0 || (Statement->Attribute & HII_DISPLAY_LOCK) != 0) { + MenuOption->GrayOut = TRUE; + } + + switch (Statement->OpCode->OpCode) { + case EFI_IFR_ORDERED_LIST_OP: + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_NUMERIC_OP: + case EFI_IFR_TIME_OP: + case EFI_IFR_DATE_OP: + case EFI_IFR_CHECKBOX_OP: + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + // + // User could change the value of these items + // + MenuOption->IsQuestion = TRUE; + break; + case EFI_IFR_TEXT_OP: + if (FeaturePcdGet (PcdBrowserGrayOutTextStatement)) { + // + // Initializing GrayOut option as TRUE for Text setup options + // so that those options will be Gray in colour and un selectable. + // + MenuOption->GrayOut = TRUE; + } + break; + default: + MenuOption->IsQuestion = FALSE; + break; + } + + if ((Statement->Attribute & HII_DISPLAY_READONLY) != 0) { + MenuOption->ReadOnly = TRUE; + if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu)) { + MenuOption->GrayOut = TRUE; + } + } + + InsertTailList (&gMenuOption, &MenuOption->Link); + } + + (*MenuItemCount)++; +} + +/** + Create the menu list base on the form data info. + +**/ +VOID +ConvertStatementToMenu ( + VOID + ) +{ + UINT16 MenuItemCount; + LIST_ENTRY *Link; + LIST_ENTRY *NestLink; + FORM_DISPLAY_ENGINE_STATEMENT *Statement; + FORM_DISPLAY_ENGINE_STATEMENT *NestStatement; + + MenuItemCount = 0; + InitializeListHead (&gMenuOption); + + Link = GetFirstNode (&gFormData->StatementListHead); + while (!IsNull (&gFormData->StatementListHead, Link)) { + Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&gFormData->StatementListHead, Link); + + // + // Skip the opcode not recognized by Display core. + // + if (Statement->OpCode->OpCode == EFI_IFR_GUID_OP) { + continue; + } + + UiAddMenuOption (Statement, &MenuItemCount, FALSE); + + // + // Check the statement nest in this host statement. + // + NestLink = GetFirstNode (&Statement->NestStatementList); + while (!IsNull (&Statement->NestStatementList, NestLink)) { + NestStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink); + NestLink = GetNextNode (&Statement->NestStatementList, NestLink); + + UiAddMenuOption (NestStatement, &MenuItemCount, TRUE); + } + } +} + +/** + Count the storage space of a Unicode string. + + This function handles the Unicode string with NARROW_CHAR + and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR + does not count in the resultant output. If a WIDE_CHAR is + hit, then 2 Unicode character will consume an output storage + space with size of CHAR16 till a NARROW_CHAR is hit. + + If String is NULL, then ASSERT (). + + @param String The input string to be counted. + + @return Storage space for the input string. + +**/ +UINTN +GetStringWidth ( + IN CHAR16 *String + ) +{ + UINTN Index; + UINTN Count; + UINTN IncrementValue; + + ASSERT (String != NULL); + if (String == NULL) { + return 0; + } + + Index = 0; + Count = 0; + IncrementValue = 1; + + do { + // + // Advance to the null-terminator or to the first width directive + // + for (; + (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0); + Index++, Count = Count + IncrementValue + ) + ; + + // + // We hit the null-terminator, we now have a count + // + if (String[Index] == 0) { + break; + } + // + // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed + // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2) + // + if (String[Index] == NARROW_CHAR) { + // + // Skip to the next character + // + Index++; + IncrementValue = 1; + } else { + // + // Skip to the next character + // + Index++; + IncrementValue = 2; + } + } while (String[Index] != 0); + + // + // Increment by one to include the null-terminator in the size + // + Count++; + + return Count * sizeof (CHAR16); +} + +/** + Base on the input option string to update the skip value for a menu option. + + @param MenuOption The MenuOption to be checked. + @param OptionString The input option string. + +**/ +VOID +UpdateSkipInfoForMenu ( + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *OptionString + ) +{ + UINTN Index; + UINT16 Width; + UINTN Row; + CHAR16 *OutputString; + UINT16 GlyphWidth; + + Width = (UINT16) gOptionBlockWidth; + GlyphWidth = 1; + Row = 1; + + for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { + if (StrLen (&OptionString[Index]) != 0) { + Row++; + } + + FreePool (OutputString); + } + + if ((Row > MenuOption->Skip) && + (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_DATE_OP) && + (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_TIME_OP)) { + MenuOption->Skip = Row; + } +} + +/** + Update display lines for a Menu Option. + + @param MenuOption The MenuOption to be checked. + +**/ +VOID +UpdateOptionSkipLines ( + IN UI_MENU_OPTION *MenuOption + ) +{ + CHAR16 *OptionString; + + OptionString = NULL; + + ProcessOptions (MenuOption, FALSE, &OptionString, TRUE); + if (OptionString != NULL) { + UpdateSkipInfoForMenu (MenuOption, OptionString); + + FreePool (OptionString); + } + + if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo != 0)) { + OptionString = GetToken (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo, gFormData->HiiHandle); + + if (OptionString != NULL) { + UpdateSkipInfoForMenu (MenuOption, OptionString); + + FreePool (OptionString); + } + } +} + +/** + Check whether this Menu Option could be highlighted. + + This is an internal function. + + @param MenuOption The MenuOption to be checked. + + @retval TRUE This Menu Option is selectable. + @retval FALSE This Menu Option could not be selected. + +**/ +BOOLEAN +IsSelectable ( + UI_MENU_OPTION *MenuOption + ) +{ + if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) || + MenuOption->GrayOut || MenuOption->ReadOnly) { + return FALSE; + } else { + return TRUE; + } +} + +/** + Move to next selectable statement. + + This is an internal function. + + @param GoUp The navigation direction. TRUE: up, FALSE: down. + @param CurrentPosition Current position. + @param GapToTop Gap position to top or bottom. + + @return The row distance from current MenuOption to next selectable MenuOption. + + @retval -1 Reach the begin of the menu, still can't find the selectable menu. + @retval Value Find the selectable menu, maybe the truly selectable, maybe the l + last menu showing at current form. + +**/ +INTN +MoveToNextStatement ( + IN BOOLEAN GoUp, + IN OUT LIST_ENTRY **CurrentPosition, + IN UINTN GapToTop + ) +{ + INTN Distance; + LIST_ENTRY *Pos; + UI_MENU_OPTION *NextMenuOption; + UI_MENU_OPTION *PreMenuOption; + + Distance = 0; + Pos = *CurrentPosition; + PreMenuOption = MENU_OPTION_FROM_LINK (Pos); + + while (TRUE) { + NextMenuOption = MENU_OPTION_FROM_LINK (Pos); + // + // NextMenuOption->Row == 0 means this menu has not calculate + // the NextMenuOption->Skip value yet, just calculate here. + // + if (NextMenuOption->Row == 0) { + UpdateOptionSkipLines (NextMenuOption); + } + + if (GoUp && (PreMenuOption != NextMenuOption)) { + // + // In this case, still can't find the selectable menu, + // return the last one in the showing form. + // + if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) { + NextMenuOption = PreMenuOption; + break; + } + + // + // Current Position doesn't need to be caculated when go up. + // Caculate distanct at first when go up + // + Distance += NextMenuOption->Skip; + } + + if (IsSelectable (NextMenuOption)) { + break; + } + + // + // Arrive at begin of the menu list. + // + if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) { + Distance = -1; + break; + } + + if (!GoUp) { + // + // In this case, still can't find the selectable menu, + // return the last one in the showing form. + // + if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) { + NextMenuOption = PreMenuOption; + break; + } + + Distance += NextMenuOption->Skip; + } + + PreMenuOption = NextMenuOption; + Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink); + } + + *CurrentPosition = &NextMenuOption->Link; + return Distance; +} + + +/** + Process option string for date/time opcode. + + @param MenuOption Menu option point to date/time. + @param OptionString Option string input for process. + @param AddOptCol Whether need to update MenuOption->OptCol. + +**/ +VOID +ProcessStringForDateTime ( + UI_MENU_OPTION *MenuOption, + CHAR16 *OptionString, + BOOLEAN AddOptCol + ) +{ + UINTN Index; + UINTN Count; + FORM_DISPLAY_ENGINE_STATEMENT *Statement; + EFI_IFR_DATE *Date; + EFI_IFR_TIME *Time; + + ASSERT (MenuOption != NULL && OptionString != NULL); + + Statement = MenuOption->ThisTag; + Date = NULL; + Time = NULL; + if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) { + Date = (EFI_IFR_DATE *) Statement->OpCode; + } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) { + Time = (EFI_IFR_TIME *) Statement->OpCode; + } + + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) { + // + // Base on the blockspace to get the option column info. + // + if (AddOptCol) { + MenuOption->OptCol++; + } + } + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + OptionString[Count] = CHAR_NULL; + + // + // Enable to suppress field in the opcode base on the flag. + // + if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) { + // + // OptionString format is: <**: **: ****> + // |month|day|year| + // 4 3 5 + // + if ((Date->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) { + // + // At this point, only "<**:" in the optionstring. + // Clean the day's ** field, after clean, the format is "< :" + // + SetUnicodeMem (&OptionString[1], 2, L' '); + } else if ((Date->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) { + // + // At this point, only "**:" in the optionstring. + // Clean the month's "**" field, after clean, the format is " :" + // + SetUnicodeMem (&OptionString[0], 2, L' '); + } else if ((Date->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) { + // + // At this point, only "****>" in the optionstring. + // Clean the year's "****" field, after clean, the format is " >" + // + SetUnicodeMem (&OptionString[0], 4, L' '); + } + } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) { + // + // OptionString format is: <**: **: **> + // |hour|minute|second| + // 4 3 3 + // + if ((Time->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) { + // + // At this point, only "<**:" in the optionstring. + // Clean the hour's ** field, after clean, the format is "< :" + // + SetUnicodeMem (&OptionString[1], 2, L' '); + } else if ((Time->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) { + // + // At this point, only "**:" in the optionstring. + // Clean the minute's "**" field, after clean, the format is " :" + // + SetUnicodeMem (&OptionString[0], 2, L' '); + } else if ((Time->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) { + // + // At this point, only "**>" in the optionstring. + // Clean the second's "**" field, after clean, the format is " >" + // + SetUnicodeMem (&OptionString[0], 2, L' '); + } + } +} + + +/** + Adjust Data and Time position accordingly. + Data format : [01/02/2004] [11:22:33] + Line number : 0 0 1 0 0 1 + + This is an internal function. + + @param DirectionUp the up or down direction. False is down. True is + up. + @param CurrentPosition Current position. On return: Point to the last + Option (Year or Second) if up; Point to the first + Option (Month or Hour) if down. + + @return Return line number to pad. It is possible that we stand on a zero-advance + @return data or time opcode, so pad one line when we judge if we are going to scroll outside. + +**/ +UINTN +AdjustDateAndTimePosition ( + IN BOOLEAN DirectionUp, + IN OUT LIST_ENTRY **CurrentPosition + ) +{ + UINTN Count; + LIST_ENTRY *NewPosition; + UI_MENU_OPTION *MenuOption; + UINTN PadLineNumber; + + PadLineNumber = 0; + NewPosition = *CurrentPosition; + MenuOption = MENU_OPTION_FROM_LINK (NewPosition); + + if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || + (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) { + // + // Calculate the distance from current position to the last Date/Time MenuOption + // + Count = 0; + while (MenuOption->Skip == 0) { + Count++; + NewPosition = NewPosition->ForwardLink; + MenuOption = MENU_OPTION_FROM_LINK (NewPosition); + PadLineNumber = 1; + } + + NewPosition = *CurrentPosition; + if (DirectionUp) { + // + // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended + // to be one that back to the previous set of MenuOptions, we need to advance to the first + // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate + // checking can be done. + // + while (Count++ < 2) { + NewPosition = NewPosition->BackLink; + } + } else { + // + // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended + // to be one that progresses to the next set of MenuOptions, we need to advance to the last + // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate + // checking can be done. + // + while (Count-- > 0) { + NewPosition = NewPosition->ForwardLink; + } + } + + *CurrentPosition = NewPosition; + } + + return PadLineNumber; +} + +/** + Get step info from numeric opcode. + + @param[in] OpCode The input numeric op code. + + @return step info for this opcode. +**/ +UINT64 +GetFieldFromNum ( + IN EFI_IFR_OP_HEADER *OpCode + ) +{ + EFI_IFR_NUMERIC *NumericOp; + UINT64 Step; + + NumericOp = (EFI_IFR_NUMERIC *) OpCode; + + switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + Step = NumericOp->data.u8.Step; + break; + + case EFI_IFR_NUMERIC_SIZE_2: + Step = NumericOp->data.u16.Step; + break; + + case EFI_IFR_NUMERIC_SIZE_4: + Step = NumericOp->data.u32.Step; + break; + + case EFI_IFR_NUMERIC_SIZE_8: + Step = NumericOp->data.u64.Step; + break; + + default: + Step = 0; + break; + } + + return Step; +} + +/** + Find the registered HotKey based on KeyData. + + @param[in] KeyData A pointer to a buffer that describes the keystroke + information for the hot key. + + @return The registered HotKey context. If no found, NULL will return. +**/ +BROWSER_HOT_KEY * +GetHotKeyFromRegisterList ( + IN EFI_INPUT_KEY *KeyData + ) +{ + LIST_ENTRY *Link; + BROWSER_HOT_KEY *HotKey; + + Link = GetFirstNode (&gFormData->HotKeyListHead); + while (!IsNull (&gFormData->HotKeyListHead, Link)) { + HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); + + if (HotKey->KeyData->ScanCode == KeyData->ScanCode) { + return HotKey; + } + + Link = GetNextNode (&gFormData->HotKeyListHead, Link); + } + + return NULL; +} + + +/** + Determine if the menu is the last menu that can be selected. + + This is an internal function. + + @param Direction The scroll direction. False is down. True is up. + @param CurrentPos The current focus. + + @return FALSE -- the menu isn't the last menu that can be selected. + @return TRUE -- the menu is the last menu that can be selected. + +**/ +BOOLEAN +ValueIsScroll ( + IN BOOLEAN Direction, + IN LIST_ENTRY *CurrentPos + ) +{ + LIST_ENTRY *Temp; + + Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink; + + if (Temp == &gMenuOption) { + return TRUE; + } + + return FALSE; +} + +/** + Wait for a given event to fire, or for an optional timeout to expire. + + @param Event The event to wait for + + @retval UI_EVENT_TYPE The type of the event which is trigged. + +**/ +UI_EVENT_TYPE +UiWaitForEvent ( + IN EFI_EVENT Event + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN EventNum; + UINT64 Timeout; + EFI_EVENT TimerEvent; + EFI_EVENT WaitList[3]; + UI_EVENT_TYPE EventType; + + TimerEvent = NULL; + Timeout = FormExitTimeout(gFormData); + + if (Timeout != 0) { + Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); + + // + // Set the timer event + // + gBS->SetTimer ( + TimerEvent, + TimerRelative, + Timeout + ); + } + + WaitList[0] = Event; + EventNum = 1; + if (gFormData->FormRefreshEvent != NULL) { + WaitList[EventNum] = gFormData->FormRefreshEvent; + EventNum ++; + } + + if (Timeout != 0) { + WaitList[EventNum] = TimerEvent; + EventNum ++; + } + + Status = gBS->WaitForEvent (EventNum, WaitList, &Index); + ASSERT_EFI_ERROR (Status); + + switch (Index) { + case 0: + EventType = UIEventKey; + break; + + case 1: + if (gFormData->FormRefreshEvent != NULL) { + EventType = UIEventDriver; + } else { + ASSERT (Timeout != 0 && EventNum == 2); + EventType = UIEventTimeOut; + } + break; + + default: + ASSERT (Index == 2 && EventNum == 3); + EventType = UIEventTimeOut; + break; + } + + if (Timeout != 0) { + gBS->CloseEvent (TimerEvent); + } + + return EventType; +} + +/** + Get question id info from the input opcode header. + + @param OpCode The input opcode header pointer. + + @retval The question id for this opcode. + +**/ +EFI_QUESTION_ID +GetQuestionIdInfo ( + IN EFI_IFR_OP_HEADER *OpCode + ) +{ + EFI_IFR_QUESTION_HEADER *QuestionHeader; + + if (OpCode->Length < sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER)) { + return 0; + } + + QuestionHeader = (EFI_IFR_QUESTION_HEADER *)((UINT8 *) OpCode + sizeof(EFI_IFR_OP_HEADER)); + + return QuestionHeader->QuestionId; +} + +/** + Find the first menu which will be show at the top. + + @param FormData The data info for this form. + @param TopOfScreen The link_entry pointer to top menu. + @param HighlightMenu The menu which will be highlight. + @param SkipValue The skip value for the top menu. + +**/ +VOID +FindTopMenu ( + IN FORM_DISPLAY_ENGINE_FORM *FormData, + OUT LIST_ENTRY **TopOfScreen, + OUT LIST_ENTRY **HighlightMenu, + OUT INTN *SkipValue + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *NewPos; + UINTN TopRow; + UINTN BottomRow; + UINTN Index; + UI_MENU_OPTION *SavedMenuOption; + UINTN EndRow; + + TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT; + BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT; + + // + // If not has input highlight statement, just return the first one in this form. + // + if (FormData->HighLightedStatement == NULL) { + *TopOfScreen = gMenuOption.ForwardLink; + *HighlightMenu = gMenuOption.ForwardLink; + if (!IsListEmpty (&gMenuOption)) { + MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow); + } + *SkipValue = 0; + return; + } + + // + // Now base on the input highlight menu to find the top menu in this page. + // Will base on the highlight menu show at the bottom to find the top menu. + // + NewPos = gMenuOption.ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); + + while ((SavedMenuOption->ThisTag != FormData->HighLightedStatement) || + (SavedMenuOption->Sequence != gSequence)) { + NewPos = NewPos->ForwardLink; + if (NewPos == &gMenuOption) { + // + // Not Found it, break + // + break; + } + SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); + } + ASSERT (SavedMenuOption->ThisTag == FormData->HighLightedStatement); + + *HighlightMenu = NewPos; + + AdjustDateAndTimePosition(FALSE, &NewPos); + SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); + UpdateOptionSkipLines (SavedMenuOption); + + // + // If highlight opcode is date/time, keep the highlight row info not change. + // + if ((SavedMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP || SavedMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP) && + (gHighligthMenuInfo.QuestionId != 0) && + (gHighligthMenuInfo.QuestionId == GetQuestionIdInfo(SavedMenuOption->ThisTag->OpCode))) { + // + // Still show the highlight menu before exit from display engine. + // + EndRow = gHighligthMenuInfo.DisplayRow + SavedMenuOption->Skip; + } else { + EndRow = BottomRow; + } + + // + // Base on the selected menu will show at the bottome of next page, + // select the menu show at the top of the next page. + // + Link = NewPos; + for (Index = TopRow + SavedMenuOption->Skip; Index <= EndRow; ) { + Link = Link->BackLink; + // + // Already find the first menu in this form, means highlight menu + // will show in first page of this form. + // + if (Link == &gMenuOption) { + *TopOfScreen = gMenuOption.ForwardLink; + *SkipValue = 0; + return; + } + SavedMenuOption = MENU_OPTION_FROM_LINK (Link); + UpdateOptionSkipLines (SavedMenuOption); + Index += SavedMenuOption->Skip; + } + + // + // Found the menu which will show at the top of the page. + // + if (Link == NewPos) { + // + // The menu can show more than one pages, just show the menu at the top of the page. + // + *SkipValue = 0; + *TopOfScreen = Link; + } else { + // + // Check whether need to skip some line for menu shows at the top of the page. + // + *SkipValue = Index - EndRow; + if (*SkipValue > 0 && *SkipValue < (INTN) SavedMenuOption->Skip) { + *TopOfScreen = Link; + } else { + *SkipValue = 0; + *TopOfScreen = Link->ForwardLink; + } + } +} + +/** + Display menu and wait for user to select one menu option, then return it. + If AutoBoot is enabled, then if user doesn't select any option, + after period of time, it will automatically return the first menu option. + + @param FormData The current form data info. + + @retval EFI_SUCESSS Process the user selection success. + @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail. + +**/ +EFI_STATUS +UiDisplayMenu ( + IN FORM_DISPLAY_ENGINE_FORM *FormData + ) +{ + INTN SkipValue; + INTN Difference; + UINTN DistanceValue; + UINTN Row; + UINTN Col; + UINTN TempRightCol; + UINTN Temp; + UINTN Temp2; + UINTN Temp3; + UINTN TopRow; + UINTN BottomRow; + UINTN OriginalRow; + UINTN Index; + UINT16 Width; + CHAR16 *StringPtr; + CHAR16 *OptionString; + CHAR16 *OutputString; + CHAR16 *HelpString; + CHAR16 *HelpHeaderString; + CHAR16 *HelpBottomString; + BOOLEAN NewLine; + BOOLEAN Repaint; + BOOLEAN UpArrow; + BOOLEAN DownArrow; + EFI_STATUS Status; + EFI_INPUT_KEY Key; + LIST_ENTRY *Link; + LIST_ENTRY *NewPos; + LIST_ENTRY *TopOfScreen; + LIST_ENTRY *SavedListEntry; + UI_MENU_OPTION *MenuOption; + UI_MENU_OPTION *NextMenuOption; + UI_MENU_OPTION *SavedMenuOption; + UI_MENU_OPTION *PreviousMenuOption; + UI_CONTROL_FLAG ControlFlag; + UI_SCREEN_OPERATION ScreenOperation; + UINT16 DefaultId; + FORM_DISPLAY_ENGINE_STATEMENT *Statement; + UINTN ModalSkipColumn; + BROWSER_HOT_KEY *HotKey; + UINTN HelpPageIndex; + UINTN HelpPageCount; + UINTN RowCount; + UINTN HelpLine; + UINTN HelpHeaderLine; + UINTN HelpBottomLine; + BOOLEAN MultiHelpPage; + UINT16 GlyphWidth; + UINT16 EachLineWidth; + UINT16 HeaderLineWidth; + UINT16 BottomLineWidth; + EFI_STRING_ID HelpInfo; + UI_EVENT_TYPE EventType; + FORM_DISPLAY_ENGINE_STATEMENT *InitialHighlight; + + EventType = UIEventNone; + Status = EFI_SUCCESS; + HelpString = NULL; + HelpHeaderString = NULL; + HelpBottomString = NULL; + OptionString = NULL; + ScreenOperation = UiNoOperation; + NewLine = TRUE; + DefaultId = 0; + HelpPageCount = 0; + HelpLine = 0; + RowCount = 0; + HelpBottomLine = 0; + HelpHeaderLine = 0; + HelpPageIndex = 0; + MultiHelpPage = FALSE; + EachLineWidth = 0; + HeaderLineWidth = 0; + BottomLineWidth = 0; + OutputString = NULL; + UpArrow = FALSE; + DownArrow = FALSE; + SkipValue = 0; + + NextMenuOption = NULL; + PreviousMenuOption = NULL; + SavedMenuOption = NULL; + HotKey = NULL; + Repaint = TRUE; + MenuOption = NULL; + ModalSkipColumn = (gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 6; + InitialHighlight = gFormData->HighLightedStatement; + + ZeroMem (&Key, sizeof (EFI_INPUT_KEY)); + + gOptionBlockWidth = (CHAR16) ((gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 3); + gPromptBlockWidth = (CHAR16) (gOptionBlockWidth + LEFT_SKIPPED_COLUMNS); + gHelpBlockWidth = (CHAR16) (gOptionBlockWidth - LEFT_SKIPPED_COLUMNS); + + TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT; + BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT - 1; + + Row = TopRow; + if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) { + Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + ModalSkipColumn; + } else { + Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS; + } + + FindTopMenu(FormData, &TopOfScreen, &NewPos, &SkipValue); + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + ControlFlag = CfInitialization; + while (TRUE) { + switch (ControlFlag) { + case CfInitialization: + if (IsListEmpty (&gMenuOption)) { + + if ((FormData->Attribute & HII_DISPLAY_MODAL) == 0) { + // + // Clear Statement range. + // + ClearLines ( + gStatementDimensions.LeftColumn, + gStatementDimensions.RightColumn, + TopRow - SCROLL_ARROW_HEIGHT, + BottomRow + SCROLL_ARROW_HEIGHT, + GetFieldTextColor () + ); + + // + // Clear Key Range + // + RefreshKeyHelp (gFormData, NULL, FALSE); + } + + ControlFlag = CfReadKey; + } else { + ControlFlag = CfRepaint; + } + break; + + case CfRepaint: + ControlFlag = CfRefreshHighLight; + + if (Repaint) { + // + // Display menu + // + DownArrow = FALSE; + UpArrow = FALSE; + Row = TopRow; + + Temp = (UINTN) SkipValue; + Temp2 = (UINTN) SkipValue; + Temp3 = (UINTN) SkipValue; + + // + // 1. Clear the screen. + // + if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) { + ClearLines ( + gStatementDimensions.LeftColumn + ModalSkipColumn, + gStatementDimensions.LeftColumn + ModalSkipColumn + gPromptBlockWidth + gOptionBlockWidth, + TopRow - SCROLL_ARROW_HEIGHT, + BottomRow + SCROLL_ARROW_HEIGHT, + GetFieldTextColor () + ); + } else { + TempRightCol = gStatementDimensions.RightColumn; + if (!mStatementLayoutIsChanged) { + TempRightCol = gStatementDimensions.RightColumn - gHelpBlockWidth; + } + ClearLines ( + gStatementDimensions.LeftColumn, + gStatementDimensions.RightColumn, + TopRow - SCROLL_ARROW_HEIGHT, + TopRow - 1, + GetFieldTextColor () + ); + ClearLines ( + gStatementDimensions.LeftColumn, + TempRightCol, + TopRow, + BottomRow, + GetFieldTextColor () + ); + ClearLines ( + gStatementDimensions.LeftColumn, + gStatementDimensions.RightColumn, + BottomRow + 1, + BottomRow + SCROLL_ARROW_HEIGHT, + GetFieldTextColor () + ); + } + + // + // 2.Paint the menu. + // + for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) { + MenuOption = MENU_OPTION_FROM_LINK (Link); + MenuOption->Row = Row; + MenuOption->Col = Col; + if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) { + MenuOption->OptCol = gPromptBlockWidth + 1 + gStatementDimensions.LeftColumn + ModalSkipColumn; + } else { + MenuOption->OptCol = gPromptBlockWidth + 1 + gStatementDimensions.LeftColumn; + } + + Statement = MenuOption->ThisTag; + if (MenuOption->NestInStatement) { + MenuOption->Col += SUBTITLE_INDENT; + } + + if (MenuOption->GrayOut) { + gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ()); + } else { + if (Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) { + gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ()); + } + } + + Width = GetWidth (Statement); + OriginalRow = Row; + GlyphWidth = 1; + + if (Statement->OpCode->OpCode == EFI_IFR_REF_OP && MenuOption->Col >= 2) { + // + // Print Arrow for Goto button. + // + PrintCharAt ( + MenuOption->Col - 2, + Row, + GEOMETRICSHAPE_RIGHT_TRIANGLE + ); + } + + // + // 2.1. Paint the description. + // + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { + // + // Temp means need to skip how many lines from the start. + // + if ((Temp == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->Col, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index]) != 0) { + if (Temp == 0) { + Row++; + } + } + + FreePool (OutputString); + if (Temp != 0) { + Temp--; + } + } + + Temp = 0; + Row = OriginalRow; + + // + // 2.2. Paint the option string. + // + Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE); + // + // If Error occur, question value update in ProcessOptions. + // Exit current FormDisplay with new question value. + // + if (EFI_ERROR (Status)) { + return Status; + } + + if (OptionString != NULL) { + if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) { + ProcessStringForDateTime(MenuOption, OptionString, TRUE); + } + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = Row; + GlyphWidth = 1; + + for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { + if ((Temp2 == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->OptCol, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index]) != 0) { + if (Temp2 == 0) { + Row++; + // + // Since the Number of lines for this menu entry may or may not be reflected accurately + // since the prompt might be 1 lines and option might be many, and vice versa, we need to do + // some testing to ensure we are keeping this in-sync. + // + // If the difference in rows is greater than or equal to the skip value, increase the skip value + // + if ((Row - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + FreePool (OutputString); + if (Temp2 != 0) { + Temp2--; + } + } + + Row = OriginalRow; + + FreePool (OptionString); + } + Temp2 = 0; + + // + // If this is a text op with secondary text information + // + if ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo != 0)) { + StringPtr = GetToken (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo, gFormData->HiiHandle); + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = Row; + GlyphWidth = 1; + + for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { + if ((Temp3 == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->OptCol, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&StringPtr[Index]) != 0) { + if (Temp3 == 0) { + Row++; + // + // Since the Number of lines for this menu entry may or may not be reflected accurately + // since the prompt might be 1 lines and option might be many, and vice versa, we need to do + // some testing to ensure we are keeping this in-sync. + // + // If the difference in rows is greater than or equal to the skip value, increase the skip value + // + if ((Row - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + FreePool (OutputString); + if (Temp3 != 0) { + Temp3--; + } + } + + Row = OriginalRow; + FreePool (StringPtr); + } + Temp3 = 0; + + gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ()); + + // + // 3. Update the row info which will be used by next menu. + // + if (Link == TopOfScreen) { + Row += MenuOption->Skip - SkipValue; + } else { + Row += MenuOption->Skip; + } + + if (Row > BottomRow) { + if (!ValueIsScroll (FALSE, Link)) { + DownArrow = TRUE; + } + + Row = BottomRow + 1; + break; + } + } + + if (!ValueIsScroll (TRUE, TopOfScreen)) { + UpArrow = TRUE; + } + + if (UpArrow) { + gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ()); + PrintCharAt ( + gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, + TopRow - SCROLL_ARROW_HEIGHT, + ARROW_UP + ); + gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ()); + } + + if (DownArrow) { + gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ()); + PrintCharAt ( + gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, + BottomRow + SCROLL_ARROW_HEIGHT, + ARROW_DOWN + ); + gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ()); + } + + MenuOption = NULL; + } + break; + + case CfRefreshHighLight: + + // + // MenuOption: Last menu option that need to remove hilight + // MenuOption is set to NULL in Repaint + // NewPos: Current menu option that need to hilight + // + ControlFlag = CfUpdateHelpString; + + if (MenuOption != NULL && TopOfScreen == &MenuOption->Link) { + Temp = SkipValue; + } else { + Temp = 0; + } + if (NewPos == TopOfScreen) { + Temp2 = SkipValue; + } else { + Temp2 = 0; + } + + if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) { + if (MenuOption != NULL) { + // + // Remove highlight on last Menu Option + // + gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); + ProcessOptions (MenuOption, FALSE, &OptionString, TRUE); + gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ()); + if (OptionString != NULL) { + if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || + (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP) + ) { + ProcessStringForDateTime(MenuOption, OptionString, FALSE); + } + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = MenuOption->Row; + GlyphWidth = 1; + + for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { + if ((Temp == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow)) { + PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index]) != 0) { + if (Temp == 0) { + MenuOption->Row++; + } + } + + FreePool (OutputString); + if (Temp != 0) { + Temp--; + } + } + + MenuOption->Row = OriginalRow; + + FreePool (OptionString); + } else { + if (NewLine) { + if (MenuOption->GrayOut) { + gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ()); + } else if (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) { + gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ()); + } + + OriginalRow = MenuOption->Row; + Width = GetWidth (MenuOption->ThisTag); + GlyphWidth = 1; + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { + if ((Temp == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow)) { + PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index]) != 0) { + if (Temp == 0) { + MenuOption->Row++; + } + } + + FreePool (OutputString); + if (Temp != 0) { + Temp--; + } + } + + MenuOption->Row = OriginalRow; + gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ()); + } + } + } + + // + // This is the current selected statement + // + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + Statement = MenuOption->ThisTag; + + // + // Get the highlight statement. + // + gUserInput->SelectedStatement = Statement; + gSequence = (UINT16) MenuOption->Sequence; + + // + // Record highlight row info for date/time opcode. + // + if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) { + gHighligthMenuInfo.QuestionId = GetQuestionIdInfo(Statement->OpCode); + gHighligthMenuInfo.DisplayRow = (UINT16) MenuOption->Row; + } else { + gHighligthMenuInfo.QuestionId = 0; + gHighligthMenuInfo.DisplayRow = 0; + } + + if (!IsSelectable (MenuOption)) { + RefreshKeyHelp(gFormData, Statement, FALSE); + break; + } + + // + // Set reverse attribute + // + gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ()); + gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); + + ProcessOptions (MenuOption, FALSE, &OptionString, TRUE); + if (OptionString != NULL) { + if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) { + ProcessStringForDateTime(MenuOption, OptionString, FALSE); + } + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = MenuOption->Row; + GlyphWidth = 1; + + for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { + if ((Temp2 == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow) ) { + PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index]) != 0) { + if (Temp2 == 0) { + MenuOption->Row++; + } + } + + FreePool (OutputString); + if (Temp2 != 0) { + Temp2--; + } + } + + MenuOption->Row = OriginalRow; + + FreePool (OptionString); + } else { + if (NewLine) { + OriginalRow = MenuOption->Row; + + Width = GetWidth (Statement); + GlyphWidth = 1; + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { + if ((Temp2 == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow) ) { + PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index]) != 0) { + if (Temp2 == 0) { + MenuOption->Row++; + } + } + + FreePool (OutputString); + if (Temp2 != 0) { + Temp2--; + } + } + + MenuOption->Row = OriginalRow; + + } + } + + RefreshKeyHelp(gFormData, MenuOption->ThisTag, FALSE); + + // + // Clear reverse attribute + // + gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ()); + } + break; + + case CfUpdateHelpString: + ControlFlag = CfPrepareToReadKey; + if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) { + break; + } + + if (Repaint || NewLine) { + // + // Don't print anything if it is a NULL help token + // + ASSERT(MenuOption != NULL); + HelpInfo = ((EFI_IFR_STATEMENT_HEADER *) ((CHAR8 *)MenuOption->ThisTag->OpCode + sizeof (EFI_IFR_OP_HEADER)))->Help; + if (HelpInfo == 0 || !IsSelectable (MenuOption)) { + StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } else { + StringPtr = GetToken (HelpInfo, gFormData->HiiHandle); + } + + RowCount = BottomRow - TopRow + 1; + HelpPageIndex = 0; + // + // 1.Calculate how many line the help string need to print. + // + if (HelpString != NULL) { + FreePool (HelpString); + HelpString = NULL; + } + HelpLine = ProcessHelpString (StringPtr, &HelpString, &EachLineWidth, RowCount); + FreePool (StringPtr); + + if (HelpLine > RowCount) { + MultiHelpPage = TRUE; + StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP), gHiiHandle); + if (HelpHeaderString != NULL) { + FreePool (HelpHeaderString); + HelpHeaderString = NULL; + } + HelpHeaderLine = ProcessHelpString (StringPtr, &HelpHeaderString, &HeaderLineWidth, 0); + FreePool (StringPtr); + StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN), gHiiHandle); + if (HelpBottomString != NULL) { + FreePool (HelpBottomString); + HelpBottomString = NULL; + } + HelpBottomLine = ProcessHelpString (StringPtr, &HelpBottomString, &BottomLineWidth, 0); + FreePool (StringPtr); + // + // Calculate the help page count. + // + if (HelpLine > 2 * RowCount - 2) { + HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1; + if ((HelpLine - RowCount + 1) % (RowCount - 2) > 1) { + HelpPageCount += 1; + } + } else { + HelpPageCount = 2; + } + } else { + MultiHelpPage = FALSE; + } + } + + // + // Check whether need to show the 'More(U/u)' at the begin. + // Base on current direct info, here shows aligned to the right side of the column. + // If the direction is multi line and aligned to right side may have problem, so + // add ASSERT code here. + // + if (HelpPageIndex > 0) { + gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ()); + for (Index = 0; Index < HelpHeaderLine; Index++) { + ASSERT (HelpHeaderLine == 1); + ASSERT (GetStringWidth (HelpHeaderString) / 2 < (UINTN) (gHelpBlockWidth - 1)); + PrintStringAtWithWidth ( + gStatementDimensions.RightColumn - gHelpBlockWidth, + Index + TopRow, + gEmptyString, + gHelpBlockWidth + ); + PrintStringAt ( + gStatementDimensions.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1, + Index + TopRow, + &HelpHeaderString[Index * HeaderLineWidth] + ); + } + } + + gST->ConOut->SetAttribute (gST->ConOut, GetHelpTextColor ()); + // + // Print the help string info. + // + if (!MultiHelpPage) { + for (Index = 0; Index < HelpLine; Index++) { + PrintStringAtWithWidth ( + gStatementDimensions.RightColumn - gHelpBlockWidth, + Index + TopRow, + &HelpString[Index * EachLineWidth], + gHelpBlockWidth + ); + } + for (; Index < RowCount; Index ++) { + PrintStringAtWithWidth ( + gStatementDimensions.RightColumn - gHelpBlockWidth, + Index + TopRow, + gEmptyString, + gHelpBlockWidth + ); + } + gST->ConOut->SetCursorPosition(gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow); + } else { + if (HelpPageIndex == 0) { + for (Index = 0; Index < RowCount - HelpBottomLine; Index++) { + PrintStringAtWithWidth ( + gStatementDimensions.RightColumn - gHelpBlockWidth, + Index + TopRow, + &HelpString[Index * EachLineWidth], + gHelpBlockWidth + ); + } + } else { + for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) && + (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++) { + PrintStringAtWithWidth ( + gStatementDimensions.RightColumn - gHelpBlockWidth, + Index + TopRow + HelpHeaderLine, + &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* EachLineWidth], + gHelpBlockWidth + ); + } + if (HelpPageIndex == HelpPageCount - 1) { + for (; Index < RowCount - HelpHeaderLine; Index ++) { + PrintStringAtWithWidth ( + gStatementDimensions.RightColumn - gHelpBlockWidth, + Index + TopRow + HelpHeaderLine, + gEmptyString, + gHelpBlockWidth + ); + } + gST->ConOut->SetCursorPosition(gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow); + } + } + } + + // + // Check whether need to print the 'More(D/d)' at the bottom. + // Base on current direct info, here shows aligned to the right side of the column. + // If the direction is multi line and aligned to right side may have problem, so + // add ASSERT code here. + // + if (HelpPageIndex < HelpPageCount - 1 && MultiHelpPage) { + gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ()); + for (Index = 0; Index < HelpBottomLine; Index++) { + ASSERT (HelpBottomLine == 1); + ASSERT (GetStringWidth (HelpBottomString) / 2 < (UINTN) (gHelpBlockWidth - 1)); + PrintStringAtWithWidth ( + gStatementDimensions.RightColumn - gHelpBlockWidth, + BottomRow + Index - HelpBottomLine + 1, + gEmptyString, + gHelpBlockWidth + ); + PrintStringAt ( + gStatementDimensions.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1, + BottomRow + Index - HelpBottomLine + 1, + &HelpBottomString[Index * BottomLineWidth] + ); + } + } + // + // Reset this flag every time we finish using it. + // + Repaint = FALSE; + NewLine = FALSE; + break; + + case CfPrepareToReadKey: + ControlFlag = CfReadKey; + ScreenOperation = UiNoOperation; + break; + + case CfReadKey: + ControlFlag = CfScreenOperation; + + // + // Wait for user's selection + // + while (TRUE) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (!EFI_ERROR (Status)) { + EventType = UIEventKey; + break; + } + + // + // If we encounter error, continue to read another key in. + // + if (Status != EFI_NOT_READY) { + continue; + } + + EventType = UiWaitForEvent(gST->ConIn->WaitForKey); + if (EventType == UIEventKey) { + gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + } + break; + } + + if (EventType == UIEventDriver) { + gUserInput->Action = BROWSER_ACTION_NONE; + ControlFlag = CfExit; + break; + } + + if (EventType == UIEventTimeOut) { + gUserInput->Action = BROWSER_ACTION_FORM_EXIT; + ControlFlag = CfExit; + break; + } + + switch (Key.UnicodeChar) { + case CHAR_CARRIAGE_RETURN: + if(MenuOption == NULL || MenuOption->GrayOut || MenuOption->ReadOnly) { + ControlFlag = CfReadKey; + break; + } + + ScreenOperation = UiSelect; + gDirection = 0; + break; + + // + // We will push the adjustment of these numeric values directly to the input handler + // NOTE: we won't handle manual input numeric + // + case '+': + case '-': + // + // If the screen has no menu items, and the user didn't select UiReset + // ignore the selection and go back to reading keys. + // + if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) { + ControlFlag = CfReadKey; + break; + } + + ASSERT(MenuOption != NULL); + Statement = MenuOption->ThisTag; + if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) + || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) + || ((Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (GetFieldFromNum(Statement->OpCode) != 0)) + ){ + if (Key.UnicodeChar == '+') { + gDirection = SCAN_RIGHT; + } else { + gDirection = SCAN_LEFT; + } + + Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE); + if (OptionString != NULL) { + FreePool (OptionString); + } + if (EFI_ERROR (Status)) { + // + // Repaint to clear possible error prompt pop-up + // + Repaint = TRUE; + NewLine = TRUE; + } else { + ControlFlag = CfExit; + } + } + break; + + case '^': + ScreenOperation = UiUp; + break; + + case 'V': + case 'v': + ScreenOperation = UiDown; + break; + + case ' ': + if(IsListEmpty (&gMenuOption)) { + ControlFlag = CfReadKey; + break; + } + + ASSERT(MenuOption != NULL); + if (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) { + ScreenOperation = UiSelect; + } + break; + + case 'D': + case 'd': + if (!MultiHelpPage) { + ControlFlag = CfReadKey; + break; + } + ControlFlag = CfUpdateHelpString; + HelpPageIndex = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1; + break; + + case 'U': + case 'u': + if (!MultiHelpPage) { + ControlFlag = CfReadKey; + break; + } + ControlFlag = CfUpdateHelpString; + HelpPageIndex = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0; + break; + + case CHAR_NULL: + for (Index = 0; Index < mScanCodeNumber; Index++) { + if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) { + ScreenOperation = gScanCodeToOperation[Index].ScreenOperation; + break; + } + } + + if (((FormData->Attribute & HII_DISPLAY_MODAL) != 0) && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) { + // + // ModalForm has no ESC key and Hot Key. + // + ControlFlag = CfReadKey; + } else if (Index == mScanCodeNumber) { + // + // Check whether Key matches the registered hot key. + // + HotKey = NULL; + HotKey = GetHotKeyFromRegisterList (&Key); + if (HotKey != NULL) { + ScreenOperation = UiHotKey; + } + } + break; + } + break; + + case CfScreenOperation: + if (ScreenOperation != UiReset) { + // + // If the screen has no menu items, and the user didn't select UiReset + // ignore the selection and go back to reading keys. + // + if (IsListEmpty (&gMenuOption)) { + ControlFlag = CfReadKey; + break; + } + } + + for (Index = 0; + Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]); + Index++ + ) { + if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) { + ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag; + break; + } + } + break; + + case CfUiSelect: + ControlFlag = CfRepaint; + + ASSERT(MenuOption != NULL); + Statement = MenuOption->ThisTag; + if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) { + break; + } + + switch (Statement->OpCode->OpCode) { + case EFI_IFR_REF_OP: + case EFI_IFR_ACTION_OP: + case EFI_IFR_RESET_BUTTON_OP: + ControlFlag = CfExit; + break; + + default: + // + // Editable Questions: oneof, ordered list, checkbox, numeric, string, password + // + RefreshKeyHelp (gFormData, Statement, TRUE); + Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE); + + if (OptionString != NULL) { + FreePool (OptionString); + } + + if (EFI_ERROR (Status)) { + Repaint = TRUE; + NewLine = TRUE; + RefreshKeyHelp (gFormData, Statement, FALSE); + break; + } else { + ControlFlag = CfExit; + break; + } + } + break; + + case CfUiReset: + // + // We come here when someone press ESC + // If the policy is not exit front page when user press ESC, process here. + // + if (!FormExitPolicy()) { + Repaint = TRUE; + NewLine = TRUE; + ControlFlag = CfRepaint; + break; + } + + // + // When user press ESC, it will try to show another menu, should clean the gSequence info. + // + if (gSequence != 0) { + gSequence = 0; + } + + gUserInput->Action = BROWSER_ACTION_FORM_EXIT; + ControlFlag = CfExit; + break; + + case CfUiHotKey: + ControlFlag = CfRepaint; + + gUserInput->Action = HotKey->Action; + ControlFlag = CfExit; + break; + + case CfUiLeft: + ControlFlag = CfRepaint; + ASSERT(MenuOption != NULL); + if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) { + if (MenuOption->Sequence != 0) { + // + // In the middle or tail of the Date/Time op-code set, go left. + // + ASSERT(NewPos != NULL); + NewPos = NewPos->BackLink; + } + } + break; + + case CfUiRight: + ControlFlag = CfRepaint; + ASSERT(MenuOption != NULL); + if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) { + if (MenuOption->Sequence != 2) { + // + // In the middle or tail of the Date/Time op-code set, go left. + // + ASSERT(NewPos != NULL); + NewPos = NewPos->ForwardLink; + } + } + break; + + case CfUiUp: + ControlFlag = CfRepaint; + + SavedListEntry = NewPos; + + ASSERT(NewPos != NULL); + // + // Adjust Date/Time position before we advance forward. + // + AdjustDateAndTimePosition (TRUE, &NewPos); + if (NewPos->BackLink != &gMenuOption) { + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + ASSERT (MenuOption != NULL); + NewLine = TRUE; + NewPos = NewPos->BackLink; + + PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos); + if (PreviousMenuOption->Row == 0) { + UpdateOptionSkipLines (PreviousMenuOption); + } + DistanceValue = PreviousMenuOption->Skip; + Difference = 0; + if (MenuOption->Row >= DistanceValue + TopRow) { + Difference = MoveToNextStatement (TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue); + } + NextMenuOption = MENU_OPTION_FROM_LINK (NewPos); + + if (Difference < 0) { + // + // We hit the begining MenuOption that can be focused + // so we simply scroll to the top. + // + if (TopOfScreen != gMenuOption.ForwardLink) { + TopOfScreen = gMenuOption.ForwardLink; + Repaint = TRUE; + } else { + // + // Scroll up to the last page when we have arrived at top page. + // + NewPos = &gMenuOption; + TopOfScreen = &gMenuOption; + MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); + ScreenOperation = UiPageUp; + ControlFlag = CfScreenOperation; + break; + } + } else if (MenuOption->Row < TopRow + DistanceValue + Difference) { + // + // Previous focus MenuOption is above the TopOfScreen, so we need to scroll + // + TopOfScreen = NewPos; + Repaint = TRUE; + SkipValue = 0; + } else if (!IsSelectable (NextMenuOption)) { + // + // Continue to go up until scroll to next page or the selectable option is found. + // + ScreenOperation = UiUp; + ControlFlag = CfScreenOperation; + } + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); + UpdateStatusBar (INPUT_ERROR, FALSE); + } else { + // + // Scroll up to the last page. + // + NewPos = &gMenuOption; + TopOfScreen = &gMenuOption; + MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); + ScreenOperation = UiPageUp; + ControlFlag = CfScreenOperation; + } + break; + + case CfUiPageUp: + // + // SkipValue means lines is skipped when show the top menu option. + // + ControlFlag = CfRepaint; + + ASSERT(NewPos != NULL); + // + // Already at the first menu option, Check the skip value. + // + if (NewPos->BackLink == &gMenuOption) { + if (SkipValue == 0) { + NewLine = FALSE; + Repaint = FALSE; + } else { + NewLine = TRUE; + Repaint = TRUE; + SkipValue = 0; + } + break; + } + + NewLine = TRUE; + Repaint = TRUE; + + // + // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one + // form of options to be show, so just update the SkipValue to show the next + // parts of options. + // + if (SkipValue > (INTN) (BottomRow - TopRow + 1)) { + SkipValue -= BottomRow - TopRow + 1; + break; + } + + Link = TopOfScreen; + // + // First minus the menu of the top screen, it's value is SkipValue. + // + Index = (BottomRow + 1) - SkipValue; + while ((Index > TopRow) && (Link->BackLink != &gMenuOption)) { + Link = Link->BackLink; + PreviousMenuOption = MENU_OPTION_FROM_LINK (Link); + if (PreviousMenuOption->Row == 0) { + UpdateOptionSkipLines (PreviousMenuOption); + } + if (Index < PreviousMenuOption->Skip) { + break; + } + Index = Index - PreviousMenuOption->Skip; + } + + if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) { + SkipValue = 0; + if (TopOfScreen == &gMenuOption) { + TopOfScreen = gMenuOption.ForwardLink; + NewPos = gMenuOption.BackLink; + MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow); + Repaint = FALSE; + } else if (TopOfScreen != Link) { + TopOfScreen = Link; + NewPos = Link; + MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow); + } else { + // + // Finally we know that NewPos is the last MenuOption can be focused. + // + Repaint = FALSE; + NewPos = Link; + MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow); + } + } else { + if (Index > TopRow) { + // + // At here, only case "Index < PreviousMenuOption->Skip" can reach here. + // + SkipValue = PreviousMenuOption->Skip - (Index - TopRow); + } else if (Index == TopRow) { + SkipValue = 0; + } else { + SkipValue = TopRow - Index; + } + + // + // Move to the option in Next page. + // + if (TopOfScreen == &gMenuOption) { + NewPos = gMenuOption.BackLink; + MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow); + } else { + NewPos = Link; + MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow); + } + + // + // There are more MenuOption needing scrolling up. + // + TopOfScreen = Link; + MenuOption = NULL; + } + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // Don't do this when we are already in the first page. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + break; + + case CfUiPageDown: + // + // SkipValue means lines is skipped when show the top menu option. + // + ControlFlag = CfRepaint; + + ASSERT (NewPos != NULL); + if (NewPos->ForwardLink == &gMenuOption) { + NewLine = FALSE; + Repaint = FALSE; + break; + } + + NewLine = TRUE; + Repaint = TRUE; + Link = TopOfScreen; + NextMenuOption = MENU_OPTION_FROM_LINK (Link); + Index = TopRow + NextMenuOption->Skip - SkipValue; + // + // Count to the menu option which will show at the top of the next form. + // + while ((Index <= BottomRow + 1) && (Link->ForwardLink != &gMenuOption)) { + Link = Link->ForwardLink; + NextMenuOption = MENU_OPTION_FROM_LINK (Link); + Index = Index + NextMenuOption->Skip; + } + + if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) { + // + // Finally we know that NewPos is the last MenuOption can be focused. + // + Repaint = FALSE; + MoveToNextStatement (TRUE, &Link, Index - TopRow); + } else { + // + // Calculate the skip line for top of screen menu. + // + if (Link == TopOfScreen) { + // + // The top of screen menu option occupies the entire form. + // + SkipValue += BottomRow - TopRow + 1; + } else { + SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1)); + } + + TopOfScreen = Link; + MenuOption = NULL; + // + // Move to the Next selectable menu. + // + MoveToNextStatement (FALSE, &Link, BottomRow - TopRow); + } + + // + // Save the menu as the next highlight menu. + // + NewPos = Link; + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // Don't do this when we are already in the last page. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + break; + + case CfUiDown: + // + // SkipValue means lines is skipped when show the top menu option. + // NewPos points to the menu which is highlighted now. + // + ControlFlag = CfRepaint; + + // + // Since the behavior of hitting the down arrow on a Date/Time op-code is intended + // to be one that progresses to the next set of op-codes, we need to advance to the last + // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate + // checking can be done. The only other logic we need to introduce is that if a Date/Time + // op-code is the last entry in the menu, we need to rewind back to the first op-code of + // the Date/Time op-code. + // + SavedListEntry = NewPos; + AdjustDateAndTimePosition (FALSE, &NewPos); + + if (NewPos->ForwardLink != &gMenuOption) { + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + NewLine = TRUE; + NewPos = NewPos->ForwardLink; + + Difference = 0; + // + // Current menu not at the bottom of the form. + // + if (BottomRow >= MenuOption->Row + MenuOption->Skip) { + // + // Find the next selectable menu. + // + Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip); + // + // We hit the end of MenuOption that can be focused + // so we simply scroll to the first page. + // + if (Difference < 0) { + // + // Scroll to the first page. + // + if (TopOfScreen != gMenuOption.ForwardLink) { + TopOfScreen = gMenuOption.ForwardLink; + Repaint = TRUE; + MenuOption = NULL; + } else { + MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); + } + NewPos = gMenuOption.ForwardLink; + MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow); + + SkipValue = 0; + // + // If we are at the end of the list and sitting on a Date/Time op, rewind to the head. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + break; + } + } + NextMenuOption = MENU_OPTION_FROM_LINK (NewPos); + if (NextMenuOption->Row == 0) { + UpdateOptionSkipLines (NextMenuOption); + } + DistanceValue = Difference + NextMenuOption->Skip; + + Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1; + if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) && + (NextMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP || + NextMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP) + ) { + Temp ++; + } + + // + // If we are going to scroll, update TopOfScreen + // + if (Temp > BottomRow) { + do { + // + // Is the current top of screen a zero-advance op-code? + // If so, keep moving forward till we hit a >0 advance op-code + // + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + + // + // If bottom op-code is more than one line or top op-code is more than one line + // + if ((DistanceValue > 1) || (SavedMenuOption->Skip > 1)) { + // + // Is the bottom op-code greater than or equal in size to the top op-code? + // + if ((Temp - BottomRow) >= (SavedMenuOption->Skip - SkipValue)) { + // + // Skip the top op-code + // + TopOfScreen = TopOfScreen->ForwardLink; + Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue); + + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + + // + // If we have a remainder, skip that many more op-codes until we drain the remainder + // + while (Difference >= (INTN) SavedMenuOption->Skip) { + // + // Since the Difference is greater than or equal to this op-code's skip value, skip it + // + Difference = Difference - (INTN) SavedMenuOption->Skip; + TopOfScreen = TopOfScreen->ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + } + // + // Since we will act on this op-code in the next routine, and increment the + // SkipValue, set the skips to one less than what is required. + // + SkipValue = Difference - 1; + } else { + // + // Since we will act on this op-code in the next routine, and increment the + // SkipValue, set the skips to one less than what is required. + // + SkipValue += (Temp - BottomRow) - 1; + } + } else { + if ((SkipValue + 1) == (INTN) SavedMenuOption->Skip) { + TopOfScreen = TopOfScreen->ForwardLink; + break; + } + } + // + // If the op-code at the top of the screen is more than one line, let's not skip it yet + // Let's set a skip flag to smoothly scroll the top of the screen. + // + if (SavedMenuOption->Skip > 1) { + if (SavedMenuOption == NextMenuOption) { + SkipValue = 0; + } else { + SkipValue++; + } + } else if (SavedMenuOption->Skip == 1) { + SkipValue = 0; + } else { + SkipValue = 0; + TopOfScreen = TopOfScreen->ForwardLink; + } + } while (SavedMenuOption->Skip == 0); + + Repaint = TRUE; + } else if (!IsSelectable (NextMenuOption)) { + // + // Continue to go down until scroll to next page or the selectable option is found. + // + ScreenOperation = UiDown; + ControlFlag = CfScreenOperation; + } + + MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); + + UpdateStatusBar (INPUT_ERROR, FALSE); + + } else { + // + // Scroll to the first page. + // + if (TopOfScreen != gMenuOption.ForwardLink) { + TopOfScreen = gMenuOption.ForwardLink; + Repaint = TRUE; + MenuOption = NULL; + } else { + // + // Need to remove the current highlight menu. + // MenuOption saved the last highlight menu info. + // + MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); + } + + SkipValue = 0; + NewLine = TRUE; + // + // Get the next highlight menu. + // + NewPos = gMenuOption.ForwardLink; + MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow); + } + + // + // If we are at the end of the list and sitting on a Date/Time op, rewind to the head. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + break; + + case CfUiNoOperation: + ControlFlag = CfRepaint; + break; + + case CfExit: + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + if (HelpString != NULL) { + FreePool (HelpString); + } + if (HelpHeaderString != NULL) { + FreePool (HelpHeaderString); + } + if (HelpBottomString != NULL) { + FreePool (HelpBottomString); + } + return EFI_SUCCESS; + + default: + break; + } + } +} + +/** + + Base on the browser status info to show an pop up message. + +**/ +VOID +BrowserStatusProcess ( + VOID + ) +{ + CHAR16 *ErrorInfo; + EFI_INPUT_KEY Key; + + if (gFormData->BrowserStatus == BROWSER_SUCCESS) { + return; + } + + if (gFormData->ErrorString != NULL) { + ErrorInfo = gFormData->ErrorString; + } else { + switch (gFormData->BrowserStatus) { + case BROWSER_SUBMIT_FAIL: + ErrorInfo = gSaveFailed; + break; + + case BROWSER_NO_SUBMIT_IF: + ErrorInfo = gNoSubmitIf; + break; + + case BROWSER_FORM_NOT_FOUND: + ErrorInfo = gFormNotFound; + break; + + case BROWSER_FORM_SUPPRESS: + ErrorInfo = gFormSuppress; + break; + + case BROWSER_PROTOCOL_NOT_FOUND: + ErrorInfo = gProtocolNotFound; + break; + + default: + ErrorInfo = gBrwoserError; + break; + } + } + + // + // Error occur, prompt error message. + // + do { + CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); +} + +/** + Display one form, and return user input. + + @param FormData Form Data to be shown. + @param UserInputData User input data. + + @retval EFI_SUCCESS 1.Form Data is shown, and user input is got. + 2.Error info has show and return. + @retval EFI_INVALID_PARAMETER The input screen dimension is not valid + @retval EFI_NOT_FOUND New form data has some error. +**/ +EFI_STATUS +EFIAPI +FormDisplay ( + IN FORM_DISPLAY_ENGINE_FORM *FormData, + OUT USER_INPUT *UserInputData + ) +{ + EFI_STATUS Status; + + ASSERT (FormData != NULL); + if (FormData == NULL) { + return EFI_INVALID_PARAMETER; + } + + gUserInput = UserInputData; + gFormData = FormData; + + // + // Process the status info first. + // + BrowserStatusProcess(); + if (UserInputData == NULL) { + // + // UserInputData == NULL, means only need to print the error info, return here. + // + return EFI_SUCCESS; + } + + ConvertStatementToMenu(); + + Status = DisplayPageFrame (FormData, &gStatementDimensions); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check whether layout is changed. + // + if (mIsFirstForm + || (gOldFormEntry.HiiHandle != FormData->HiiHandle) + || (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid)) + || (gOldFormEntry.FormId != FormData->FormId)) { + mStatementLayoutIsChanged = TRUE; + } else { + mStatementLayoutIsChanged = FALSE; + } + + Status = UiDisplayMenu(FormData); + + // + // Backup last form info. + // + mIsFirstForm = FALSE; + gOldFormEntry.HiiHandle = FormData->HiiHandle; + CopyGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid); + gOldFormEntry.FormId = FormData->FormId; + + return Status; +} + +/** + Clear Screen to the initial state. +**/ +VOID +EFIAPI +DriverClearDisplayPage ( + VOID + ) +{ + ClearDisplayPage (); + mIsFirstForm = TRUE; +} + +/** + Set Buffer to Value for Size bytes. + + @param Buffer Memory to set. + @param Size Number of bytes to set + @param Value Value of the set operation. + +**/ +VOID +SetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ) +{ + CHAR16 *Ptr; + + Ptr = Buffer; + while ((Size--) != 0) { + *(Ptr++) = Value; + } +} + +/** + Initialize Setup Browser driver. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCCESS The Setup Browser module is initialized correctly.. + @return Other value if failed to initialize the Setup Browser module. + +**/ +EFI_STATUS +EFIAPI +InitializeDisplayEngine ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY HotKey; + EFI_STRING NewString; + EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2; + + // + // Publish our HII data + // + gHiiHandle = HiiAddPackages ( + &gDisplayEngineGuid, + ImageHandle, + DisplayEngineStrings, + NULL + ); + ASSERT (gHiiHandle != NULL); + + // + // Install Form Display protocol + // + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEdkiiFormDisplayEngineProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.FromDisplayProt + ); + ASSERT_EFI_ERROR (Status); + + InitializeDisplayStrings(); + + ZeroMem (&gHighligthMenuInfo, sizeof (gHighligthMenuInfo)); + ZeroMem (&gOldFormEntry, sizeof (gOldFormEntry)); + + // + // Use BrowserEx2 protocol to register HotKey. + // + Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **) &FormBrowserEx2); + if (!EFI_ERROR (Status)) { + // + // Register the default HotKey F9 and F10 again. + // + HotKey.UnicodeChar = CHAR_NULL; + HotKey.ScanCode = SCAN_F10; + NewString = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_TEN_STRING), NULL); + ASSERT (NewString != NULL); + FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_SUBMIT, 0, NewString); + + HotKey.ScanCode = SCAN_F9; + NewString = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_NINE_STRING), NULL); + ASSERT (NewString != NULL); + FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, NewString); + } + + return EFI_SUCCESS; +} + +/** + This is the default unload handle for display core drivers. + + @param[in] ImageHandle The drivers' driver image. + + @retval EFI_SUCCESS The image is unloaded. + @retval Others Failed to unload the image. + +**/ +EFI_STATUS +EFIAPI +UnloadDisplayEngine ( + IN EFI_HANDLE ImageHandle + ) +{ + HiiRemovePackages(gHiiHandle); + + FreeDisplayStrings (); + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h new file mode 100644 index 0000000000..45bcadc7e6 --- /dev/null +++ b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h @@ -0,0 +1,589 @@ +/** @file + FormDiplay protocol to show Form + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __FORM_DISPLAY_H__ +#define __FORM_DISPLAY_H__ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +// +// This is the generated header file which includes whatever needs to be exported (strings + IFR) +// +extern UINT8 DisplayEngineStrings[]; +extern EFI_SCREEN_DESCRIPTOR gStatementDimensions; +extern USER_INPUT *gUserInput; +extern FORM_DISPLAY_ENGINE_FORM *gFormData; +extern EFI_HII_HANDLE gHiiHandle; +extern UINT16 gDirection; +extern LIST_ENTRY gMenuOption; + +// +// Browser Global Strings +// +extern CHAR16 *gSaveFailed; +extern CHAR16 *gPromptForData; +extern CHAR16 *gPromptForPassword; +extern CHAR16 *gPromptForNewPassword; +extern CHAR16 *gConfirmPassword; +extern CHAR16 *gConfirmError; +extern CHAR16 *gPassowordInvalid; +extern CHAR16 *gPressEnter; +extern CHAR16 *gEmptyString; +extern CHAR16 *gMiniString; +extern CHAR16 *gOptionMismatch; +extern CHAR16 *gFormSuppress; +extern CHAR16 *gProtocolNotFound; + +extern CHAR16 gPromptBlockWidth; +extern CHAR16 gOptionBlockWidth; +extern CHAR16 gHelpBlockWidth; +extern CHAR16 *mUnknownString; + +// +// Screen definitions +// + +#define LEFT_SKIPPED_COLUMNS 3 +#define SCROLL_ARROW_HEIGHT 1 +#define POPUP_PAD_SPACE_COUNT 5 +#define POPUP_FRAME_WIDTH 2 + +// +// Display definitions +// +#define LEFT_ONEOF_DELIMITER L'<' +#define RIGHT_ONEOF_DELIMITER L'>' + +#define LEFT_NUMERIC_DELIMITER L'[' +#define RIGHT_NUMERIC_DELIMITER L']' + +#define LEFT_CHECKBOX_DELIMITER L'[' +#define RIGHT_CHECKBOX_DELIMITER L']' + +#define CHECK_ON L'X' +#define CHECK_OFF L' ' + +#define TIME_SEPARATOR L':' +#define DATE_SEPARATOR L'/' + +#define SUBTITLE_INDENT 2 + +// +// This is the Input Error Message +// +#define INPUT_ERROR 1 + +// +// This is the NV RAM update required Message +// +#define NV_UPDATE_REQUIRED 2 +// +// Time definitions +// +#define ONE_SECOND 10000000 + +// +// It take 23 characters including the NULL to print a 64 bits number with "[" and "]". +// pow(2, 64) = [18446744073709551616] +// +#define MAX_NUMERIC_INPUT_WIDTH 23 + +#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0 +#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1 +#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2 +#define EFI_HII_EXPRESSION_SUPPRESS_IF 3 +#define EFI_HII_EXPRESSION_DISABLE_IF 4 + +// +// Character definitions +// +#define CHAR_SPACE 0x0020 + +#define FORM_DISPLAY_DRIVER_SIGNATURE SIGNATURE_32 ('F', 'D', 'D', 'V') +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + + // + // Produced protocol + // + EDKII_FORM_DISPLAY_ENGINE_PROTOCOL FromDisplayProt; +} FORM_DISPLAY_DRIVER_PRIVATE_DATA; + + +typedef enum { + UiNoOperation, + UiSelect, + UiUp, + UiDown, + UiLeft, + UiRight, + UiReset, + UiPrevious, + UiPageUp, + UiPageDown, + UiHotKey, + UiMaxOperation +} UI_SCREEN_OPERATION; + +typedef enum { + CfInitialization, + CfCheckSelection, + CfRepaint, + CfRefreshHighLight, + CfUpdateHelpString, + CfPrepareToReadKey, + CfReadKey, + CfScreenOperation, + CfUiSelect, + CfUiReset, + CfUiLeft, + CfUiRight, + CfUiUp, + CfUiPageUp, + CfUiPageDown, + CfUiDown, + CfUiDefault, + CfUiNoOperation, + CfExit, + CfUiHotKey, + CfMaxControlFlag +} UI_CONTROL_FLAG; + +typedef enum { + UIEventNone, + UIEventKey, + UIEventTimeOut, + UIEventDriver +} UI_EVENT_TYPE; + +typedef struct { + UINT16 ScanCode; + UI_SCREEN_OPERATION ScreenOperation; +} SCAN_CODE_TO_SCREEN_OPERATION; + +typedef struct { + UI_SCREEN_OPERATION ScreenOperation; + UI_CONTROL_FLAG ControlFlag; +} SCREEN_OPERATION_T0_CONTROL_FLAG; + +typedef struct { + EFI_QUESTION_ID QuestionId; + UINT16 DisplayRow; +} DISPLAY_HIGHLIGHT_MENU_INFO; + +#define UI_MENU_OPTION_SIGNATURE SIGNATURE_32 ('u', 'i', 'm', 'm') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_HII_HANDLE Handle; + FORM_DISPLAY_ENGINE_STATEMENT *ThisTag; + UINT16 EntryNumber; + + UINTN Row; + UINTN Col; + UINTN OptCol; + CHAR16 *Description; + UINTN Skip; // Number of lines + + // + // Display item sequence for date/time + // Date: Month/Day/Year + // Sequence: 0 1 2 + // + // Time: Hour : Minute : Second + // Sequence: 0 1 2 + // + // + UINTN Sequence; + + BOOLEAN GrayOut; + BOOLEAN ReadOnly; + + // + // Whether user could change value of this item + // + BOOLEAN IsQuestion; + BOOLEAN NestInStatement; +} UI_MENU_OPTION; + +#define MENU_OPTION_FROM_LINK(a) CR (a, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE) + +/** + Print Question Value according to it's storage width and display attributes. + + @param Question The Question to be printed. + @param FormattedNumber Buffer for output string. + @param BufferSize The FormattedNumber buffer size in bytes. + + @retval EFI_SUCCESS Print success. + @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number. + +**/ +EFI_STATUS +PrintFormattedNumber ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question, + IN OUT CHAR16 *FormattedNumber, + IN UINTN BufferSize + ); + +/** + Set value of a data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + @param Value The value to be set. + +**/ +VOID +SetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index, + IN UINT64 Value + ); + +/** + Return data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + + @retval Value The data to be returned + +**/ +UINT64 +GetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index + ); + +/** + Search an Option of a Question by its value. + + @param Question The Question + @param OptionValue Value for Option to be searched. + + @retval Pointer Pointer to the found Option. + @retval NULL Option not found. + +**/ +DISPLAY_QUESTION_OPTION * +ValueToOption ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue + ); + +/** + Compare two Hii value. + + @param Value1 Expression value to compare on left-hand. + @param Value2 Expression value to compare on right-hand. + @param Result Return value after compare. + retval 0 Two operators equal. + return Positive value if Value1 is greater than Value2. + retval Negative value if Value1 is less than Value2. + @param HiiHandle Only required for string compare. + + @retval other Could not perform compare on two values. + @retval EFI_SUCCESS Compare the value success. + +**/ +EFI_STATUS +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + OUT INTN *Result, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ); + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param ... A series of text strings that displayed in the pop-up. + +**/ +VOID +EFIAPI +CreateMultiStringPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + ... + ); + +/** + Will copy LineWidth amount of a string in the OutputString buffer and return the + number of CHAR16 characters that were copied into the OutputString buffer. + The output string format is: + Glyph Info + String info + '\0'. + + In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g. + + @param InputString String description for this option. + @param LineWidth Width of the desired string to extract in CHAR16 + characters + @param GlyphWidth The glyph width of the begin of the char in the string. + @param Index Where in InputString to start the copy process + @param OutputString Buffer to copy the string into + + @return Returns the number of CHAR16 characters that were copied into the OutputString + buffer, include extra glyph info and '\0' info. + +**/ +UINT16 +GetLineByWidth ( + IN CHAR16 *InputString, + IN UINT16 LineWidth, + IN OUT UINT16 *GlyphWidth, + IN OUT UINTN *Index, + OUT CHAR16 **OutputString + ); + + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The Hii handle for this string package. + + @return The output string. + +**/ +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ); + +/** + Count the storage space of a Unicode string. + + This function handles the Unicode string with NARROW_CHAR + and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR + does not count in the resultant output. If a WIDE_CHAR is + hit, then 2 Unicode character will consume an output storage + space with size of CHAR16 till a NARROW_CHAR is hit. + + If String is NULL, then ASSERT (). + + @param String The input string to be counted. + + @return Storage space for the input string. + +**/ +UINTN +GetStringWidth ( + IN CHAR16 *String + ); + +/** + This routine reads a numeric value from the user input. + + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If numerical input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetNumericInput ( + IN UI_MENU_OPTION *MenuOption + ); + +/** + Get string or password input from user. + + @param MenuOption Pointer to the current input menu. + @param Prompt The prompt string shown on popup window. + @param StringPtr Old user input and destination for use input string. + + @retval EFI_SUCCESS If string input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +ReadString ( + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *Prompt, + IN OUT CHAR16 *StringPtr + ); + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param Marker The variable argument list for the list of string to be printed. + +**/ +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN VA_LIST Marker + ); + +/** + Wait for a key to be pressed by user. + + @param Key The key which is pressed by user. + + @retval EFI_SUCCESS The function always completed successfully. + +**/ +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ); + +/** + Get selection for OneOf and OrderedList (Left/Right will be ignored). + + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If Option input is processed successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetSelectionInputPopUp ( + IN UI_MENU_OPTION *MenuOption + ); + +/** + Process the help string: Split StringPtr to several lines of strings stored in + FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth. + + @param StringPtr The entire help string. + @param FormattedString The oupput formatted string. + @param EachLineWidth The max string length of each line in the formatted string. + @param RowCount TRUE: if Question is selected. + +**/ +UINTN +ProcessHelpString ( + IN CHAR16 *StringPtr, + OUT CHAR16 **FormattedString, + OUT UINT16 *EachLineWidth, + IN UINTN RowCount + ); + +/** + Process a Question's Option (whether selected or un-selected). + + @param MenuOption The MenuOption for this Question. + @param Selected TRUE: if Question is selected. + @param OptionString Pointer of the Option String to be displayed. + @param SkipErrorValue Whether need to return when value without option for it. + + @retval EFI_SUCCESS Question Option process success. + @retval Other Question Option process fail. + +**/ +EFI_STATUS +ProcessOptions ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected, + OUT CHAR16 **OptionString, + IN BOOLEAN SkipErrorValue + ); + +/** + Set Buffer to Value for Size bytes. + + @param Buffer Memory to set. + @param Size Number of bytes to set + @param Value Value of the set operation. + +**/ +VOID +SetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ); + +/** + Display one form, and return user input. + + @param FormData Form Data to be shown. + @param UserInputData User input data. + + @retval EFI_SUCCESS Form Data is shown, and user input is got. +**/ +EFI_STATUS +EFIAPI +FormDisplay ( + IN FORM_DISPLAY_ENGINE_FORM *FormData, + OUT USER_INPUT *UserInputData + ); + +/** + Clear Screen to the initial state. +**/ +VOID +EFIAPI +DriverClearDisplayPage ( + VOID + ); + +/** + Exit Display and Clear Screen to the original state. + +**/ +VOID +EFIAPI +ExitDisplay ( + VOID + ); + +/** + Process validate for one question. + + @param Question The question which need to validate. + + @retval EFI_SUCCESS Question Option process success. + @retval Other Question Option process fail. + +**/ +EFI_STATUS +ValidateQuestion ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question + ); + +#endif diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserStr.uni b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni similarity index 51% rename from MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserStr.uni rename to MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni index bb6414d2063253f2bca5bfb00c999f37eada585c..0ee7f46302f0f9cbf66981dc309c0094322b0a77 100644 GIT binary patch delta 578 zcmX?5e8qXg99Hg720sRGAogbnpZu0hb8-Qv9;4#qi;|T<@*tbIdN4x>gCh`!G6XZk zGdM8>fm8z7u0U2im;{LgO};2)ZR^BP#E{QW&QQ#d3S=oT$yNarzt?WE8IpnFyEyVnimRtDe6{6>^2r3B^_aF9O$vIqYI)+`=$IY`>Vxk?UG3?p z?;h&Tn(ou0?0e|XPTWw>4%}OPchvH+d+J`eZz`zvgruidh58++zpn55Oy`H{yQANc zTAcXvW1&5FXKKm4cY3a`_Jyv1hWGSz^hUjf(bLPoKmA7cj&;=ci0C);&(odp8{X=; zrydU7k-mBBrAI;EB@%nrnMWOZ0U3CE*Ss*Mb9Y*K?x}0L4V`aIU@5U)c`lCi4Z6wE z_JoEWVZ-?1T|=ES>LcN-%A;`b3jR~wG1-9n2epb(O)_I_zEi8C@$=_n4!|_3FpCC_ zB#W=To}pXDF6{@N>xUZuKoVLNf-3t%T{#l=j3UPW(#MW}`wN|cool>vPpxRfTdmcm+VbRU z{r*LFK#m1A#&5AvG~Bn>{gk~o#l^1lig#|v&H``Yx6u7_@r^E^6)nl~Oh;cQS{AzB z*1eHhUufi5<&~s`4YYN2p#HInUgFs`FIU>2zoQxbo8FrJVtuFTk3NGI4~62?>ksT# zF{DPfB2D^q?Clt{jr)mv;EyHg@R2$y+Wtb8Q)unf38^pYQ4W4!r}pK>LIugX*!-;W;M`!Tu_+XJDjYR66P zu zF{%`%s#PGj$KEn5;(g;eA{RLE){So>I~XVy*Tq?kZ(Y`V?pf;zS0Sv+*C^i$_k14L z<&(Gd!MEqJdK(_erO0I95_az=mjUB@kMVYV67kj**>)v|yW_JVyEv9UHk8v4HSPm{ z0aIJD9SGB68n`G+Rcp@Cz<@3=R+q&F995RmR@s);y!2YLsiUUy8_VjdBcFbp!^x(P z+}NPaG>DjWM*+M)KI~Gcu(%)f_dYu!tSRFE*=IF)FLLHBS>A#E)|6jhfgAE~uM|I1 z%;j)KCTVl3kJZ`+&oJGv%WnUbnIN{o&yzGmY%X`AhB$nB{w4^!P%C~K< zF^!G#dJZq2i3_R#Zj(jW{j`Mvo*E|k)#xe4_*nB3BPZfaQJxO5RCx^qT_B~fl zL+y}xvegjlVvWqtxMBuEb&UF>)$z`J^h6h_ad3Z{{;jFfVp%D1vQe3#&tonxCSV)X zQi8=6zGgsHO*PeKDpVyy?O^^}7ip1_ZagmsVL&n*XRNSD{UuzVX1`R{*5&&wY7jH1 zs2zB#-j!X?*1#0Hc=q{)d!*X*SE@|^*8R@?-u*#UjyV$^3-J=VG*Y0 zw@smqxlE%SN*mEZ(@uEp_$z&7b;ff!j#3liI87$^?FZ(1Wz6o1YBKkk??hp{tMidhCtL%HMSV z{5opRe)FPtQ%GYyP9c3N#LT!u1=%vBb$^vOWuBL{AuMsE>(nXJe%EUFRIHh!Y>Hp% zSIkh_`n>YztdpcasS(6n?|Mc-47QQ#Q>;!D9$TR^Tccpji8e#Uf95ou+H!!ls#L5y zk#m9#FF|eS(EZ1I4*0YYaG#1Bqan@(zfz86G1jR;zsg|$E?Msj{gof#FPVMnvzI>O zrMkYTG^jGRr29?j{&oicleVz9G_0b`D$BrUAEgca(xfpt5}R*St>SLwLRQ0y;|oc6 z{wGf^lUk3hhgE8@W6@#Fd#F3)uytkGTY5M6%+pxzg69c-lVkL!P^*yT*gb25pTe(& z{5H;NVxMoh<4Z*XW--%afJq{U?WXXdF$3>2S(7Z$*X{MUC0#s-tsVxJ%UEi95~P2V zJ6la=_FS$5&DYU0kuL3za6DA_rUJlzq z#0-WyZt#y`-xgVQ$k|eC-~L)kPH{wksYrh5^G50-{}4LXKiTJK^WKmbamVTo$BLE# z`@emwfIeotTvMjT!+twfMcZ@r%SN0+A4hqrI3dyy8#%MJn~>d;)pLa%vE_QR)my7i za?H9k`!?C*@Tc1Jw;?2O-xUtqfmE*ZFh=GF>_;W`B8%!SKK8d1?(bfr>=@ewENmjWrTeO;6M>fm8!(g-aY-kbo$Ano!tOq;3 zHfXzJ$!^$ryX~_^tahF@>f4$bF9&@KaRcIF%R}^7*i}CtJzYwYWs{n>}+Ol^SoJmUfkLg zDyvi>33QU($kkb%dC!*G*`9dYX=|;`KCOcKP7A(QGpUGt(?_*)+Zup??gW;Nyu@O#8L{NS?hqwD3zzN=94 zq6f3fzJEIWmq}gnyAPv|WnIl(4*bl(GRg424%6k#ojh6JRThICQzgVsL)@Q@Z_&G{ z@x(dh-DPE|@x=0}W|`GGf8NMat=aN;WyEVpq`#-|!zTyqV UHKHIZ=tNKU1u-9@E)CNE15p5OpCode == EFI_IFR_STRING_OP) { + StringOp = (EFI_IFR_STRING *) OpCode; + *Minimum = StringOp->MinSize; + *Maximum = StringOp->MaxSize; + } else if (OpCode->OpCode == EFI_IFR_PASSWORD_OP) { + PasswordOp = (EFI_IFR_PASSWORD *) OpCode; + *Minimum = PasswordOp->MinSize; + *Maximum = PasswordOp->MaxSize; + } else { + *Minimum = 0; + *Maximum = 0; + } +} /** Get string or password input from user. @@ -52,11 +82,11 @@ ReadString ( BOOLEAN CursorVisible; UINTN Minimum; UINTN Maximum; - FORM_BROWSER_STATEMENT *Question; + FORM_DISPLAY_ENGINE_STATEMENT *Question; BOOLEAN IsPassword; - DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; - DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn; + DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow; NullCharacter = CHAR_NULL; ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16); @@ -64,10 +94,9 @@ ReadString ( Space[1] = CHAR_NULL; Question = MenuOption->ThisTag; - Minimum = (UINTN) Question->Minimum; - Maximum = (UINTN) Question->Maximum; + GetFieldFromOp(Question->OpCode, &Minimum, &Maximum); - if (Question->Operand == EFI_IFR_PASSWORD_OP) { + if (Question->OpCode->OpCode == EFI_IFR_PASSWORD_OP) { IsPassword = TRUE; } else { IsPassword = FALSE; @@ -87,14 +116,14 @@ ReadString ( BufferedString = AllocateZeroPool (ScreenSize * 2); ASSERT (BufferedString); - Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1; - Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1; + Start = (DimensionsWidth - ScreenSize - 2) / 2 + gStatementDimensions.LeftColumn + 1; + Top = ((DimensionsHeight - 6) / 2) + gStatementDimensions.TopRow - 1; // // Display prompt for string // + // CreateDialog (NULL, "", Prompt, Space, "", NULL); CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter); - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); CursorVisible = gST->ConOut->Mode->CursorVisible; @@ -122,7 +151,7 @@ ReadString ( BufferedString[Count] = StringPtr[Index]; if (IsPassword) { - PrintChar (L'*'); + PrintCharAt ((UINTN)-1, (UINTN)-1, L'*'); } } @@ -181,7 +210,7 @@ ReadString ( // To save code space, we can then treat this as an error and return back to the menu. // do { - CreateDialog (4, TRUE, 0, NULL, &Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter); + CreateDialog (&Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter, NULL); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); FreePool (TempString); @@ -258,7 +287,7 @@ ReadString ( BufferedString[Count] = StringPtr[Index]; if (IsPassword) { - PrintChar (L'*'); + PrintCharAt ((UINTN)-1, (UINTN)-1, L'*'); } } @@ -279,12 +308,12 @@ ReadString ( like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01 Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28 - @param Question Pointer to current question. + @param QuestionValue Pointer to current question. @param Sequence The sequence of the field in the question. **/ VOID AdjustQuestionValue ( - IN FORM_BROWSER_STATEMENT *Question, + IN EFI_HII_VALUE *QuestionValue, IN UINT8 Sequence ) { @@ -293,12 +322,8 @@ AdjustQuestionValue ( UINT8 Maximum; UINT8 Minimum; - if (Question->Operand != EFI_IFR_DATE_OP) { - return; - } - - Month = Question->HiiValue.Value.date.Month; - Year = Question->HiiValue.Value.date.Year; + Month = QuestionValue->Value.date.Month; + Year = QuestionValue->Value.date.Year; Minimum = 1; switch (Month) { @@ -324,8 +349,8 @@ AdjustQuestionValue ( // Change the month area. // if (Sequence == 0) { - if (Question->HiiValue.Value.date.Day > Maximum) { - Question->HiiValue.Value.date.Day = Maximum; + if (QuestionValue->Value.date.Day > Maximum) { + QuestionValue->Value.date.Day = Maximum; } } @@ -333,16 +358,76 @@ AdjustQuestionValue ( // Change the Year area. // if (Sequence == 2) { - if (Question->HiiValue.Value.date.Day > Maximum) { - Question->HiiValue.Value.date.Day = Minimum; + if (QuestionValue->Value.date.Day > Maximum) { + QuestionValue->Value.date.Day = Minimum; } } } +/** + Get field info from numeric opcode. + + @param OpCode Pointer to the current input opcode. + @param Minimum The minimum size info for this opcode. + @param Maximum The maximum size info for this opcode. + @param Step The step size info for this opcode. + @param StorageWidth The storage width info for this opcode. + +**/ +VOID +GetValueFromNum ( + IN EFI_IFR_OP_HEADER *OpCode, + OUT UINT64 *Minimum, + OUT UINT64 *Maximum, + OUT UINT64 *Step, + OUT UINT16 *StorageWidth +) +{ + EFI_IFR_NUMERIC *NumericOp; + + NumericOp = (EFI_IFR_NUMERIC *) OpCode; + + switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + *Minimum = NumericOp->data.u8.MinValue; + *Maximum = NumericOp->data.u8.MaxValue; + *Step = NumericOp->data.u8.Step; + *StorageWidth = (UINT16) sizeof (UINT8); + break; + + case EFI_IFR_NUMERIC_SIZE_2: + *Minimum = NumericOp->data.u16.MinValue; + *Maximum = NumericOp->data.u16.MaxValue; + *Step = NumericOp->data.u16.Step; + *StorageWidth = (UINT16) sizeof (UINT16); + break; + + case EFI_IFR_NUMERIC_SIZE_4: + *Minimum = NumericOp->data.u32.MinValue; + *Maximum = NumericOp->data.u32.MaxValue; + *Step = NumericOp->data.u32.Step; + *StorageWidth = (UINT16) sizeof (UINT32); + break; + + case EFI_IFR_NUMERIC_SIZE_8: + *Minimum = NumericOp->data.u64.MinValue; + *Maximum = NumericOp->data.u64.MaxValue; + *Step = NumericOp->data.u64.Step; + *StorageWidth = (UINT16) sizeof (UINT64); + break; + + default: + break; + } + + if (*Maximum == 0) { + *Maximum = (UINT64) -1; + } +} + /** This routine reads a numeric value from the user input. - @param Selection Pointer to current selection. @param MenuOption Pointer to the current input menu. @retval EFI_SUCCESS If numerical input is read successfully @@ -351,7 +436,6 @@ AdjustQuestionValue ( **/ EFI_STATUS GetNumericInput ( - IN UI_MENU_SELECTION *Selection, IN UI_MENU_OPTION *MenuOption ) { @@ -375,9 +459,9 @@ GetNumericInput ( UINT8 Digital; EFI_INPUT_KEY Key; EFI_HII_VALUE *QuestionValue; - FORM_BROWSER_FORM *Form; - FORM_BROWSER_FORMSET *FormSet; - FORM_BROWSER_STATEMENT *Question; + FORM_DISPLAY_ENGINE_STATEMENT *Question; + EFI_IFR_NUMERIC *NumericOp; + UINT16 StorageWidth; Column = MenuOption->OptCol; Row = MenuOption->Row; @@ -385,14 +469,13 @@ GetNumericInput ( Count = 0; InputWidth = 0; Digital = 0; + StorageWidth = 0; + Minimum = 0; + Maximum = 0; + NumericOp = NULL; - FormSet = Selection->FormSet; - Form = Selection->Form; Question = MenuOption->ThisTag; - QuestionValue = &Question->HiiValue; - Step = Question->Step; - Minimum = Question->Minimum; - Maximum = Question->Maximum; + QuestionValue = &Question->CurrentValue; // // Only two case, user can enter to this function: Enter and +/- case. @@ -400,7 +483,7 @@ GetNumericInput ( // ManualInput = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE); - if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) { + if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) || (Question->OpCode->OpCode == EFI_IFR_TIME_OP)) { DateOrTime = TRUE; } else { DateOrTime = FALSE; @@ -411,7 +494,7 @@ GetNumericInput ( // EraseLen = 0; EditValue = 0; - if (Question->Operand == EFI_IFR_DATE_OP) { + if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) { Step = 1; Minimum = 1; @@ -457,7 +540,7 @@ GetNumericInput ( default: break; } - } else if (Question->Operand == EFI_IFR_TIME_OP) { + } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) { Step = 1; Minimum = 0; @@ -484,18 +567,15 @@ GetNumericInput ( break; } } else { - // - // Numeric - // - EraseLen = gOptionBlockWidth; + ASSERT (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP); + NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode; + GetValueFromNum(Question->OpCode, &Minimum, &Maximum, &Step, &StorageWidth); EditValue = QuestionValue->Value.u64; - if (Maximum == 0) { - Maximum = (UINT64) -1; - } + EraseLen = gOptionBlockWidth; } - if ((Question->Operand == EFI_IFR_NUMERIC_OP) && - ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) { + if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL) && + ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) { HexInput = TRUE; } else { HexInput = FALSE; @@ -505,11 +585,11 @@ GetNumericInput ( // Enter from "Enter" input, clear the old word showing. // if (ManualInput) { - if (Question->Operand == EFI_IFR_NUMERIC_OP) { + if (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) { if (HexInput) { - InputWidth = Question->StorageWidth * 2; + InputWidth = StorageWidth * 2; } else { - switch (Question->StorageWidth) { + switch (StorageWidth) { case 1: InputWidth = 3; break; @@ -538,11 +618,11 @@ GetNumericInput ( InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER; InputText[InputWidth + 2] = L'\0'; - PrintAt (Column, Row, InputText); + PrintStringAt (Column, Row, InputText); Column++; } - if (Question->Operand == EFI_IFR_DATE_OP) { + if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) { if (MenuOption->Sequence == 2) { InputWidth = 4; } else { @@ -563,13 +643,13 @@ GetNumericInput ( } InputText[InputWidth + 2] = L'\0'; - PrintAt (Column, Row, InputText); + PrintStringAt (Column, Row, InputText); if (MenuOption->Sequence == 0) { Column++; } } - if (Question->Operand == EFI_IFR_TIME_OP) { + if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) { InputWidth = 2; if (MenuOption->Sequence == 0) { @@ -586,7 +666,7 @@ GetNumericInput ( } InputText[InputWidth + 2] = L'\0'; - PrintAt (Column, Row, InputText); + PrintStringAt (Column, Row, InputText); if (MenuOption->Sequence == 0) { Column++; } @@ -654,7 +734,7 @@ TheKey2: } ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); - if (Question->Operand == EFI_IFR_DATE_OP) { + if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) { if (MenuOption->Sequence == 2) { // // Year @@ -674,7 +754,7 @@ TheKey2: ASSERT (EraseLen >= 1); FormattedNumber[EraseLen - 1] = DATE_SEPARATOR; } - } else if (Question->Operand == EFI_IFR_TIME_OP) { + } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) { UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue); if (MenuOption->Sequence == 0) { @@ -689,11 +769,11 @@ TheKey2: PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); } - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND); + gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ()); for (Loop = 0; Loop < EraseLen; Loop++) { - PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" "); + PrintStringAt (MenuOption->OptCol + Loop, MenuOption->Row, L" "); } - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor)); + gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ()); if (MenuOption->Sequence == 0) { PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER); @@ -703,7 +783,7 @@ TheKey2: PrintStringAt (Column, Row, FormattedNumber); if (!DateOrTime || MenuOption->Sequence == 2) { - PrintChar (RIGHT_NUMERIC_DELIMITER); + PrintCharAt ((UINTN)-1, (UINTN)-1, RIGHT_NUMERIC_DELIMITER); } } @@ -730,16 +810,18 @@ EnterCarriageReturn: // Validate input value with Minimum value. // if (EditValue < Minimum) { - UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE); + UpdateStatusBar (INPUT_ERROR, TRUE); break; } else { - UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE); + UpdateStatusBar (INPUT_ERROR, FALSE); } - + + CopyMem (&gUserInput->InputValue, &Question->CurrentValue, sizeof (EFI_HII_VALUE)); + QuestionValue = &gUserInput->InputValue; // // Store Edit value back to Question // - if (Question->Operand == EFI_IFR_DATE_OP) { + if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) { switch (MenuOption->Sequence) { case 0: QuestionValue->Value.date.Month = (UINT8) EditValue; @@ -756,7 +838,7 @@ EnterCarriageReturn: default: break; } - } else if (Question->Operand == EFI_IFR_TIME_OP) { + } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) { switch (MenuOption->Sequence) { case 0: QuestionValue->Value.time.Hour = (UINT8) EditValue; @@ -785,32 +867,12 @@ EnterCarriageReturn: // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01 // 2013.03.29 -> 2013.02.29 -> 2013.02.28 // - if (Question->Operand == EFI_IFR_DATE_OP && + if (Question->OpCode->OpCode == EFI_IFR_DATE_OP && (MenuOption->Sequence == 0 || MenuOption->Sequence == 2)) { - AdjustQuestionValue (Question, (UINT8)MenuOption->Sequence); - } - - // - // Check to see if the Value is something reasonable against consistency limitations. - // If not, let's kick the error specified. - // - Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); - if (EFI_ERROR (Status)) { - // - // Input value is not valid, restore Question Value - // - GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); - } else { - SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); - if (!DateOrTime || (Question->Storage != NULL)) { - // - // NV flag is unnecessary for RTC type of Date/Time - // - UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); - } + AdjustQuestionValue (QuestionValue, (UINT8)MenuOption->Sequence); } - return Status; + return ValidateQuestion (Question); break; case CHAR_BACKSPACE: @@ -822,10 +884,10 @@ EnterCarriageReturn: // Remove a character // EditValue = PreviousNumber[Count - 1]; - UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE); + UpdateStatusBar (INPUT_ERROR, FALSE); Count--; Column--; - PrintAt (Column, Row, L" "); + PrintStringAt (Column, Row, L" "); } break; @@ -839,12 +901,12 @@ EnterCarriageReturn: } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) { Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A); } else { - UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE); + UpdateStatusBar (INPUT_ERROR, TRUE); break; } } else { if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') { - UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE); + UpdateStatusBar (INPUT_ERROR, TRUE); break; } } @@ -873,32 +935,178 @@ EnterCarriageReturn: } if (EditValue > Maximum) { - UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE); + UpdateStatusBar (INPUT_ERROR, TRUE); ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0])); EditValue = PreviousNumber[Count]; break; } else { - UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE); + UpdateStatusBar (INPUT_ERROR, FALSE); } Count++; ASSERT (Count < (sizeof (PreviousNumber) / sizeof (PreviousNumber[0]))); PreviousNumber[Count] = EditValue; + gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ()); PrintCharAt (Column, Row, Key.UnicodeChar); Column++; } break; } } while (TRUE); +} + +/** + Adjust option order base on the question value. + + @param Question Pointer to current question. + @param PopUpMenuLines The line number of the pop up menu. + + @retval EFI_SUCCESS If Option input is processed successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +AdjustOptionOrder ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question, + OUT UINTN *PopUpMenuLines + ) +{ + UINTN Index; + EFI_IFR_ORDERED_LIST *OrderList; + UINT8 *ValueArray; + UINT8 ValueType; + LIST_ENTRY *Link; + DISPLAY_QUESTION_OPTION *OneOfOption; + EFI_HII_VALUE *HiiValueArray; + + Link = GetFirstNode (&Question->OptionListHead); + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + ValueArray = Question->CurrentValue.Buffer; + ValueType = OneOfOption->OptionOpCode->Type; + OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode; + + for (Index = 0; Index < OrderList->MaxContainers; Index++) { + if (GetArrayData (ValueArray, ValueType, Index) == 0) { + break; + } + } + + *PopUpMenuLines = Index; + + // + // Prepare HiiValue array + // + HiiValueArray = AllocateZeroPool (*PopUpMenuLines * sizeof (EFI_HII_VALUE)); + ASSERT (HiiValueArray != NULL); + + for (Index = 0; Index < *PopUpMenuLines; Index++) { + HiiValueArray[Index].Type = ValueType; + HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index); + } + + for (Index = 0; Index < *PopUpMenuLines; Index++) { + OneOfOption = ValueToOption (Question, &HiiValueArray[*PopUpMenuLines - Index - 1]); + if (OneOfOption == NULL) { + return EFI_NOT_FOUND; + } + + RemoveEntryList (&OneOfOption->Link); + + // + // Insert to head. + // + InsertHeadList (&Question->OptionListHead, &OneOfOption->Link); + } + + FreePool (HiiValueArray); + return EFI_SUCCESS; } +/** + Base on the type to compare the value. + + @param Value1 The first value need to compare. + @param Value2 The second value need to compare. + @param Type The value type for above two values. + + @retval TRUE The two value are same. + @retval FALSE The two value are different. + +**/ +BOOLEAN +IsValuesEqual ( + IN EFI_IFR_TYPE_VALUE *Value1, + IN EFI_IFR_TYPE_VALUE *Value2, + IN UINT8 Type + ) +{ + switch (Type) { + case EFI_IFR_TYPE_BOOLEAN: + case EFI_IFR_TYPE_NUM_SIZE_8: + return (BOOLEAN) (Value1->u8 == Value2->u8); + + case EFI_IFR_TYPE_NUM_SIZE_16: + return (BOOLEAN) (Value1->u16 == Value2->u16); + + case EFI_IFR_TYPE_NUM_SIZE_32: + return (BOOLEAN) (Value1->u32 == Value2->u32); + + case EFI_IFR_TYPE_NUM_SIZE_64: + return (BOOLEAN) (Value1->u64 == Value2->u64); + + default: + ASSERT (FALSE); + return FALSE; + } +} + +/** + Base on the type to set the value. + + @param Dest The dest value. + @param Source The source value. + @param Type The value type for above two values. + +**/ +VOID +SetValuesByType ( + OUT EFI_IFR_TYPE_VALUE *Dest, + IN EFI_IFR_TYPE_VALUE *Source, + IN UINT8 Type + ) +{ + switch (Type) { + case EFI_IFR_TYPE_BOOLEAN: + Dest->b = Source->b; + break; + + case EFI_IFR_TYPE_NUM_SIZE_8: + Dest->u8 = Source->u8; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Dest->u16 = Source->u16; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Dest->u32 = Source->u32; + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + Dest->u64 = Source->u64; + break; + + default: + ASSERT (FALSE); + break; + } +} /** Get selection for OneOf and OrderedList (Left/Right will be ignored). - @param Selection Pointer to current selection. @param MenuOption Pointer to the current input menu. @retval EFI_SUCCESS If Option input is processed successfully @@ -907,7 +1115,6 @@ EnterCarriageReturn: **/ EFI_STATUS GetSelectionInputPopUp ( - IN UI_MENU_SELECTION *Selection, IN UI_MENU_OPTION *MenuOption ) { @@ -934,16 +1141,16 @@ GetSelectionInputPopUp ( LIST_ENTRY *Link; BOOLEAN OrderedList; UINT8 *ValueArray; + UINT8 *ReturnValue; UINT8 ValueType; EFI_HII_VALUE HiiValue; - EFI_HII_VALUE *HiiValueArray; - UINTN OptionCount; - QUESTION_OPTION *OneOfOption; - QUESTION_OPTION *CurrentOption; - FORM_BROWSER_STATEMENT *Question; + DISPLAY_QUESTION_OPTION *OneOfOption; + DISPLAY_QUESTION_OPTION *CurrentOption; + FORM_DISPLAY_ENGINE_STATEMENT *Question; INTN Result; + EFI_IFR_ORDERED_LIST *OrderList; - DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn; ValueArray = NULL; ValueType = 0; @@ -954,81 +1161,33 @@ GetSelectionInputPopUp ( StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2); ASSERT (StringPtr); + ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE)); + Question = MenuOption->ThisTag; - if (Question->Operand == EFI_IFR_ORDERED_LIST_OP) { - ValueArray = Question->BufferValue; - ValueType = Question->ValueType; + if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) { + Link = GetFirstNode (&Question->OptionListHead); + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + ValueArray = Question->CurrentValue.Buffer; + ValueType = OneOfOption->OptionOpCode->Type; OrderedList = TRUE; + OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode; } else { OrderedList = FALSE; + OrderList = NULL; } // // Calculate Option count // + PopUpMenuLines = 0; if (OrderedList) { - for (Index = 0; Index < Question->MaxContainers; Index++) { - if (GetArrayData (ValueArray, ValueType, Index) == 0) { - break; - } - } - - OptionCount = Index; + AdjustOptionOrder(Question, &PopUpMenuLines); } else { - OptionCount = 0; Link = GetFirstNode (&Question->OptionListHead); while (!IsNull (&Question->OptionListHead, Link)) { - OneOfOption = QUESTION_OPTION_FROM_LINK (Link); - - OptionCount++; - - Link = GetNextNode (&Question->OptionListHead, Link); - } - } - - // - // Move valid Option to list head. - // - PopUpMenuLines = 0; - if (OrderedList) { - // - // Prepare HiiValue array - // - HiiValueArray = AllocateZeroPool (OptionCount * sizeof (EFI_HII_VALUE)); - ASSERT (HiiValueArray != NULL); - for (Index = 0; Index < OptionCount; Index++) { - HiiValueArray[Index].Type = ValueType; - HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index); - } - - for (Index = 0; Index < OptionCount; Index++) { - OneOfOption = ValueToOption (Question, &HiiValueArray[OptionCount - Index - 1]); - if (OneOfOption == NULL) { - return EFI_NOT_FOUND; - } - - RemoveEntryList (&OneOfOption->Link); - - // - // Insert to head. - // - InsertHeadList (&Question->OptionListHead, &OneOfOption->Link); - + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); PopUpMenuLines++; - } - - FreePool (HiiValueArray); - } else { - Link = GetFirstNode (&Question->OptionListHead); - for (Index = 0; Index < OptionCount; Index++) { - OneOfOption = QUESTION_OPTION_FROM_LINK (Link); Link = GetNextNode (&Question->OptionListHead, Link); - if ((OneOfOption->SuppressExpression != NULL) && - EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) { - continue; - } else { - PopUpMenuLines++; - } } } @@ -1039,27 +1198,23 @@ GetSelectionInputPopUp ( HighlightOptionIndex = 0; Link = GetFirstNode (&Question->OptionListHead); for (Index = 0; Index < PopUpMenuLines; Index++) { - OneOfOption = QUESTION_OPTION_FROM_LINK (Link); - Link = GetNextNode (&Question->OptionListHead, Link); - - if (!OrderedList && (OneOfOption->SuppressExpression != NULL) && - EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) { - Index--; - continue; - } + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); - StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle); + StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); if (StrLen (StringPtr) > PopUpWidth) { PopUpWidth = StrLen (StringPtr); } FreePool (StringPtr); - - if (!OrderedList && (CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { + HiiValue.Type = OneOfOption->OptionOpCode->Type; + SetValuesByType (&HiiValue.Value, &OneOfOption->OptionOpCode->Value, HiiValue.Type); + if (!OrderedList && (CompareHiiValue (&Question->CurrentValue, &HiiValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { // // Find current selected Option for OneOf // HighlightOptionIndex = Index; } + + Link = GetNextNode (&Question->OptionListHead, Link); } // @@ -1068,16 +1223,16 @@ GetSelectionInputPopUp ( PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT; SavedAttribute = gST->ConOut->Mode->Attribute; - gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) { PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH; } - Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn; + Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gStatementDimensions.LeftColumn; End = Start + PopUpWidth + POPUP_FRAME_WIDTH; - Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT; - Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - 1; + Top = gStatementDimensions.TopRow; + Bottom = gStatementDimensions.BottomRow - 1; MenuLinesInView = Bottom - Top - 1; if (MenuLinesInView >= PopUpMenuLines) { @@ -1097,7 +1252,7 @@ GetSelectionInputPopUp ( // // Clear that portion of the screen // - ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND); + ClearLines (Start, End, Top, Bottom, GetPopupColor ()); // // Draw "One of" pop-up menu @@ -1111,11 +1266,11 @@ GetSelectionInputPopUp ( Character = BOXDRAW_HORIZONTAL; } - PrintChar (Character); + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); } Character = BOXDRAW_DOWN_LEFT; - PrintChar (Character); + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); Character = BOXDRAW_VERTICAL; for (Index = Top + 1; Index < Bottom; Index++) { PrintCharAt (Start, Index, Character); @@ -1128,13 +1283,6 @@ GetSelectionInputPopUp ( Link = GetFirstNode (&Question->OptionListHead); for (Index = 0; Index < TopOptionIndex; Index++) { Link = GetNextNode (&Question->OptionListHead, Link); - - OneOfOption = QUESTION_OPTION_FROM_LINK (Link); - if (!OrderedList && (OneOfOption->SuppressExpression != NULL) && - EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) { - Index--; - continue; - } } // @@ -1142,16 +1290,10 @@ GetSelectionInputPopUp ( // Index2 = Top + 1; for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) { - OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); Link = GetNextNode (&Question->OptionListHead, Link); - if (!OrderedList && (OneOfOption->SuppressExpression != NULL) && - EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) { - Index--; - continue; - } - - StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle); + StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); ASSERT (StringPtr != NULL); // // If the string occupies multiple lines, truncate it to fit in one line, @@ -1172,11 +1314,11 @@ GetSelectionInputPopUp ( // CurrentOption = OneOfOption; - gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND); + gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ()); PrintStringAt (Start + 2, Index2, StringPtr); - gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); } else { - gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); PrintStringAt (Start + 2, Index2, StringPtr); } @@ -1193,11 +1335,11 @@ GetSelectionInputPopUp ( Character = BOXDRAW_HORIZONTAL; } - PrintChar (Character); + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); } Character = BOXDRAW_UP_LEFT; - PrintChar (Character); + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); // // Get User selection @@ -1313,7 +1455,7 @@ TheKey: if (OrderedList) { HiiValue.Type = ValueType; HiiValue.Value.u64 = 0; - for (Index = 0; Index < Question->MaxContainers; Index++) { + for (Index = 0; Index < OrderList->MaxContainers; Index++) { HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index); if (HiiValue.Value.u64 == 0) { break; @@ -1342,44 +1484,44 @@ TheKey: // return the current selection // if (OrderedList) { + ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen); + ASSERT (ReturnValue != NULL); Index = 0; Link = GetFirstNode (&Question->OptionListHead); while (!IsNull (&Question->OptionListHead, Link)) { - OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); Link = GetNextNode (&Question->OptionListHead, Link); - if ((OneOfOption->SuppressExpression != NULL) && - EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) { - continue; - } - - SetArrayData (ValueArray, ValueType, Index, OneOfOption->Value.Value.u64); + SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64); Index++; - if (Index > Question->MaxContainers) { + if (Index > OrderList->MaxContainers) { break; } } + if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) { + FreePool (ReturnValue); + return EFI_DEVICE_ERROR; + } else { + gUserInput->InputValue.Buffer = ReturnValue; + gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; + Status = EFI_SUCCESS; + } } else { ASSERT (CurrentOption != NULL); - CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE)); + gUserInput->InputValue.Type = CurrentOption->OptionOpCode->Type; + if (IsValuesEqual (&Question->CurrentValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type)) { + return EFI_DEVICE_ERROR; + } else { + SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type); + Status = EFI_SUCCESS; + } } gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); - Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); - if (EFI_ERROR (Status)) { - // - // Input value is not valid, restore Question Value - // - GetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer); - } else { - SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer); - UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); - } - - return Status; - + return ValidateQuestion (Question); + default: break; } @@ -1387,32 +1529,3 @@ TheKey: } -/** - Wait for a key to be pressed by user. - - @param Key The key which is pressed by user. - - @retval EFI_SUCCESS The function always completed successfully. - -**/ -EFI_STATUS -WaitForKeyStroke ( - OUT EFI_INPUT_KEY *Key - ) -{ - EFI_STATUS Status; - - while (TRUE) { - Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key); - if (!EFI_ERROR (Status)) { - break; - } - - if (Status != EFI_NOT_READY) { - continue; - } - - UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, 0); - } - return Status; -} diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c b/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c new file mode 100644 index 0000000000..aca043a8c2 --- /dev/null +++ b/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c @@ -0,0 +1,1286 @@ +/** @file +Implementation for handling the User Interface option processing. + + +Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "FormDisplay.h" + +/** + Concatenate a narrow string to another string. + + @param Destination The destination string. + @param Source The source string. The string to be concatenated. + to the end of Destination. + +**/ +VOID +NewStrCat ( + IN OUT CHAR16 *Destination, + IN CHAR16 *Source + ) +{ + UINTN Length; + + for (Length = 0; Destination[Length] != 0; Length++) + ; + + // + // We now have the length of the original string + // We can safely assume for now that we are concatenating a narrow value to this string. + // For instance, the string is "XYZ" and cat'ing ">" + // If this assumption changes, we need to make this routine a bit more complex + // + Destination[Length] = NARROW_CHAR; + Length++; + + StrCpy (Destination + Length, Source); +} + +/** + Compare two Hii value. + + @param Value1 Expression value to compare on left-hand. + @param Value2 Expression value to compare on right-hand. + @param Result Return value after compare. + retval 0 Two operators equal. + return Positive value if Value1 is greater than Value2. + retval Negative value if Value1 is less than Value2. + @param HiiHandle Only required for string compare. + + @retval other Could not perform compare on two values. + @retval EFI_SUCCESS Compare the value success. + +**/ +EFI_STATUS +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + OUT INTN *Result, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ) +{ + INT64 Temp64; + CHAR16 *Str1; + CHAR16 *Str2; + UINTN Len; + + if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) { + if (Value1->Type != EFI_IFR_TYPE_BUFFER && Value2->Type != EFI_IFR_TYPE_BUFFER) { + return EFI_UNSUPPORTED; + } + } + + if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) { + if (Value1->Type != Value2->Type) { + // + // Both Operator should be type of String + // + return EFI_UNSUPPORTED; + } + + if (Value1->Value.string == 0 || Value2->Value.string == 0) { + // + // StringId 0 is reserved + // + return EFI_INVALID_PARAMETER; + } + + if (Value1->Value.string == Value2->Value.string) { + *Result = 0; + return EFI_SUCCESS; + } + + Str1 = GetToken (Value1->Value.string, HiiHandle); + if (Str1 == NULL) { + // + // String not found + // + return EFI_NOT_FOUND; + } + + Str2 = GetToken (Value2->Value.string, HiiHandle); + if (Str2 == NULL) { + FreePool (Str1); + return EFI_NOT_FOUND; + } + + *Result = StrCmp (Str1, Str2); + + FreePool (Str1); + FreePool (Str2); + + return EFI_SUCCESS; + } + + if (Value1->Type == EFI_IFR_TYPE_BUFFER || Value2->Type == EFI_IFR_TYPE_BUFFER ) { + if (Value1->Type != Value2->Type) { + // + // Both Operator should be type of Buffer. + // + return EFI_UNSUPPORTED; + } + Len = Value1->BufferLen > Value2->BufferLen ? Value2->BufferLen : Value1->BufferLen; + *Result = CompareMem (Value1->Buffer, Value2->Buffer, Len); + if ((*Result == 0) && (Value1->BufferLen != Value2->BufferLen)) + { + // + // In this case, means base on samll number buffer, the data is same + // So which value has more data, which value is bigger. + // + *Result = Value1->BufferLen > Value2->BufferLen ? 1 : -1; + } + return EFI_SUCCESS; + } + + // + // Take remain types(integer, boolean, date/time) as integer + // + Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64); + if (Temp64 > 0) { + *Result = 1; + } else if (Temp64 < 0) { + *Result = -1; + } else { + *Result = 0; + } + + return EFI_SUCCESS; +} + +/** + Search an Option of a Question by its value. + + @param Question The Question + @param OptionValue Value for Option to be searched. + + @retval Pointer Pointer to the found Option. + @retval NULL Option not found. + +**/ +DISPLAY_QUESTION_OPTION * +ValueToOption ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue + ) +{ + LIST_ENTRY *Link; + DISPLAY_QUESTION_OPTION *Option; + INTN Result; + EFI_HII_VALUE Value; + + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + + ZeroMem (&Value, sizeof (EFI_HII_VALUE)); + Value.Type = Option->OptionOpCode->Type; + CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value)); + + if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { + return Option; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + + return NULL; +} + + +/** + Return data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + + @retval Value The data to be returned + +**/ +UINT64 +GetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index + ) +{ + UINT64 Data; + + ASSERT (Array != NULL); + + Data = 0; + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Data = (UINT64) *(((UINT8 *) Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Data = (UINT64) *(((UINT16 *) Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Data = (UINT64) *(((UINT32 *) Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + Data = (UINT64) *(((UINT64 *) Array) + Index); + break; + + default: + break; + } + + return Data; +} + + +/** + Set value of a data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + @param Value The value to be set. + +**/ +VOID +SetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index, + IN UINT64 Value + ) +{ + + ASSERT (Array != NULL); + + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + *(((UINT8 *) Array) + Index) = (UINT8) Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + *(((UINT16 *) Array) + Index) = (UINT16) Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + *(((UINT32 *) Array) + Index) = (UINT32) Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + *(((UINT64 *) Array) + Index) = (UINT64) Value; + break; + + default: + break; + } +} + +/** + Check whether this value already in the array, if yes, return the index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Value The value to be find. + @param Index The index in the array which has same value with Value. + + @retval TRUE Found the value in the array. + @retval FALSE Not found the value. + +**/ +BOOLEAN +FindArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINT64 Value, + OUT UINTN *Index OPTIONAL + ) +{ + UINTN Count; + UINT64 TmpValue; + UINT64 ValueComp; + + ASSERT (Array != NULL); + + Count = 0; + TmpValue = 0; + + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + ValueComp = (UINT8) Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + ValueComp = (UINT16) Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + ValueComp = (UINT32) Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + ValueComp = (UINT64) Value; + break; + + default: + ValueComp = 0; + break; + } + + while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) { + if (ValueComp == TmpValue) { + if (Index != NULL) { + *Index = Count; + } + return TRUE; + } + + Count ++; + } + + return FALSE; +} + +/** + Print Question Value according to it's storage width and display attributes. + + @param Question The Question to be printed. + @param FormattedNumber Buffer for output string. + @param BufferSize The FormattedNumber buffer size in bytes. + + @retval EFI_SUCCESS Print success. + @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number. + +**/ +EFI_STATUS +PrintFormattedNumber ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question, + IN OUT CHAR16 *FormattedNumber, + IN UINTN BufferSize + ) +{ + INT64 Value; + CHAR16 *Format; + EFI_HII_VALUE *QuestionValue; + EFI_IFR_NUMERIC *NumericOp; + + if (BufferSize < (21 * sizeof (CHAR16))) { + return EFI_BUFFER_TOO_SMALL; + } + + QuestionValue = &Question->CurrentValue; + NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode; + + Value = (INT64) QuestionValue->Value.u64; + switch (NumericOp->Flags & EFI_IFR_DISPLAY) { + case EFI_IFR_DISPLAY_INT_DEC: + switch (QuestionValue->Type) { + case EFI_IFR_NUMERIC_SIZE_1: + Value = (INT64) ((INT8) QuestionValue->Value.u8); + break; + + case EFI_IFR_NUMERIC_SIZE_2: + Value = (INT64) ((INT16) QuestionValue->Value.u16); + break; + + case EFI_IFR_NUMERIC_SIZE_4: + Value = (INT64) ((INT32) QuestionValue->Value.u32); + break; + + case EFI_IFR_NUMERIC_SIZE_8: + default: + break; + } + + if (Value < 0) { + Value = -Value; + Format = L"-%ld"; + } else { + Format = L"%ld"; + } + break; + + case EFI_IFR_DISPLAY_UINT_DEC: + Format = L"%ld"; + break; + + case EFI_IFR_DISPLAY_UINT_HEX: + Format = L"%lx"; + break; + + default: + return EFI_UNSUPPORTED; + break; + } + + UnicodeSPrint (FormattedNumber, BufferSize, Format, Value); + + return EFI_SUCCESS; +} + + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param Marker The variable argument list for the list of string to be printed. + +**/ +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN VA_LIST Marker + ) +{ + UINTN Index; + UINTN Count; + CHAR16 Character; + UINTN Start; + UINTN End; + UINTN Top; + UINTN Bottom; + CHAR16 *String; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + + DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn; + DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow; + + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); + + if ((RequestedWidth + 2) > DimensionsWidth) { + RequestedWidth = DimensionsWidth - 2; + } + + // + // Subtract the PopUp width from total Columns, allow for one space extra on + // each end plus a border. + // + Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1; + End = Start + RequestedWidth + 1; + + Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1; + Bottom = Top + NumberOfLines + 2; + + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (Start, Top, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + } + + Character = BOXDRAW_DOWN_LEFT; + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + Character = BOXDRAW_VERTICAL; + + Count = 0; + for (Index = Top; Index + 2 < Bottom; Index++, Count++) { + String = VA_ARG (Marker, CHAR16*); + + // + // This will clear the background of the line - we never know who might have been + // here before us. This differs from the next clear in that it used the non-reverse + // video for normal printing. + // + if (GetStringWidth (String) / 2 > 1) { + ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ()); + } + + // + // Passing in a space results in the assumption that this is where typing will occur + // + if (String[0] == L' ') { + ClearLines (Start + 1, End - 1, Index + 1, Index + 1, GetPopupInverseColor ()); + } + + // + // Passing in a NULL results in a blank space + // + if (String[0] == CHAR_NULL) { + ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ()); + } + + PrintStringAt ( + ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gStatementDimensions.LeftColumn + 1, + Index + 1, + String + ); + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); + PrintCharAt (Start, Index + 1, Character); + PrintCharAt (End - 1, Index + 1, Character); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (Start, Bottom - 1, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + } + + Character = BOXDRAW_UP_LEFT; + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); +} + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param ... A series of text strings that displayed in the pop-up. + +**/ +VOID +EFIAPI +CreateMultiStringPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + ... + ) +{ + VA_LIST Marker; + + VA_START (Marker, NumberOfLines); + + CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker); + + VA_END (Marker); +} + +/** + Process validate for one question. + + @param Question The question need to be validate. + + @retval EFI_SUCCESS Question Option process success. + @retval EFI_INVALID_PARAMETER Question Option process fail. + +**/ +EFI_STATUS +ValidateQuestion ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question + ) +{ + CHAR16 *ErrorInfo; + EFI_INPUT_KEY Key; + EFI_STATUS Status; + STATEMENT_ERROR_INFO RetInfo; + UINT32 RetVal; + + if (Question->ValidateQuestion == NULL) { + return EFI_SUCCESS; + } + + Status = EFI_SUCCESS; + RetVal = Question->ValidateQuestion(gFormData, Question, &gUserInput->InputValue, &RetInfo); + + switch (RetVal) { + case INCOSISTENT_IF_TRUE: + // + // Condition meet, show up error message + // + ASSERT (RetInfo.StringId != 0); + ErrorInfo = GetToken (RetInfo.StringId, gFormData->HiiHandle); + do { + CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + FreePool (ErrorInfo); + + Status = EFI_INVALID_PARAMETER; + break; + + default: + break; + } + + return Status; +} + +/** + Display error message for invalid password. + +**/ +VOID +PasswordInvalid ( + VOID + ) +{ + EFI_INPUT_KEY Key; + + // + // Invalid password, prompt error message + // + do { + CreateDialog (&Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); +} + +/** + Process password op code. + + @param MenuOption The menu for current password op code. + + @retval EFI_SUCCESS Question Option process success. + @retval Other Question Option process fail. + +**/ +EFI_STATUS +PasswordProcess ( + IN UI_MENU_OPTION *MenuOption + ) +{ + CHAR16 *StringPtr; + CHAR16 *TempString; + UINTN Maximum; + EFI_STATUS Status; + EFI_IFR_PASSWORD *PasswordInfo; + FORM_DISPLAY_ENGINE_STATEMENT *Question; + EFI_INPUT_KEY Key; + + Question = MenuOption->ThisTag; + PasswordInfo = (EFI_IFR_PASSWORD *) Question->OpCode; + Maximum = PasswordInfo->MaxSize; + Status = EFI_SUCCESS; + + StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); + ASSERT (StringPtr); + + // + // Use a NULL password to test whether old password is required + // + *StringPtr = 0; + Status = Question->PasswordCheck (gFormData, Question, StringPtr); + if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) { + // + // Password can't be set now. + // + FreePool (StringPtr); + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + // + // Old password exist, ask user for the old password + // + Status = ReadString (MenuOption, gPromptForPassword, StringPtr); + if (EFI_ERROR (Status)) { + FreePool (StringPtr); + return Status; + } + + // + // Check user input old password + // + Status = Question->PasswordCheck (gFormData, Question, StringPtr); + if (EFI_ERROR (Status)) { + if (Status == EFI_NOT_READY) { + // + // Typed in old password incorrect + // + PasswordInvalid (); + } else { + Status = EFI_SUCCESS; + } + + FreePool (StringPtr); + return Status; + } + } + + // + // Ask for new password + // + ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); + Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr); + if (EFI_ERROR (Status)) { + // + // Reset state machine for password + // + Question->PasswordCheck (gFormData, Question, NULL); + FreePool (StringPtr); + return Status; + } + + // + // Confirm new password + // + TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); + ASSERT (TempString); + Status = ReadString (MenuOption, gConfirmPassword, TempString); + if (EFI_ERROR (Status)) { + // + // Reset state machine for password + // + Question->PasswordCheck (gFormData, Question, NULL); + FreePool (StringPtr); + FreePool (TempString); + return Status; + } + + // + // Compare two typed-in new passwords + // + if (StrCmp (StringPtr, TempString) == 0) { + gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr); + gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; + gUserInput->InputValue.Type = Question->CurrentValue.Type; + gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL); + FreePool (StringPtr); + + Status = ValidateQuestion (Question); + + if (EFI_ERROR (Status)) { + // + // Reset state machine for password + // + Question->PasswordCheck (gFormData, Question, NULL); + } + + return Status; + } else { + // + // Reset state machine for password + // + Question->PasswordCheck (gFormData, Question, NULL); + + // + // Two password mismatch, prompt error message + // + do { + CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + Status = EFI_INVALID_PARAMETER; + } + + FreePool (TempString); + FreePool (StringPtr); + + return Status; +} + +/** + Process a Question's Option (whether selected or un-selected). + + @param MenuOption The MenuOption for this Question. + @param Selected TRUE: if Question is selected. + @param OptionString Pointer of the Option String to be displayed. + @param SkipErrorValue Whether need to return when value without option for it. + + @retval EFI_SUCCESS Question Option process success. + @retval Other Question Option process fail. + +**/ +EFI_STATUS +ProcessOptions ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected, + OUT CHAR16 **OptionString, + IN BOOLEAN SkipErrorValue + ) +{ + EFI_STATUS Status; + CHAR16 *StringPtr; + UINTN Index; + FORM_DISPLAY_ENGINE_STATEMENT *Question; + CHAR16 FormattedNumber[21]; + UINT16 Number; + CHAR16 Character[2]; + EFI_INPUT_KEY Key; + UINTN BufferSize; + DISPLAY_QUESTION_OPTION *OneOfOption; + LIST_ENTRY *Link; + EFI_HII_VALUE HiiValue; + EFI_HII_VALUE *QuestionValue; + DISPLAY_QUESTION_OPTION *Option; + UINTN Index2; + UINT8 *ValueArray; + UINT8 ValueType; + EFI_STRING_ID StringId; + EFI_IFR_ORDERED_LIST *OrderList; + BOOLEAN ValueInvalid; + + Status = EFI_SUCCESS; + + StringPtr = NULL; + Character[1] = L'\0'; + *OptionString = NULL; + StringId = 0; + ValueInvalid = FALSE; + + ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); + BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow; + + Question = MenuOption->ThisTag; + QuestionValue = &Question->CurrentValue; + + switch (Question->OpCode->OpCode) { + case EFI_IFR_ORDERED_LIST_OP: + + // + // Check whether there are Options of this OrderedList + // + if (IsListEmpty (&Question->OptionListHead)) { + break; + } + + OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode; + + Link = GetFirstNode (&Question->OptionListHead); + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + + ValueType = OneOfOption->OptionOpCode->Type; + ValueArray = Question->CurrentValue.Buffer; + + if (Selected) { + // + // Go ask for input + // + Status = GetSelectionInputPopUp (MenuOption); + } else { + // + // We now know how many strings we will have, so we can allocate the + // space required for the array or strings. + // + *OptionString = AllocateZeroPool (OrderList->MaxContainers * BufferSize); + ASSERT (*OptionString); + + HiiValue.Type = ValueType; + HiiValue.Value.u64 = 0; + for (Index = 0; Index < OrderList->MaxContainers; Index++) { + HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index); + if (HiiValue.Value.u64 == 0) { + // + // Values for the options in ordered lists should never be a 0 + // + break; + } + + OneOfOption = ValueToOption (Question, &HiiValue); + if (OneOfOption == NULL) { + if (SkipErrorValue) { + // + // Just try to get the option string, skip the value which not has option. + // + continue; + } + + // + // Show error message + // + do { + CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + // + // The initial value of the orderedlist is invalid, force to be valid value + // Exit current DisplayForm with new value. + // + gUserInput->SelectedStatement = Question; + + ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen); + ASSERT (ValueArray != NULL); + gUserInput->InputValue.Buffer = ValueArray; + gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; + gUserInput->InputValue.Type = Question->CurrentValue.Type; + + Link = GetFirstNode (&Question->OptionListHead); + Index2 = 0; + while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) { + Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Question->OptionListHead, Link); + SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64); + Index2++; + } + SetArrayData (ValueArray, ValueType, Index2, 0); + + FreePool (*OptionString); + *OptionString = NULL; + return EFI_NOT_FOUND; + } + + Character[0] = LEFT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); + ASSERT (StringPtr != NULL); + NewStrCat (OptionString[0], StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + Character[0] = CHAR_CARRIAGE_RETURN; + NewStrCat (OptionString[0], Character); + FreePool (StringPtr); + } + + // + // If valid option more than the max container, skip these options. + // + if (Index >= OrderList->MaxContainers) { + break; + } + + // + // Search the other options, try to find the one not in the container. + // + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Question->OptionListHead, Link); + + if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) { + continue; + } + + if (SkipErrorValue) { + // + // Not report error, just get the correct option string info. + // + Character[0] = LEFT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); + ASSERT (StringPtr != NULL); + NewStrCat (OptionString[0], StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + Character[0] = CHAR_CARRIAGE_RETURN; + NewStrCat (OptionString[0], Character); + FreePool (StringPtr); + + continue; + } + + if (!ValueInvalid) { + ValueInvalid = TRUE; + // + // Show error message + // + do { + CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + // + // The initial value of the orderedlist is invalid, force to be valid value + // Exit current DisplayForm with new value. + // + gUserInput->SelectedStatement = Question; + + ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer); + ASSERT (ValueArray != NULL); + gUserInput->InputValue.Buffer = ValueArray; + gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; + gUserInput->InputValue.Type = Question->CurrentValue.Type; + } + + SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64); + } + + if (ValueInvalid) { + FreePool (*OptionString); + *OptionString = NULL; + return EFI_NOT_FOUND; + } + } + break; + + case EFI_IFR_ONE_OF_OP: + // + // Check whether there are Options of this OneOf + // + if (IsListEmpty (&Question->OptionListHead)) { + break; + } + if (Selected) { + // + // Go ask for input + // + Status = GetSelectionInputPopUp (MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + OneOfOption = ValueToOption (Question, QuestionValue); + if (OneOfOption == NULL) { + if (SkipErrorValue) { + // + // Not report error, just get the correct option string info. + // + Link = GetFirstNode (&Question->OptionListHead); + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + } else { + // + // Show error message + // + do { + CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + // + // Force the Question value to be valid + // Exit current DisplayForm with new value. + // + Link = GetFirstNode (&Question->OptionListHead); + Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + + CopyMem (&gUserInput->InputValue.Value, &Option->OptionOpCode->Value, sizeof (EFI_IFR_TYPE_VALUE)); + gUserInput->InputValue.Type = Option->OptionOpCode->Type; + gUserInput->SelectedStatement = Question; + + FreePool (*OptionString); + *OptionString = NULL; + return EFI_NOT_FOUND; + } + } + + Character[0] = LEFT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); + ASSERT (StringPtr != NULL); + NewStrCat (OptionString[0], StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + + FreePool (StringPtr); + } + break; + + case EFI_IFR_CHECKBOX_OP: + if (Selected) { + // + // Since this is a BOOLEAN operation, flip it upon selection + // + gUserInput->InputValue.Type = QuestionValue->Type; + gUserInput->InputValue.Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE); + + // + // Perform inconsistent check + // + return ValidateQuestion (Question); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + *OptionString[0] = LEFT_CHECKBOX_DELIMITER; + + if (QuestionValue->Value.b) { + *(OptionString[0] + 1) = CHECK_ON; + } else { + *(OptionString[0] + 1) = CHECK_OFF; + } + *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER; + } + break; + + case EFI_IFR_NUMERIC_OP: + if (Selected) { + // + // Go ask for input + // + Status = GetNumericInput (MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + + // + // Formatted print + // + PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); + Number = (UINT16) GetStringWidth (FormattedNumber); + CopyMem (OptionString[0] + 1, FormattedNumber, Number); + + *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER; + } + break; + + case EFI_IFR_DATE_OP: + if (Selected) { + // + // This is similar to numerics + // + Status = GetNumericInput (MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + switch (MenuOption->Sequence) { + case 0: + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month); + *(OptionString[0] + 3) = DATE_SEPARATOR; + break; + + case 1: + SetUnicodeMem (OptionString[0], 4, L' '); + UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day); + *(OptionString[0] + 6) = DATE_SEPARATOR; + break; + + case 2: + SetUnicodeMem (OptionString[0], 7, L' '); + UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year); + *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER; + break; + } + } + break; + + case EFI_IFR_TIME_OP: + if (Selected) { + // + // This is similar to numerics + // + Status = GetNumericInput (MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + switch (MenuOption->Sequence) { + case 0: + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour); + *(OptionString[0] + 3) = TIME_SEPARATOR; + break; + + case 1: + SetUnicodeMem (OptionString[0], 4, L' '); + UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute); + *(OptionString[0] + 6) = TIME_SEPARATOR; + break; + + case 2: + SetUnicodeMem (OptionString[0], 7, L' '); + UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second); + *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER; + break; + } + } + break; + + case EFI_IFR_STRING_OP: + if (Selected) { + StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16)); + ASSERT (StringPtr); + CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen); + + Status = ReadString (MenuOption, gPromptForData, StringPtr); + if (EFI_ERROR (Status)) { + FreePool (StringPtr); + return Status; + } + + gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr); + gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; + gUserInput->InputValue.Type = Question->CurrentValue.Type; + gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL); + FreePool (StringPtr); + return ValidateQuestion (Question); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + if (((CHAR16 *) Question->CurrentValue.Buffer)[0] == 0x0000) { + *(OptionString[0]) = '_'; + } else { + if (Question->CurrentValue.BufferLen < BufferSize) { + BufferSize = Question->CurrentValue.BufferLen; + } + CopyMem (OptionString[0], (CHAR16 *) Question->CurrentValue.Buffer, BufferSize); + } + } + break; + + case EFI_IFR_PASSWORD_OP: + if (Selected) { + Status = PasswordProcess (MenuOption); + } + break; + + default: + break; + } + + return Status; +} + + +/** + Process the help string: Split StringPtr to several lines of strings stored in + FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth. + + @param StringPtr The entire help string. + @param FormattedString The oupput formatted string. + @param EachLineWidth The max string length of each line in the formatted string. + @param RowCount TRUE: if Question is selected. + +**/ +UINTN +ProcessHelpString ( + IN CHAR16 *StringPtr, + OUT CHAR16 **FormattedString, + OUT UINT16 *EachLineWidth, + IN UINTN RowCount + ) +{ + UINTN Index; + CHAR16 *OutputString; + UINTN TotalRowNum; + UINTN CheckedNum; + UINT16 GlyphWidth; + UINT16 LineWidth; + UINT16 MaxStringLen; + UINT16 StringLen; + + TotalRowNum = 0; + CheckedNum = 0; + GlyphWidth = 1; + Index = 0; + MaxStringLen = 0; + StringLen = 0; + + // + // Set default help string width. + // + LineWidth = (UINT16) (gHelpBlockWidth - 1); + + // + // Get row number of the String. + // + while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) { + if (StringLen > MaxStringLen) { + MaxStringLen = StringLen; + } + + TotalRowNum ++; + FreePool (OutputString); + } + *EachLineWidth = MaxStringLen; + + *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16)); + ASSERT (*FormattedString != NULL); + + // + // Generate formatted help string array. + // + GlyphWidth = 1; + Index = 0; + while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) { + CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16)); + CheckedNum ++; + FreePool (OutputString); + } + + return TotalRowNum; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c index cd29e29438..44dae1ba03 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c @@ -787,7 +787,7 @@ FORM_BROWSER_FORM * IdToForm ( IN FORM_BROWSER_FORMSET *FormSet, IN UINT16 FormId -) + ) { LIST_ENTRY *Link; FORM_BROWSER_FORM *Form; @@ -2105,7 +2105,7 @@ GetQuestionValueFromForm ( // FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); ASSERT (FormSet != NULL); - Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet, FALSE); + Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet); if (EFI_ERROR (Status)) { GetTheVal = FALSE; goto Done; @@ -2800,7 +2800,7 @@ EvaluateExpression ( for (Index = 0; Index < OpCode->ValueWidth; Index ++, TempBuffer --) { StrPtr += UnicodeValueToString (StrPtr, PREFIX_ZERO | RADIX_HEX, *TempBuffer, 2); } - Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer); + Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer, NULL); FreePool (NameValue); if (!EFI_ERROR (Status)) { Data1.Value.b = TRUE; diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h new file mode 100644 index 0000000000..5660a997b8 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h @@ -0,0 +1,265 @@ +/** @file +Private structure, MACRO and function definitions for User Interface related functionalities. + +Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _EXPRESSION_H_ +#define _EXPRESSION_H_ + +/** + Get the expression list count. + + @param Level Which type this expression belong to. Form, + statement or option? + + @retval >=0 The expression count + @retval -1 Input parameter error. + +**/ +INTN +GetConditionalExpressionCount ( + IN EXPRESS_LEVEL Level + ); + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetCurrentExpressionStack ( + VOID + ); + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetMapExpressionListStack ( + VOID + ); + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetScopeStack ( + VOID + ); + +/** + Push an Operand onto the Stack + + @param Operand Operand to push. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PushScope ( + IN UINT8 Operand + ); + +/** + Get the expression Buffer pointer. + + @param Level Which type this expression belong to. Form, + statement or option? + + @retval The start pointer of the expression buffer or NULL. + +**/ +FORM_EXPRESSION ** +GetConditionalExpressionList ( + IN EXPRESS_LEVEL Level + ); + +/** + Pop an Operand from the Stack + + @param Operand Operand to pop. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PopScope ( + OUT UINT8 *Operand + ); + +/** + Push the list of map expression onto the Stack + + @param Pointer Pointer to the list of map expression to be pushed. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. + +**/ +EFI_STATUS +PushMapExpressionList ( + IN VOID *Pointer + ); + +/** + Push current expression onto the Stack + + @param Pointer Pointer to current expression. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. + +**/ +EFI_STATUS +PushCurrentExpression ( + IN VOID *Pointer + ); + +/** + Zero extend integer/boolean/date/time to UINT64 for comparing. + + @param Value HII Value to be converted. + +**/ +VOID +ExtendValueToU64 ( + IN EFI_HII_VALUE *Value + ); + +/** + Push the expression options onto the Stack. + + @param Pointer Pointer to the current expression. + @param Level Which type this expression belong to. Form, + statement or option? + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. + +**/ +EFI_STATUS +PushConditionalExpression ( + IN FORM_EXPRESSION *Pointer, + IN EXPRESS_LEVEL Level + ); + +/** + Pop the expression options from the Stack + + @param Level Which type this expression belong to. Form, + statement or option? + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. + +**/ +EFI_STATUS +PopConditionalExpression ( + IN EXPRESS_LEVEL Level + ); + +/** + Pop the list of map expression from the Stack + + @param Pointer Pointer to the list of map expression to be pop. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. + +**/ +EFI_STATUS +PopMapExpressionList ( + OUT VOID **Pointer + ); + +/** + Pop current expression from the Stack + + @param Pointer Pointer to current expression to be pop. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. + +**/ +EFI_STATUS +PopCurrentExpression ( + OUT VOID **Pointer + ); + +/** + Evaluate the result of a HII expression. + + If Expression is NULL, then ASSERT. + + @param FormSet FormSet associated with this expression. + @param Form Form associated with this expression. + @param Expression Expression to be evaluated. + + @retval EFI_SUCCESS The expression evaluated successfuly + @retval EFI_NOT_FOUND The Question which referenced by a QuestionId + could not be found. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + @retval EFI_INVALID_PARAMETER Syntax error with the Expression + +**/ +EFI_STATUS +EvaluateExpression ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_EXPRESSION *Expression + ); +/** + Return the result of the expression list. Check the expression list and + return the highest priority express result. + Priority: DisableIf > SuppressIf > GrayOutIf > FALSE + + @param ExpList The input expression list. + @param Evaluate Whether need to evaluate the expression first. + @param FormSet FormSet associated with this expression. + @param Form Form associated with this expression. + + @retval EXPRESS_RESULT Return the higher priority express result. + DisableIf > SuppressIf > GrayOutIf > FALSE + +**/ +EXPRESS_RESULT +EvaluateExpressionList ( + IN FORM_EXPRESSION_LIST *ExpList, + IN BOOLEAN Evaluate, + IN FORM_BROWSER_FORMSET *FormSet, OPTIONAL + IN FORM_BROWSER_FORM *Form OPTIONAL + ); + +/** + Get Form given its FormId. + + @param FormSet The formset which contains this form. + @param FormId Id of this form. + + @retval Pointer The form. + @retval NULL Specified Form is not found in the formset. + +**/ +FORM_BROWSER_FORM * +IdToForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT16 FormId + ); + +#endif // _EXPRESSION_H diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c index 2464aebd09..1c3ab2bedc 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c @@ -16,7 +16,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. UINT16 mStatementIndex; UINT16 mExpressionOpCodeIndex; - +EFI_QUESTION_ID mUsedQuestionId; BOOLEAN mInScopeSubtitle; extern LIST_ENTRY gBrowserStorageList; /** @@ -42,9 +42,9 @@ CreateStatement ( if (Form == NULL) { // - // We are currently not in a Form Scope, so just skip this Statement + // Only guid op may out side the form level. // - return NULL; + ASSERT (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_GUID_OP); } Statement = &FormSet->StatementBuffer[mStatementIndex]; @@ -58,6 +58,7 @@ CreateStatement ( Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE; Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode; + Statement->OpCode = (EFI_IFR_OP_HEADER *) OpCodeData; StatementHdr = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); CopyMem (&Statement->Prompt, &StatementHdr->Prompt, sizeof (EFI_STRING_ID)); @@ -82,8 +83,11 @@ CreateStatement ( // // Insert this Statement into current Form // - InsertTailList (&Form->StatementListHead, &Statement->Link); - + if (Form == NULL) { + InsertTailList (&FormSet->StatementListOSF, &Statement->Link); + } else { + InsertTailList (&Form->StatementListHead, &Statement->Link); + } return Statement; } @@ -1133,6 +1137,7 @@ ParseOpCodes ( CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression); mStatementIndex = 0; + mUsedQuestionId = 1; FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT)); if (FormSet->StatementBuffer == NULL) { return EFI_OUT_OF_RESOURCES; @@ -1144,6 +1149,7 @@ ParseOpCodes ( return EFI_OUT_OF_RESOURCES; } + InitializeListHead (&FormSet->StatementListOSF); InitializeListHead (&FormSet->StorageListHead); InitializeListHead (&FormSet->DefaultStoreListHead); InitializeListHead (&FormSet->FormListHead); @@ -1502,7 +1508,6 @@ ParseOpCodes ( InitializeListHead (&CurrentForm->ConfigRequestHead); CurrentForm->FormType = STANDARD_MAP_FORM_TYPE; - CurrentForm->NvUpdateRequired = FALSE; CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *) OpCodeData)->FormId, sizeof (UINT16)); CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *) OpCodeData)->FormTitle, sizeof (EFI_STRING_ID)); @@ -1539,7 +1544,6 @@ ParseOpCodes ( CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM)); ASSERT (CurrentForm != NULL); CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE; - CurrentForm->NvUpdateRequired = FALSE; InitializeListHead (&CurrentForm->ExpressionListHead); InitializeListHead (&CurrentForm->StatementListHead); InitializeListHead (&CurrentForm->ConfigRequestHead); @@ -1653,7 +1657,7 @@ ParseOpCodes ( ASSERT (CurrentStatement != NULL); CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags; - + CurrentStatement->FakeQuestionId = mUsedQuestionId++; if (Scope != 0) { mInScopeSubtitle = TRUE; } @@ -1662,13 +1666,14 @@ ParseOpCodes ( case EFI_IFR_TEXT_OP: CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); ASSERT (CurrentStatement != NULL); - + CurrentStatement->FakeQuestionId = mUsedQuestionId++; CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *) OpCodeData)->TextTwo, sizeof (EFI_STRING_ID)); break; case EFI_IFR_RESET_BUTTON_OP: CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); ASSERT (CurrentStatement != NULL); + CurrentStatement->FakeQuestionId = mUsedQuestionId++; CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *) OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID)); break; @@ -1913,6 +1918,7 @@ ParseOpCodes ( CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION)); ASSERT (CurrentOption != NULL); CurrentOption->Signature = QUESTION_OPTION_SIGNATURE; + CurrentOption->OpCode = (EFI_IFR_ONE_OF_OPTION *) OpCodeData; CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags; CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Type; @@ -2270,45 +2276,8 @@ ParseOpCodes ( // // Vendor specific // - case EFI_IFR_GUID_OP: - if (CompareGuid (&gEfiIfrTianoGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { - // - // Tiano specific GUIDed opcodes - // - switch (((EFI_IFR_GUID_LABEL *) OpCodeData)->ExtendOpCode) { - case EFI_IFR_EXTEND_OP_LABEL: - // - // just ignore label - // - break; - - case EFI_IFR_EXTEND_OP_BANNER: - // - // By SubClass to get Banner Data from Front Page - // - if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) { - CopyMem ( - &gBannerData->Banner[((EFI_IFR_GUID_BANNER *) OpCodeData)->LineNumber][ - ((EFI_IFR_GUID_BANNER *) OpCodeData)->Alignment], - &((EFI_IFR_GUID_BANNER *) OpCodeData)->Title, - sizeof (EFI_STRING_ID) - ); - } - break; - - case EFI_IFR_EXTEND_OP_CLASS: - CopyMem (&FormSet->Class, &((EFI_IFR_GUID_CLASS *) OpCodeData)->Class, sizeof (UINT16)); - break; - - case EFI_IFR_EXTEND_OP_SUBCLASS: - CopyMem (&FormSet->SubClass, &((EFI_IFR_GUID_SUBCLASS *) OpCodeData)->SubClass, sizeof (UINT16)); - break; - - default: - break; - } - } - + case EFI_IFR_GUID_OP: + CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); break; // diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c index 4cd71e5d44..def18fd9f9 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c @@ -19,863 +19,1658 @@ UI_MENU_SELECTION *gCurrentSelection; EFI_HII_HANDLE mCurrentHiiHandle = NULL; EFI_GUID mCurrentFormSetGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; UINT16 mCurrentFormId = 0; +EFI_EVENT mValueChangedEvent = NULL; +LIST_ENTRY mRefreshEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRefreshEventList); +UINT32 gBrowserStatus = BROWSER_SUCCESS; +CHAR16 *gErrorInfo; +UINT16 mCurFakeQestId; +FORM_DISPLAY_ENGINE_FORM gDisplayFormData; + +/** + Evaluate all expressions in a Form. + + @param FormSet FormSet this Form belongs to. + @param Form The Form. + + @retval EFI_SUCCESS The expression evaluated successfuly + +**/ +EFI_STATUS +EvaluateFormExpressions ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + + Link = GetFirstNode (&Form->ExpressionListHead); + while (!IsNull (&Form->ExpressionListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + Link = GetNextNode (&Form->ExpressionListHead, Link); + + if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF || + Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF || + Expression->Type == EFI_HII_EXPRESSION_WRITE || + (Expression->Type == EFI_HII_EXPRESSION_READ && Form->FormType != STANDARD_MAP_FORM_TYPE)) { + // + // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form. + // + continue; + } + + Status = EvaluateExpression (FormSet, Form, Expression); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + +/** + Add empty function for event process function. + + @param Event The Event need to be process + @param Context The context of the event. + +**/ +VOID +EFIAPI +SetupBrowserEmptyFunction ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ +} + +/** + Base on the opcode buffer info to get the display statement. + + @param OpCode The input opcode buffer for this statement. + + @retval Statement The statement use this opcode buffer. + +**/ +FORM_DISPLAY_ENGINE_STATEMENT * +GetDisplayStatement ( + IN EFI_IFR_OP_HEADER *OpCode + ) +{ + FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement; + LIST_ENTRY *Link; + + Link = GetFirstNode (&gDisplayFormData.StatementListHead); + while (!IsNull (&gDisplayFormData.StatementListHead, Link)) { + DisplayStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link); + + if (DisplayStatement->OpCode == OpCode) { + return DisplayStatement; + } + Link = GetNextNode (&gDisplayFormData.StatementListHead, Link); + } + + return NULL; +} + +/** + Free the refresh event list. + +**/ +VOID +FreeRefreshEvent ( + VOID + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_REFRESH_EVENT_NODE *EventNode; + + while (!IsListEmpty (&mRefreshEventList)) { + Link = GetFirstNode (&mRefreshEventList); + EventNode = FORM_BROWSER_REFRESH_EVENT_FROM_LINK (Link); + RemoveEntryList (&EventNode->Link); + + gBS->CloseEvent (EventNode->RefreshEvent); + + FreePool (EventNode); + } +} + +/** + Check whether this statement value is changed. If yes, update the statement value and return TRUE; + else return FALSE. + + @param Statement The statement need to check. + +**/ +VOID +UpdateStatement ( + IN OUT FORM_BROWSER_STATEMENT *Statement + ) +{ + GetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver); + + // + // Reset FormPackage update flag + // + mHiiPackageListUpdated = FALSE; + + // + // Question value may be changed, need invoke its Callback() + // + ProcessCallBackFunction (gCurrentSelection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE); + + if (mHiiPackageListUpdated) { + // + // Package list is updated, force to reparse IFR binary of target Formset + // + mHiiPackageListUpdated = FALSE; + gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; + } +} + +/** + Refresh the question which has refresh guid event attribute. + + @param Event The event which has this function related. + @param Context The input context info related to this event or the status code return to the caller. +**/ +VOID +EFIAPI +RefreshEventNotify( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + FORM_BROWSER_STATEMENT *Statement; + + Statement = (FORM_BROWSER_STATEMENT *)Context; + UpdateStatement(Statement); + gBS->SignalEvent (mValueChangedEvent); +} + + +/** + Create refresh hook event for statement which has refresh event or interval. + + @param Statement The statement need to check. + +**/ +VOID +CreateRefreshEvent ( + IN FORM_BROWSER_STATEMENT *Statement + ) +{ + EFI_STATUS Status; + EFI_EVENT RefreshEvent; + FORM_BROWSER_REFRESH_EVENT_NODE *EventNode; + + // + // If question has refresh guid, create the notify function. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + RefreshEventNotify, + Statement, + &Statement->RefreshGuid, + &RefreshEvent); + ASSERT_EFI_ERROR (Status); + + EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE)); + ASSERT (EventNode != NULL); + EventNode->RefreshEvent = RefreshEvent; + InsertTailList(&mRefreshEventList, &EventNode->Link); +} + +/** + Perform value check for a question. + + @param Question The question need to do check. + @param ErrorInfo Return info about the error. + + @retval The check result. +**/ +UINT32 +InConsistentIfCheck ( + IN FORM_BROWSER_STATEMENT *Question, + OUT STATEMENT_ERROR_INFO *ErrorInfo + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + LIST_ENTRY *ListHead; + UINT32 RetVal; + + RetVal = STATEMENT_VALID; + ListHead = &Question->InconsistentListHead; + + Link = GetFirstNode (ListHead); + while (!IsNull (ListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + Link = GetNextNode (ListHead, Link); + + // + // Evaluate the expression + // + Status = EvaluateExpression (gCurrentSelection->FormSet, gCurrentSelection->Form, Expression); + if (EFI_ERROR (Status)) { + continue; + } + + if ((Expression->Result.Type == EFI_IFR_TYPE_BOOLEAN) && Expression->Result.Value.b) { + ErrorInfo->StringId = Expression->Error; + ErrorInfo->TimeOut = 0; + RetVal = INCOSISTENT_IF_TRUE; + break; + } + } + + return RetVal; +} + +/** + Perform value check for a question. + + @param Form Form where Statement is in. + @param Statement Value will check for it. + @param InputValue New value will be checked. + @param ErrorInfo Return the error info for this check. + + @retval TRUE Input Value is valid. + @retval FALSE Input Value is invalid. +**/ +UINT32 +EFIAPI +QuestionCheck ( + IN FORM_DISPLAY_ENGINE_FORM *Form, + IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, + IN EFI_HII_VALUE *InputValue, + OUT STATEMENT_ERROR_INFO *ErrorInfo + ) +{ + FORM_BROWSER_STATEMENT *Question; + EFI_HII_VALUE BackUpValue; + UINT8 *BackUpBuffer; + UINT32 RetVal; + + BackUpBuffer = NULL; + RetVal = STATEMENT_VALID; + + ASSERT (Form != NULL && Statement != NULL && InputValue != NULL && ErrorInfo != NULL); + + Question = GetBrowserStatement(Statement); + ASSERT (Question != NULL); + + // + // Back up the quesion value. + // + switch (Question->Operand) { + case EFI_IFR_ORDERED_LIST_OP: + BackUpBuffer = AllocateCopyPool (Question->StorageWidth, Question->BufferValue); + ASSERT (BackUpBuffer != NULL); + CopyMem (Question->BufferValue, InputValue->Buffer, Question->StorageWidth); + break; + + default: + CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)); + CopyMem (&Question->HiiValue, InputValue, sizeof (EFI_HII_VALUE)); + break; + } + + // + // Do the inconsistentif check. + // + if (!IsListEmpty (&Question->InconsistentListHead)) { + RetVal = InConsistentIfCheck(Question, ErrorInfo); + } + + // + // Restore the quesion value. + // + switch (Question->Operand) { + case EFI_IFR_ORDERED_LIST_OP: + CopyMem (Question->BufferValue, BackUpBuffer, Question->StorageWidth); + break; + + default: + CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE)); + break; + } + + return RetVal; +} + +/** + + Initialize the Display statement structure data. + + @param DisplayStatement Pointer to the display Statement data strucure. + @param Statement The statement need to check. + @param HostDisplayStatement Pointer to the display Statement data strucure which is an host statement. +**/ +VOID +InitializeDisplayStatement ( + IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement, + IN FORM_BROWSER_STATEMENT *Statement, + IN FORM_DISPLAY_ENGINE_STATEMENT *HostDisplayStatement + ) +{ + LIST_ENTRY *Link; + QUESTION_OPTION *Option; + DISPLAY_QUESTION_OPTION *DisplayOption; + + DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE; + DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1; + DisplayStatement->OpCode = Statement->OpCode; + InitializeListHead (&DisplayStatement->NestStatementList); + InitializeListHead (&DisplayStatement->OptionListHead); + + if ((EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut) || Statement->Locked) { + DisplayStatement->Attribute |= HII_DISPLAY_GRAYOUT; + } + if ((Statement->ValueExpression != NULL) || ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) { + DisplayStatement->Attribute |= HII_DISPLAY_READONLY; + } + + // + // Initilize the option list in statement. + // + Link = GetFirstNode (&Statement->OptionListHead); + while (!IsNull (&Statement->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Statement->OptionListHead, Link); + if ((Option->SuppressExpression != NULL) && + ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) { + continue; + } + + DisplayOption = AllocateZeroPool (sizeof (DISPLAY_QUESTION_OPTION)); + ASSERT (DisplayOption != NULL); + + DisplayOption->ImageId = Option->ImageId; + DisplayOption->Signature = DISPLAY_QUESTION_OPTION_SIGNATURE; + DisplayOption->OptionOpCode = Option->OpCode; + InsertTailList(&DisplayStatement->OptionListHead, &DisplayOption->Link); + } + + CopyMem (&DisplayStatement->CurrentValue, &Statement->HiiValue, sizeof (EFI_HII_VALUE)); + + // + // Some special op code need an extra buffer to save the data. + // Such as string, password, orderedlist... + // + if (Statement->BufferValue != NULL) { + // + // Ordered list opcode may not initilized, get default value here. + // + if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP && GetArrayData (Statement->BufferValue, Statement->ValueType, 0) == 0) { + GetQuestionDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, 0); + } + + DisplayStatement->CurrentValue.Buffer = AllocateCopyPool(Statement->StorageWidth,Statement->BufferValue); + DisplayStatement->CurrentValue.BufferLen = Statement->StorageWidth; + } + + DisplayStatement->SettingChangedFlag = Statement->ValueChanged; + + // + // Get the highlight statement for current form. + // + if (((gCurrentSelection->QuestionId != 0) && (Statement->QuestionId == gCurrentSelection->QuestionId)) || + ((mCurFakeQestId != 0) && (Statement->FakeQuestionId == mCurFakeQestId))) { + gDisplayFormData.HighLightedStatement = DisplayStatement; + } + + // + // Create the refresh event process function. + // + if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) { + CreateRefreshEvent (Statement); + } + + // + // For RTC type of date/time, set default refresh interval to be 1 second. + // + if ((Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) && Statement->Storage == NULL) { + Statement->RefreshInterval = 1; + } + + // + // Create the refresh guid hook event. + // If the statement in this form has refresh event or refresh interval, browser will create this event for display engine. + // + if ((!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) || (Statement->RefreshInterval != 0)) { + gDisplayFormData.FormRefreshEvent = mValueChangedEvent; + } + + // + // Save the password check function for later use. + // + if (Statement->Operand == EFI_IFR_PASSWORD_OP) { + DisplayStatement->PasswordCheck = PasswordCheck; + } + + // + // Save the validate check question for later use. + // + if (!IsListEmpty (&Statement->InconsistentListHead)) { + DisplayStatement->ValidateQuestion = QuestionCheck; + } + + // + // If this statement is nest in the subtitle, insert to the host statement. + // else insert to the form it belongs to. + // + if (Statement->InSubtitle) { + InsertTailList(&HostDisplayStatement->NestStatementList, &DisplayStatement->DisplayLink); + } else { + InsertTailList(&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink); + } +} + +/** + Process for the refresh interval statement. + + @param Event The Event need to be process + @param Context The context of the event. + +**/ +VOID +EFIAPI +RefreshIntervalProcess ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + FORM_BROWSER_STATEMENT *Statement; + LIST_ENTRY *Link; + + Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead); + while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link); + + if (Statement->RefreshInterval == 0) { + continue; + } + + UpdateStatement(Statement); + } + + gBS->SignalEvent (mValueChangedEvent); +} + +/** + + Make a copy of the global hotkey info. + +**/ +VOID +UpdateHotkeyList ( + VOID + ) +{ + BROWSER_HOT_KEY *HotKey; + BROWSER_HOT_KEY *CopyKey; + LIST_ENTRY *Link; + + Link = GetFirstNode (&gBrowserHotKeyList); + while (!IsNull (&gBrowserHotKeyList, Link)) { + HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); + + CopyKey = AllocateCopyPool(sizeof (BROWSER_HOT_KEY), HotKey); + CopyKey->KeyData = AllocateCopyPool(sizeof (EFI_INPUT_KEY), HotKey->KeyData); + CopyKey->HelpString = AllocateCopyPool(StrSize (HotKey->HelpString), HotKey->HelpString); + + InsertTailList(&gDisplayFormData.HotKeyListHead, &CopyKey->Link); + + Link = GetNextNode (&gBrowserHotKeyList, Link); + } +} /** - Clear retangle with specified text attribute. - @param LeftColumn Left column of retangle. - @param RightColumn Right column of retangle. - @param TopRow Start row of retangle. - @param BottomRow End row of retangle. - @param TextAttribute The character foreground and background. + Enum all statement in current form, find all the statement can be display and + add to the display form. **/ VOID -ClearLines ( - IN UINTN LeftColumn, - IN UINTN RightColumn, - IN UINTN TopRow, - IN UINTN BottomRow, - IN UINTN TextAttribute +AddStatementToDisplayForm ( + VOID + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Statement; + FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement; + FORM_DISPLAY_ENGINE_STATEMENT *HostDisplayStatement; + UINT8 MinRefreshInterval; + EFI_EVENT RefreshIntervalEvent; + FORM_BROWSER_REFRESH_EVENT_NODE *EventNode; + BOOLEAN FormEditable; + + HostDisplayStatement = NULL; + MinRefreshInterval = 0; + FormEditable = FALSE; + + // + // Process the statement outside the form, these statements are not recognized + // by browser core. + // + Link = GetFirstNode (&gCurrentSelection->FormSet->StatementListOSF); + while (!IsNull (&gCurrentSelection->FormSet->StatementListOSF, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&gCurrentSelection->FormSet->StatementListOSF, Link); + + DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT)); + ASSERT (DisplayStatement != NULL); + DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE; + DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1; + DisplayStatement->OpCode = Statement->OpCode; + + InitializeListHead (&DisplayStatement->NestStatementList); + InitializeListHead (&DisplayStatement->OptionListHead); + + InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink); + } + + // + // Process the statement in this form. + // + Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead); + while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link); + + // + // This statement can't be show, skip it. + // + if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) { + continue; + } + + DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT)); + ASSERT (DisplayStatement != NULL); + + // + // Initialize this statement and add it to the display form. + // + InitializeDisplayStatement(DisplayStatement, Statement, HostDisplayStatement); + + // + // Save the Host statement info. + // Host statement may has nest statement follow it. + // + if (!Statement->InSubtitle) { + HostDisplayStatement = DisplayStatement; + } + + if (Statement->Storage != NULL) { + FormEditable = TRUE; + } + + // + // Get the minimal refresh interval value for later use. + // + if ((Statement->RefreshInterval != 0) && + (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval)) { + MinRefreshInterval = Statement->RefreshInterval; + } + } + + // + // Create the periodic timer for refresh interval statement. + // + if (MinRefreshInterval != 0) { + Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshIntervalProcess, NULL, &RefreshIntervalEvent); + ASSERT_EFI_ERROR (Status); + Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, MinRefreshInterval * ONE_SECOND); + ASSERT_EFI_ERROR (Status); + + EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE)); + ASSERT (EventNode != NULL); + EventNode->RefreshEvent = RefreshIntervalEvent; + InsertTailList(&mRefreshEventList, &EventNode->Link); + } + + // + // Update hotkey list field. + // + if (gBrowserSettingScope == SystemLevel || FormEditable) { + UpdateHotkeyList(); + } +} + +/** + + Initialize the SettingChangedFlag variable in the display form. + +**/ +VOID +UpdateDataChangedFlag ( + VOID + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORMSET *LocalFormSet; + + gDisplayFormData.SettingChangedFlag = FALSE; + + if (IsNvUpdateRequiredForForm (gCurrentSelection->Form)) { + gDisplayFormData.SettingChangedFlag = TRUE; + return; + } + + // + // Base on the system level to check whether need to show the NV flag. + // + switch (gBrowserSettingScope) { + case SystemLevel: + // + // Check the maintain list to see whether there is any change. + // + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + if (IsNvUpdateRequiredForFormSet(LocalFormSet)) { + gDisplayFormData.SettingChangedFlag = TRUE; + return; + } + Link = GetNextNode (&gBrowserFormSetList, Link); + } + break; + + case FormSetLevel: + if (IsNvUpdateRequiredForFormSet(gCurrentSelection->FormSet)) { + gDisplayFormData.SettingChangedFlag = TRUE; + return; + } + break; + + default: + break; + } +} + +/** + + Initialize the Display form structure data. + +**/ +VOID +InitializeDisplayFormData ( + VOID + ) +{ + EFI_STATUS Status; + + gDisplayFormData.Signature = FORM_DISPLAY_ENGINE_FORM_SIGNATURE; + gDisplayFormData.Version = FORM_DISPLAY_ENGINE_VERSION_1; + gDisplayFormData.ImageId = 0; + gDisplayFormData.AnimationId = 0; + + InitializeListHead (&gDisplayFormData.StatementListHead); + InitializeListHead (&gDisplayFormData.StatementListOSF); + InitializeListHead (&gDisplayFormData.HotKeyListHead); + + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_CALLBACK, + SetupBrowserEmptyFunction, + NULL, + &mValueChangedEvent + ); + ASSERT_EFI_ERROR (Status); +} + +/** + + Free the kotkey info saved in form data. + +**/ +VOID +FreeHotkeyList ( + VOID + ) +{ + BROWSER_HOT_KEY *HotKey; + LIST_ENTRY *Link; + + while (!IsListEmpty (&gDisplayFormData.HotKeyListHead)) { + Link = GetFirstNode (&gDisplayFormData.HotKeyListHead); + HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); + + RemoveEntryList (&HotKey->Link); + + FreePool (HotKey->KeyData); + FreePool (HotKey->HelpString); + FreePool (HotKey); + } +} + +/** + + Update the Display form structure data. + +**/ +VOID +UpdateDisplayFormData ( + VOID + ) +{ + gDisplayFormData.FormTitle = gCurrentSelection->Form->FormTitle; + gDisplayFormData.FormId = gCurrentSelection->FormId; + gDisplayFormData.HiiHandle = gCurrentSelection->Handle; + CopyGuid (&gDisplayFormData.FormSetGuid, &gCurrentSelection->FormSetGuid); + + gDisplayFormData.Attribute = 0; + gDisplayFormData.Attribute |= gCurrentSelection->Form->ModalForm ? HII_DISPLAY_MODAL : 0; + gDisplayFormData.Attribute |= gCurrentSelection->Form->Locked ? HII_DISPLAY_LOCK : 0; + + gDisplayFormData.FormRefreshEvent = NULL; + gDisplayFormData.HighLightedStatement = NULL; + + gDisplayFormData.BrowserStatus = gBrowserStatus; + gDisplayFormData.ErrorString = gErrorInfo; + + gBrowserStatus = BROWSER_SUCCESS; + gErrorInfo = NULL; + + UpdateDataChangedFlag (); + + AddStatementToDisplayForm (); +} + +/** + + Free the Display Statement structure data. + + @param StatementList Point to the statement list which need to be free. + +**/ +VOID +FreeStatementData ( + LIST_ENTRY *StatementList + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *OptionLink; + FORM_DISPLAY_ENGINE_STATEMENT *Statement; + DISPLAY_QUESTION_OPTION *Option; + + // + // Free Statements/Questions + // + while (!IsListEmpty (StatementList)) { + Link = GetFirstNode (StatementList); + Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link); + + // + // Free Options List + // + while (!IsListEmpty (&Statement->OptionListHead)) { + OptionLink = GetFirstNode (&Statement->OptionListHead); + Option = DISPLAY_QUESTION_OPTION_FROM_LINK (OptionLink); + RemoveEntryList (&Option->Link); + FreePool (Option); + } + + // + // Free nest statement List + // + if (!IsListEmpty (&Statement->NestStatementList)) { + FreeStatementData(&Statement->NestStatementList); + } + + RemoveEntryList (&Statement->DisplayLink); + FreePool (Statement); + } +} + +/** + + Free the Display form structure data. + +**/ +VOID +FreeDisplayFormData ( + VOID + ) +{ + FreeStatementData (&gDisplayFormData.StatementListHead); + FreeStatementData (&gDisplayFormData.StatementListOSF); + + FreeRefreshEvent(); + + FreeHotkeyList(); +} + +/** + + Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info. + + @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT. + + @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info. + +**/ +FORM_BROWSER_STATEMENT * +GetBrowserStatement ( + IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement + ) +{ + FORM_BROWSER_STATEMENT *Statement; + LIST_ENTRY *Link; + + Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead); + while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Statement->OpCode == DisplayStatement->OpCode) { + return Statement; + } + + Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link); + } + + return NULL; +} + +/** + + Process the action request in user input. + + @param Action The user input action request info. + @param DefaultId The user input default Id info. + + @retval EFI_SUCESSS This function always return successfully for now. + +**/ +EFI_STATUS +ProcessAction ( + IN UINT32 Action, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + + // + // This is caused by use press ESC, and it should not combine with other action type. + // + if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) { + FindNextMenu (gCurrentSelection, FormLevel); + return EFI_SUCCESS; + } + + // + // Below is normal hotkey trigged action, these action maybe combine with each other. + // + if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) { + DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); + } + + if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) { + ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE); + } + + if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) { + Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); + if (EFI_ERROR (Status)) { + gBrowserStatus = BROWSER_SUBMIT_FAIL; + } + } + + if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) { + gResetRequired = TRUE; + } + + if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) { + // + // Form Exit without saving, Similar to ESC Key. + // FormSet Exit without saving, Exit SendForm. + // System Exit without saving, CallExitHandler and Exit SendForm. + // + DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); + if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) { + FindNextMenu (gCurrentSelection, gBrowserSettingScope); + } else if (gBrowserSettingScope == SystemLevel) { + if (ExitHandlerFunction != NULL) { + ExitHandlerFunction (); + } + gCurrentSelection->Action = UI_ACTION_EXIT; + } + } + + return EFI_SUCCESS; +} + + +/** + Find HII Handle in the HII database associated with given Device Path. + + If DevicePath is NULL, then ASSERT. + + @param DevicePath Device Path associated with the HII package list + handle. + + @retval Handle HII package list Handle associated with the Device + Path. + @retval NULL Hii Package list handle is not found. + +**/ +EFI_HII_HANDLE +EFIAPI +DevicePathToHiiHandle ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { - CHAR16 *Buffer; - UINTN Row; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; + UINTN BufferSize; + UINTN HandleCount; + UINTN Index; + EFI_HANDLE Handle; + EFI_HANDLE DriverHandle; + EFI_HII_HANDLE *HiiHandles; + EFI_HII_HANDLE HiiHandle; + + ASSERT (DevicePath != NULL); + + TmpDevicePath = DevicePath; + // + // Locate Device Path Protocol handle buffer + // + Status = gBS->LocateDevicePath ( + &gEfiDevicePathProtocolGuid, + &TmpDevicePath, + &DriverHandle + ); + if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) { + return NULL; + } // - // For now, allocate an arbitrarily long buffer + // Retrieve all HII Handles from HII database // - Buffer = AllocateZeroPool (0x10000); - ASSERT (Buffer != NULL); + BufferSize = 0x1000; + HiiHandles = AllocatePool (BufferSize); + ASSERT (HiiHandles != NULL); + Status = mHiiDatabase->ListPackageLists ( + mHiiDatabase, + EFI_HII_PACKAGE_TYPE_ALL, + NULL, + &BufferSize, + HiiHandles + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + FreePool (HiiHandles); + HiiHandles = AllocatePool (BufferSize); + ASSERT (HiiHandles != NULL); + + Status = mHiiDatabase->ListPackageLists ( + mHiiDatabase, + EFI_HII_PACKAGE_TYPE_ALL, + NULL, + &BufferSize, + HiiHandles + ); + } + + if (EFI_ERROR (Status)) { + FreePool (HiiHandles); + return NULL; + } // - // Set foreground and background as defined + // Search Hii Handle by Driver Handle // - gST->ConOut->SetAttribute (gST->ConOut, TextAttribute); + HiiHandle = NULL; + HandleCount = BufferSize / sizeof (EFI_HII_HANDLE); + for (Index = 0; Index < HandleCount; Index++) { + Status = mHiiDatabase->GetPackageListHandle ( + mHiiDatabase, + HiiHandles[Index], + &Handle + ); + if (!EFI_ERROR (Status) && (Handle == DriverHandle)) { + HiiHandle = HiiHandles[Index]; + break; + } + } + + FreePool (HiiHandles); + return HiiHandle; +} + +/** + Find HII Handle in the HII database associated with given form set guid. + + If FormSetGuid is NULL, then ASSERT. + + @param ComparingGuid FormSet Guid associated with the HII package list + handle. + + @retval Handle HII package list Handle associated with the Device + Path. + @retval NULL Hii Package list handle is not found. +**/ +EFI_HII_HANDLE +FormSetGuidToHiiHandle ( + EFI_GUID *ComparingGuid + ) +{ + EFI_HII_HANDLE *HiiHandles; + UINTN Index; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINTN BufferSize; + UINT32 Offset; + UINT32 Offset2; + UINT32 PackageListLength; + EFI_HII_PACKAGE_HEADER PackageHeader; + UINT8 *Package; + UINT8 *OpCodeData; + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + + ASSERT (ComparingGuid != NULL); + + HiiHandle = NULL; // - // Much faster to buffer the long string instead of print it a character at a time + // Get all the Hii handles // - SetUnicodeMem (Buffer, RightColumn - LeftColumn, L' '); + HiiHandles = HiiGetHiiHandles (NULL); + ASSERT (HiiHandles != NULL); // - // Clear the desired area with the appropriate foreground/background + // Search for formset of each class type // - for (Row = TopRow; Row <= BottomRow; Row++) { - PrintStringAt (LeftColumn, Row, Buffer); + for (Index = 0; HiiHandles[Index] != NULL; Index++) { + BufferSize = 0; + HiiPackageList = NULL; + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList); + } + if (EFI_ERROR (Status) || HiiPackageList == NULL) { + return NULL; + } + + // + // Get Form package from this HII package List + // + Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + Offset2 = 0; + CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); + + while (Offset < PackageListLength) { + Package = ((UINT8 *) HiiPackageList) + Offset; + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + + if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) { + // + // Search FormSet in this Form Package + // + Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); + while (Offset2 < PackageHeader.Length) { + OpCodeData = Package + Offset2; + + if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { + // + // Try to compare against formset GUID + // + if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { + HiiHandle = HiiHandles[Index]; + break; + } + } + + Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; + } + } + if (HiiHandle != NULL) { + break; + } + Offset += PackageHeader.Length; + } + + FreePool (HiiPackageList); + if (HiiHandle != NULL) { + break; + } } - gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow); + FreePool (HiiHandles); - FreePool (Buffer); - return ; + return HiiHandle; } /** - Concatenate a narrow string to another string. + check how to process the changed data in current form or form set. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. - @param Destination The destination string. - @param Source The source string. The string to be concatenated. - to the end of Destination. + @param Scope Data save or discard scope, form or formset. + @retval TRUE Success process the changed data, will return to the parent form. + @retval FALSE Reject to process the changed data, will stay at current form. **/ -VOID -NewStrCat ( - IN OUT CHAR16 *Destination, - IN CHAR16 *Source +BOOLEAN +ProcessChangedData ( + IN OUT UI_MENU_SELECTION *Selection, + IN BROWSER_SETTING_SCOPE Scope ) { - UINTN Length; + BOOLEAN RetValue; - for (Length = 0; Destination[Length] != 0; Length++) - ; + RetValue = TRUE; + switch (mFormDisplay->ConfirmDataChange()) { + case BROWSER_ACTION_DISCARD: + DiscardForm (Selection->FormSet, Selection->Form, Scope); + break; + + case BROWSER_ACTION_SUBMIT: + SubmitForm (Selection->FormSet, Selection->Form, Scope); + break; - // - // We now have the length of the original string - // We can safely assume for now that we are concatenating a narrow value to this string. - // For instance, the string is "XYZ" and cat'ing ">" - // If this assumption changes, we need to make this routine a bit more complex - // - Destination[Length] = NARROW_CHAR; - Length++; + case BROWSER_ACTION_NONE: + RetValue = FALSE; + break; - StrCpy (Destination + Length, Source); + default: + // + // if Invalid value return, process same as BROWSER_ACTION_NONE. + // + RetValue = FALSE; + break; + } + + return RetValue; } /** - Count the storage space of a Unicode string. - - This function handles the Unicode string with NARROW_CHAR - and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR - does not count in the resultant output. If a WIDE_CHAR is - hit, then 2 Unicode character will consume an output storage - space with size of CHAR16 till a NARROW_CHAR is hit. - - If String is NULL, then ASSERT (). - - @param String The input string to be counted. + Find parent formset menu(the first menu which has different formset) for current menu. + If not find, just return to the first menu. - @return Storage space for the input string. + @param Selection The selection info. **/ -UINTN -GetStringWidth ( - IN CHAR16 *String +VOID +FindParentFormSet ( + IN OUT UI_MENU_SELECTION *Selection ) { - UINTN Index; - UINTN Count; - UINTN IncrementValue; - - ASSERT (String != NULL); - if (String == NULL) { - return 0; - } - - Index = 0; - Count = 0; - IncrementValue = 1; - - do { - // - // Advance to the null-terminator or to the first width directive - // - for (; - (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0); - Index++, Count = Count + IncrementValue - ) - ; + FORM_ENTRY_INFO *CurrentMenu; + FORM_ENTRY_INFO *ParentMenu; - // - // We hit the null-terminator, we now have a count - // - if (String[Index] == 0) { - break; - } - // - // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed - // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2) - // - if (String[Index] == NARROW_CHAR) { - // - // Skip to the next character - // - Index++; - IncrementValue = 1; - } else { - // - // Skip to the next character - // - Index++; - IncrementValue = 2; - } - } while (String[Index] != 0); + CurrentMenu = Selection->CurrentMenu; + ParentMenu = UiFindParentMenu(CurrentMenu); // - // Increment by one to include the null-terminator in the size + // Find a menu which has different formset guid with current. // - Count++; + while (ParentMenu != NULL && CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) { + CurrentMenu = ParentMenu; + ParentMenu = UiFindParentMenu(CurrentMenu); + } + + if (ParentMenu != NULL) { + CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID)); + Selection->Handle = ParentMenu->HiiHandle; + Selection->FormId = ParentMenu->FormId; + Selection->QuestionId = ParentMenu->QuestionId; + } else { + Selection->FormId = CurrentMenu->FormId; + Selection->QuestionId = CurrentMenu->QuestionId; + } - return Count * sizeof (CHAR16); + Selection->Statement = NULL; } /** - This function displays the page frame. + Process the goto op code, update the info in the selection structure. - @param Selection Selection contains the information about - the Selection, form and formset to be displayed. - Selection action may be updated in retrieve callback. + @param Statement The statement belong to goto op code. + @param Selection The selection info. + + @retval EFI_SUCCESS The menu process successfully. + @return Other value if the process failed. **/ -VOID -DisplayPageFrame ( - IN UI_MENU_SELECTION *Selection +EFI_STATUS +ProcessGotoOpCode ( + IN OUT FORM_BROWSER_STATEMENT *Statement, + IN OUT UI_MENU_SELECTION *Selection ) { - UINTN Index; - UINT8 Line; - UINT8 Alignment; - CHAR16 Character; - CHAR16 *Buffer; - CHAR16 *StrFrontPageBanner; - UINTN Row; - EFI_SCREEN_DESCRIPTOR LocalScreen; - UINT8 RowIdx; - UINT8 ColumnIdx; - - ZeroMem (&LocalScreen, sizeof (EFI_SCREEN_DESCRIPTOR)); - gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &LocalScreen.RightColumn, &LocalScreen.BottomRow); - ClearLines (0, LocalScreen.RightColumn, 0, LocalScreen.BottomRow, KEYHELP_BACKGROUND); - - if (Selection->Form->ModalForm) { - return; - } - - CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + CHAR16 *StringPtr; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + FORM_BROWSER_FORM *RefForm; + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + + Status = EFI_SUCCESS; + StringPtr = NULL; + HiiHandle = NULL; // - // For now, allocate an arbitrarily long buffer + // Prepare the device path check, get the device path info first. // - Buffer = AllocateZeroPool (0x10000); - ASSERT (Buffer != NULL); - - Character = BOXDRAW_HORIZONTAL; - - for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) { - Buffer[Index] = Character; + if (Statement->HiiValue.Value.ref.DevicePath != 0) { + StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle); } - if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) { - // - // ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND); - // - ClearLines ( - LocalScreen.LeftColumn, - LocalScreen.RightColumn, - LocalScreen.TopRow, - FRONT_PAGE_HEADER_HEIGHT - 1 + LocalScreen.TopRow, - BANNER_TEXT | BANNER_BACKGROUND - ); + // + // Check whether the device path string is a valid string. + // + if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL) { + if (Selection->Form->ModalForm) { + return Status; + } + // - // for (Line = 0; Line < BANNER_HEIGHT; Line++) { + // Goto another Hii Package list // - for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) { + if (mPathFromText != NULL) { + DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr); + if (DevicePath != NULL) { + HiiHandle = DevicePathToHiiHandle (DevicePath); + FreePool (DevicePath); + } + FreePool (StringPtr); + } else { // - // for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) { + // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol. // - for (Alignment = (UINT8) LocalScreen.LeftColumn; - Alignment < BANNER_COLUMNS + (UINT8) LocalScreen.LeftColumn; - Alignment++ - ) { - RowIdx = (UINT8) (Line - (UINT8) LocalScreen.TopRow); - ColumnIdx = (UINT8) (Alignment - (UINT8) LocalScreen.LeftColumn); - - ASSERT (RowIdx < BANNER_HEIGHT); - ASSERT (ColumnIdx < BANNER_COLUMNS); - - if (gBannerData->Banner[RowIdx][ColumnIdx] != 0x0000) { - StrFrontPageBanner = GetToken ( - gBannerData->Banner[RowIdx][ColumnIdx], - gFrontPageHandle - ); - } else { - continue; - } - - switch (Alignment - LocalScreen.LeftColumn) { - case 0: - // - // Handle left column - // - PrintStringAt (LocalScreen.LeftColumn + BANNER_LEFT_COLUMN_INDENT, Line, StrFrontPageBanner); - break; - - case 1: - // - // Handle center column - // - PrintStringAt ( - LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, - Line, - StrFrontPageBanner - ); - break; + gBrowserStatus = BROWSER_PROTOCOL_NOT_FOUND; + FreePool (StringPtr); + return Status; + } - case 2: - // - // Handle right column - // - PrintStringAt ( - LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3, - Line, - StrFrontPageBanner - ); - break; + if (HiiHandle != Selection->Handle) { + // + // Goto another Formset, check for uncommitted data + // + if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) && + IsNvUpdateRequiredForFormSet(Selection->FormSet)) { + if (!ProcessChangedData(Selection, FormSetLevel)) { + return EFI_SUCCESS; } - - FreePool (StrFrontPageBanner); } } - } - ClearLines ( - LocalScreen.LeftColumn, - LocalScreen.RightColumn, - LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, - LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, - KEYHELP_TEXT | KEYHELP_BACKGROUND - ); - - if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) { - ClearLines ( - LocalScreen.LeftColumn, - LocalScreen.RightColumn, - LocalScreen.TopRow, - LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, - TITLE_TEXT | TITLE_BACKGROUND - ); - // - // Print Top border line - // +------------------------------------------------------------------------------+ - // ? ? - // +------------------------------------------------------------------------------+ - // - Character = BOXDRAW_DOWN_RIGHT; - - PrintChar (Character); - PrintString (Buffer); - - Character = BOXDRAW_DOWN_LEFT; - PrintChar (Character); - - Character = BOXDRAW_VERTICAL; - for (Row = LocalScreen.TopRow + 1; Row <= LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) { - PrintCharAt (LocalScreen.LeftColumn, Row, Character); - PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); + Selection->Action = UI_ACTION_REFRESH_FORMSET; + Selection->Handle = HiiHandle; + if (Selection->Handle == NULL) { + // + // If target Hii Handle not found, exit current formset. + // + FindParentFormSet(Selection); + return EFI_SUCCESS; } - Character = BOXDRAW_UP_RIGHT; - PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character); - PrintString (Buffer); - - Character = BOXDRAW_UP_LEFT; - PrintChar (Character); - - if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) { + CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID)); + Selection->FormId = Statement->HiiValue.Value.ref.FormId; + Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; + } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) { + if (Selection->Form->ModalForm) { + return Status; + } + if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) { // - // Print Bottom border line - // +------------------------------------------------------------------------------+ - // ? ? - // +------------------------------------------------------------------------------+ + // Goto another Formset, check for uncommitted data // - Character = BOXDRAW_DOWN_RIGHT; - PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, Character); - - PrintString (Buffer); - - Character = BOXDRAW_DOWN_LEFT; - PrintChar (Character); - Character = BOXDRAW_VERTICAL; - for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1; - Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2; - Row++ - ) { - PrintCharAt (LocalScreen.LeftColumn, Row, Character); - PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); + if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) && + IsNvUpdateRequiredForFormSet(Selection->FormSet)) { + if (!ProcessChangedData(Selection, FormSetLevel)) { + return EFI_SUCCESS; + } } + } - Character = BOXDRAW_UP_RIGHT; - PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character); + Selection->Action = UI_ACTION_REFRESH_FORMSET; + Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid); + if (Selection->Handle == NULL) { + // + // If target Hii Handle not found, exit current formset. + // + FindParentFormSet(Selection); + return EFI_SUCCESS; + } - PrintString (Buffer); + CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID)); + Selection->FormId = Statement->HiiValue.Value.ref.FormId; + Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; + } else if (Statement->HiiValue.Value.ref.FormId != 0) { + // + // Goto another Form, check for uncommitted data + // + if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) { + if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) { + if (!ProcessChangedData (Selection, FormLevel)) { + return EFI_SUCCESS; + } + } + } - Character = BOXDRAW_UP_LEFT; - PrintChar (Character); + RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId); + if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) { + if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) { + // + // Form is suppressed. + // + gBrowserStatus = BROWSER_FORM_SUPPRESS; + return EFI_SUCCESS; + } } - } - FreePool (Buffer); + Selection->FormId = Statement->HiiValue.Value.ref.FormId; + Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; + } else if (Statement->HiiValue.Value.ref.QuestionId != 0) { + Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; + } + return Status; } /** - Evaluate all expressions in a Form. + Process Question Config. - @param FormSet FormSet this Form belongs to. - @param Form The Form. + @param Selection The UI menu selection. + @param Question The Question to be peocessed. - @retval EFI_SUCCESS The expression evaluated successfuly + @retval EFI_SUCCESS Question Config process success. + @retval Other Question Config process fail. **/ EFI_STATUS -EvaluateFormExpressions ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form +ProcessQuestionConfig ( + IN UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_STATEMENT *Question ) { - EFI_STATUS Status; - LIST_ENTRY *Link; - FORM_EXPRESSION *Expression; + EFI_STATUS Status; + CHAR16 *ConfigResp; + CHAR16 *Progress; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; - Link = GetFirstNode (&Form->ExpressionListHead); - while (!IsNull (&Form->ExpressionListHead, Link)) { - Expression = FORM_EXPRESSION_FROM_LINK (Link); - Link = GetNextNode (&Form->ExpressionListHead, Link); + if (Question->QuestionConfig == 0) { + return EFI_SUCCESS; + } - if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF || - Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF || - Expression->Type == EFI_HII_EXPRESSION_WRITE || - (Expression->Type == EFI_HII_EXPRESSION_READ && Form->FormType != STANDARD_MAP_FORM_TYPE)) { - // - // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form. - // - continue; - } + // + // Get + // + ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle); + if (ConfigResp == NULL) { + return EFI_NOT_FOUND; + } - Status = EvaluateExpression (FormSet, Form, Expression); - if (EFI_ERROR (Status)) { - return Status; - } + // + // Send config to Configuration Driver + // + ConfigAccess = Selection->FormSet->ConfigAccess; + if (ConfigAccess == NULL) { + return EFI_UNSUPPORTED; } + Status = ConfigAccess->RouteConfig ( + ConfigAccess, + ConfigResp, + &Progress + ); - return EFI_SUCCESS; + return Status; } -/* -+------------------------------------------------------------------------------+ -? Setup Page ? -+------------------------------------------------------------------------------+ - - - - - - - - - - - - - - - - - -+------------------------------------------------------------------------------+ -?F1=Scroll Help F9=Reset to Defaults F10=Save and Exit ? -| ^"=Move Highlight Toggles Checkbox Esc=Discard Changes | -+------------------------------------------------------------------------------+ -*/ - /** + Process the user input data. - Display form and wait for user to select one menu option, then return it. + @param UserInput The user input data. + @param ChangeHighlight Whether need to change the highlight statement. - @param Selection On input, Selection tell setup browser the information - about the Selection, form and formset to be displayed. - On output, Selection return the screen item that is selected - by user. @retval EFI_SUCESSS This function always return successfully for now. **/ EFI_STATUS -DisplayForm ( - IN OUT UI_MENU_SELECTION *Selection +ProcessUserInput ( + IN USER_INPUT *UserInput, + IN BOOLEAN ChangeHighlight ) { - CHAR16 *StringPtr; - UINT16 MenuItemCount; - EFI_HII_HANDLE Handle; - EFI_SCREEN_DESCRIPTOR LocalScreen; - UINT16 Width; - UINTN ArrayEntry; - CHAR16 *OutputString; - LIST_ENTRY *Link; - FORM_BROWSER_STATEMENT *Statement; - UINT16 NumberOfLines; - EFI_STATUS Status; - UI_MENU_OPTION *MenuOption; - UINT16 GlyphWidth; - - Handle = Selection->Handle; - MenuItemCount = 0; - ArrayEntry = 0; - OutputString = NULL; - - UiInitMenu (); - - CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - - StringPtr = GetToken (Selection->Form->FormTitle, Handle); + EFI_STATUS Status; + FORM_BROWSER_STATEMENT *Statement; - if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) { - if (Selection->Form->ModalForm) { - gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | EFI_BACKGROUND_BLACK); - } else { - gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND); - } - PrintStringAt ( - (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2, - LocalScreen.TopRow + 1, - StringPtr - ); - } + Status = EFI_SUCCESS; // - // Remove Buffer allocated for StringPtr after it has been used. + // When Exit from FormDisplay function, one of the below two cases must be true. // - FreePool (StringPtr); + ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL); // - // Evaluate all the Expressions in this Form + // Remove the last highligh question id, this id will update when show next form. // - Status = EvaluateFormExpressions (Selection->FormSet, Selection->Form); - if (EFI_ERROR (Status)) { - return Status; - } + gCurrentSelection->QuestionId = 0; - Selection->FormEditable = FALSE; - Link = GetFirstNode (&Selection->Form->StatementListHead); - while (!IsNull (&Selection->Form->StatementListHead, Link)) { - Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + // + // First process the Action field in USER_INPUT. + // + if (UserInput->Action != 0) { + Status = ProcessAction (UserInput->Action, UserInput->DefaultId); + if (EFI_ERROR (Status)) { + return Status; + } - if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) <= ExpressGrayOut) { - StringPtr = GetToken (Statement->Prompt, Handle); - ASSERT (StringPtr != NULL); + // + // Clear the highlight info. + // + gCurrentSelection->Statement = NULL; - Width = GetWidth (Statement, Handle); + if (UserInput->SelectedStatement != NULL) { + Statement = GetBrowserStatement(UserInput->SelectedStatement); + ASSERT (Statement != NULL); + // + // Save the current highlight menu in the menu history data. + // which will be used when later browse back to this form. + // + gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId; + // + // For statement like text, actio, it not has question id. + // So use FakeQuestionId to save the question. + // + if (gCurrentSelection->CurrentMenu->QuestionId == 0) { + mCurFakeQestId = Statement->FakeQuestionId; + } else { + mCurFakeQestId = 0; + } + } + } else { + Statement = GetBrowserStatement(UserInput->SelectedStatement); + ASSERT (Statement != NULL); - NumberOfLines = 1; - ArrayEntry = 0; - GlyphWidth = 1; - for (; GetLineByWidth (StringPtr, Width, &GlyphWidth,&ArrayEntry, &OutputString) != 0x0000;) { - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&StringPtr[ArrayEntry]) != 0) { - NumberOfLines++; - } + gCurrentSelection->Statement = Statement; - FreePool (OutputString); + if (ChangeHighlight) { + // + // This question is the current user select one,record it and later + // show it as the highlight question. + // + gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId; + // + // For statement like text, actio, it not has question id. + // So use FakeQuestionId to save the question. + // + if (gCurrentSelection->CurrentMenu->QuestionId == 0) { + mCurFakeQestId = Statement->FakeQuestionId; + } else { + mCurFakeQestId = 0; } + } + switch (Statement->Operand) { + case EFI_IFR_REF_OP: + Status = ProcessGotoOpCode(Statement, gCurrentSelection); + break; + + case EFI_IFR_ACTION_OP: + // + // Process the Config string + // + Status = ProcessQuestionConfig (gCurrentSelection, Statement); + break; + + case EFI_IFR_RESET_BUTTON_OP: // - // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do - // it in UiFreeMenu. + // Reset Question to default value specified by DefaultId // - MenuOption = UiAddMenuOption (StringPtr, Selection->Handle, Selection->Form, Statement, NumberOfLines, MenuItemCount); - MenuItemCount++; + Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE); + break; + + default: + switch (Statement->Operand) { + case EFI_IFR_STRING_OP: + DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle); + Statement->HiiValue.Value.string = UserInput->InputValue.Value.string; + CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen); + FreePool (UserInput->InputValue.Buffer); + break; + + case EFI_IFR_PASSWORD_OP: + if (UserInput->InputValue.Buffer == NULL) { + // + // User not input new password, just return. + // + break; + } - if (MenuOption->IsQuestion && !MenuOption->ReadOnly) { + DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle); + Statement->HiiValue.Value.string = UserInput->InputValue.Value.string; + CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen); + FreePool (UserInput->InputValue.Buffer); // - // At least one item is not readonly, this Form is considered as editable + // Two password match, send it to Configuration Driver // - Selection->FormEditable = TRUE; + if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { + PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue); + // + // Clean the value after saved it. + // + ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen); + HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL); + } else { + SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver); + } + break; + + case EFI_IFR_ORDERED_LIST_OP: + CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen); + break; + + default: + CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE)); + break; + } + if (Statement->Operand != EFI_IFR_PASSWORD_OP) { + SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer); } + break; } - - Link = GetNextNode (&Selection->Form->StatementListHead, Link); } - Status = UiDisplayMenu (Selection); - - UiFreeMenu (); - return Status; } /** - Initialize the HII String Token to the correct values. - -**/ -VOID -InitializeBrowserStrings ( - VOID - ) -{ - gEnterString = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle); - gEnterCommitString = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle); - gEnterEscapeString = GetToken (STRING_TOKEN (ENTER_ESCAPE_STRING), gHiiHandle); - gEscapeString = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle); - gMoveHighlight = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle); - gMakeSelection = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle); - gDecNumericInput = GetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), gHiiHandle); - gHexNumericInput = GetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), gHiiHandle); - gToggleCheckBox = GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), gHiiHandle); - gPromptForData = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle); - gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle); - gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle); - gConfirmPassword = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle); - gConfirmError = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle); - gPassowordInvalid = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle); - gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle); - gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); - gAreYouSure = GetToken (STRING_TOKEN (ARE_YOU_SURE), gHiiHandle); - gYesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle); - gNoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle); - gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle); - gPlusString = GetToken (STRING_TOKEN (PLUS_STRING), gHiiHandle); - gMinusString = GetToken (STRING_TOKEN (MINUS_STRING), gHiiHandle); - gAdjustNumber = GetToken (STRING_TOKEN (ADJUST_NUMBER), gHiiHandle); - gSaveChanges = GetToken (STRING_TOKEN (SAVE_CHANGES), gHiiHandle); - gOptionMismatch = GetToken (STRING_TOKEN (OPTION_MISMATCH), gHiiHandle); - gFormSuppress = GetToken (STRING_TOKEN (FORM_SUPPRESSED), gHiiHandle); - gProtocolNotFound = GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND), gHiiHandle); - return ; -} - -/** - Free up the resource allocated for all strings required - by Setup Browser. -**/ -VOID -FreeBrowserStrings ( - VOID - ) -{ - FreePool (gEnterString); - FreePool (gEnterCommitString); - FreePool (gEnterEscapeString); - FreePool (gEscapeString); - FreePool (gMoveHighlight); - FreePool (gMakeSelection); - FreePool (gDecNumericInput); - FreePool (gHexNumericInput); - FreePool (gToggleCheckBox); - FreePool (gPromptForData); - FreePool (gPromptForPassword); - FreePool (gPromptForNewPassword); - FreePool (gConfirmPassword); - FreePool (gPassowordInvalid); - FreePool (gConfirmError); - FreePool (gPressEnter); - FreePool (gEmptyString); - FreePool (gAreYouSure); - FreePool (gYesResponse); - FreePool (gNoResponse); - FreePool (gMiniString); - FreePool (gPlusString); - FreePool (gMinusString); - FreePool (gAdjustNumber); - FreePool (gSaveChanges); - FreePool (gOptionMismatch); - FreePool (gFormSuppress); - FreePool (gProtocolNotFound); - return ; -} + Display form and wait for user to select one menu option, then return it. -/** - Show all registered HotKey help strings on bottom Rows. + @retval EFI_SUCESSS This function always return successfully for now. **/ -VOID -PrintHotKeyHelpString ( +EFI_STATUS +DisplayForm ( VOID ) { - UINTN CurrentCol; - UINTN CurrentRow; - UINTN BottomRowOfHotKeyHelp; - UINTN ColumnWidth; - UINTN Index; - EFI_SCREEN_DESCRIPTOR LocalScreen; - LIST_ENTRY *Link; - BROWSER_HOT_KEY *HotKey; + EFI_STATUS Status; + USER_INPUT UserInput; + FORM_ENTRY_INFO *CurrentMenu; + BOOLEAN ChangeHighlight; - CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - ColumnWidth = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3; - BottomRowOfHotKeyHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3; + ZeroMem (&UserInput, sizeof (USER_INPUT)); // - // Calculate total number of Register HotKeys. + // Update the menu history data. // - Index = 0; - Link = GetFirstNode (&gBrowserHotKeyList); - while (!IsNull (&gBrowserHotKeyList, Link)) { - HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); - // - // Help string can't exceed ColumnWidth. One Row will show three Help information. + CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId); + if (CurrentMenu == NULL) { // - if (StrLen (HotKey->HelpString) > ColumnWidth) { - HotKey->HelpString[ColumnWidth] = L'\0'; - } - // - // Calculate help information Column and Row. - // - if ((Index % 3) != 2) { - CurrentCol = LocalScreen.LeftColumn + (2 - Index % 3) * ColumnWidth; - } else { - CurrentCol = LocalScreen.LeftColumn + 2; - } - CurrentRow = BottomRowOfHotKeyHelp - Index / 3; - // - // Print HotKey help string on bottom Row. + // Current menu not found, add it to the menu tree // - PrintStringAt (CurrentCol, CurrentRow, HotKey->HelpString); + CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, + gCurrentSelection->FormId, gCurrentSelection->QuestionId); + ASSERT (CurrentMenu != NULL); + } + gCurrentSelection->CurrentMenu = CurrentMenu; + // + // Find currrent highlight statement. + // + if (gCurrentSelection->QuestionId == 0) { // - // Get Next Hot Key. + // Highlight not specified, fetch it from cached menu // - Link = GetNextNode (&gBrowserHotKeyList, Link); - Index ++; + gCurrentSelection->QuestionId = CurrentMenu->QuestionId; } - - return; -} - -/** - Update key's help imformation. - - @param Selection Tell setup browser the information about the Selection - @param MenuOption The Menu option - @param Selected Whether or not a tag be selected - -**/ -VOID -UpdateKeyHelp ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption, - IN BOOLEAN Selected - ) -{ - UINTN SecCol; - UINTN ThdCol; - UINTN LeftColumnOfHelp; - UINTN RightColumnOfHelp; - UINTN TopRowOfHelp; - UINTN BottomRowOfHelp; - UINTN StartColumnOfHelp; - EFI_SCREEN_DESCRIPTOR LocalScreen; - FORM_BROWSER_STATEMENT *Statement; - - gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); - if (Selection->Form->ModalForm) { - return; + // + // Evaluate all the Expressions in this Form + // + Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form); + if (EFI_ERROR (Status)) { + return Status; } - CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - - SecCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3; - ThdCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3 * 2; - - StartColumnOfHelp = LocalScreen.LeftColumn + 2; - LeftColumnOfHelp = LocalScreen.LeftColumn + 1; - RightColumnOfHelp = LocalScreen.RightColumn - 2; - TopRowOfHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1; - BottomRowOfHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2; - - Statement = MenuOption->ThisTag; - switch (Statement->Operand) { - case EFI_IFR_ORDERED_LIST_OP: - case EFI_IFR_ONE_OF_OP: - case EFI_IFR_NUMERIC_OP: - case EFI_IFR_TIME_OP: - case EFI_IFR_DATE_OP: - ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); - - if (!Selected) { - // - // On system setting, HotKey will show on every form. - // - if (gBrowserSettingScope == SystemLevel || - (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) { - PrintHotKeyHelpString (); - } - - if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) { - PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); - } - - if ((Statement->Operand == EFI_IFR_DATE_OP) || - (Statement->Operand == EFI_IFR_TIME_OP)) { - PrintAt ( - StartColumnOfHelp, - BottomRowOfHelp, - L"%c%c%c%c%s", - ARROW_UP, - ARROW_DOWN, - ARROW_RIGHT, - ARROW_LEFT, - gMoveHighlight - ); - PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); - PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber); - } else { - PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); - if (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0) { - PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber); - } - PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); - } - } else { - PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString); - - // - // If it is a selected numeric with manual input, display different message - // - if ((Statement->Operand == EFI_IFR_NUMERIC_OP) || - (Statement->Operand == EFI_IFR_DATE_OP) || - (Statement->Operand == EFI_IFR_TIME_OP)) { - PrintStringAt ( - SecCol, - TopRowOfHelp, - ((Statement->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX) ? gHexNumericInput : gDecNumericInput - ); - } else if (Statement->Operand != EFI_IFR_ORDERED_LIST_OP) { - PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); - } - - if (Statement->Operand == EFI_IFR_ORDERED_LIST_OP) { - PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString); - PrintStringAt (ThdCol, TopRowOfHelp, gMinusString); - } - - PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString); - } - break; - - case EFI_IFR_CHECKBOX_OP: - ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); - - // - // On system setting, HotKey will show on every form. - // - if (gBrowserSettingScope == SystemLevel || - (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) { - PrintHotKeyHelpString (); - } - if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) { - PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); - } + UpdateDisplayFormData (); - PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); - PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox); - break; + // + // Three possible status maybe return. + // + // EFI_INVALID_PARAMETER: The input dimension info is not valid. + // EFI_NOT_FOUND: The input value for oneof/orderedlist opcode is not valid + // and an valid value has return. + // EFI_SUCCESS: Success shows form and get user input in UserInput paramenter. + // + Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput); + if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) { + FreeDisplayFormData(); + return Status; + } - case EFI_IFR_REF_OP: - case EFI_IFR_PASSWORD_OP: - case EFI_IFR_STRING_OP: - case EFI_IFR_TEXT_OP: - case EFI_IFR_ACTION_OP: - case EFI_IFR_RESET_BUTTON_OP: - case EFI_IFR_SUBTITLE_OP: - ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + // + // If status is EFI_SUCCESS, means user has change the highlight menu and new user input return. + // in this case, browser need to change the highlight menu. + // If status is EFI_NOT_FOUND, means the input DisplayFormData has error for oneof/orderedlist + // opcode and new valid value has return, browser core need to adjust + // value for this opcode and shows this form again. + // + ChangeHighlight = (Status == EFI_SUCCESS ? TRUE :FALSE); - if (!Selected) { - // - // On system setting, HotKey will show on every form. - // - if (gBrowserSettingScope == SystemLevel || - (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) { - PrintHotKeyHelpString (); - } - if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) { - PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); - } + Status = ProcessUserInput (&UserInput, ChangeHighlight); - PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); - if (Statement->Operand != EFI_IFR_TEXT_OP && Statement->Operand != EFI_IFR_SUBTITLE_OP) { - PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); - } - } else { - if (Statement->Operand != EFI_IFR_REF_OP) { - PrintStringAt ( - (LocalScreen.RightColumn - GetStringWidth (gEnterCommitString) / 2) / 2, - BottomRowOfHelp, - gEnterCommitString - ); - PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString); - } - } - break; + FreeDisplayFormData(); - default: - break; - } + return Status; } /** @@ -920,60 +1715,136 @@ FormUpdateNotify ( } /** - check whether the formset need to update the NV. + Update the NV flag info for this form set. @param FormSet FormSet data structure. - @retval TRUE Need to update the NV. - @retval FALSE No need to update the NV. **/ -BOOLEAN -IsNvUpdateRequired ( +BOOLEAN +IsNvUpdateRequiredForFormSet ( IN FORM_BROWSER_FORMSET *FormSet ) { LIST_ENTRY *Link; FORM_BROWSER_FORM *Form; + BOOLEAN RetVal; + + // + // Not finished question initialization, return FALSE. + // + if (!FormSet->QuestionInited) { + return FALSE; + } + + RetVal = FALSE; Link = GetFirstNode (&FormSet->FormListHead); while (!IsNull (&FormSet->FormListHead, Link)) { Form = FORM_BROWSER_FORM_FROM_LINK (Link); - if (Form->NvUpdateRequired ) { - return TRUE; + RetVal = IsNvUpdateRequiredForForm(Form); + if (RetVal) { + break; } Link = GetNextNode (&FormSet->FormListHead, Link); } + return RetVal; +} + +/** + Update the NvUpdateRequired flag for a form. + + @param Form Form data structure. + +**/ +BOOLEAN +IsNvUpdateRequiredForForm ( + IN FORM_BROWSER_FORM *Form + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Statement; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Statement->ValueChanged) { + return TRUE; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + return FALSE; } /** - check whether the formset need to update the NV. + Check whether the storage data for current form set is changed. - @param FormSet FormSet data structure. - @param SetValue Whether set new value or clear old value. + @param FormSet FormSet data structure. + @retval TRUE Data is changed. + @retval FALSE Data is not changed. **/ -VOID -UpdateNvInfoInForm ( - IN FORM_BROWSER_FORMSET *FormSet, - IN BOOLEAN SetValue +BOOLEAN +IsStorageDataChangedForFormSet ( + IN FORM_BROWSER_FORMSET *FormSet ) { LIST_ENTRY *Link; - FORM_BROWSER_FORM *Form; - - Link = GetFirstNode (&FormSet->FormListHead); - while (!IsNull (&FormSet->FormListHead, Link)) { - Form = FORM_BROWSER_FORM_FROM_LINK (Link); + FORMSET_STORAGE *Storage; + BROWSER_STORAGE *BrowserStorage; + CHAR16 *ConfigRespNew; + CHAR16 *ConfigRespOld; + BOOLEAN RetVal; - Form->NvUpdateRequired = SetValue; + RetVal = FALSE; + ConfigRespNew = NULL; + ConfigRespOld = NULL; - Link = GetNextNode (&FormSet->FormListHead, Link); + // + // Request current settings from Configuration Driver + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + BrowserStorage = Storage->BrowserStorage; + + if (BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + if (Storage->ElementCount == 0) { + continue; + } + + StorageToConfigResp (BrowserStorage, &ConfigRespNew, Storage->ConfigRequest, TRUE); + StorageToConfigResp (BrowserStorage, &ConfigRespOld, Storage->ConfigRequest, FALSE); + ASSERT (ConfigRespNew != NULL && ConfigRespOld != NULL); + + if (StrCmp (ConfigRespNew, ConfigRespOld) != 0) { + RetVal = TRUE; + } + + FreePool (ConfigRespNew); + ConfigRespNew = NULL; + + FreePool (ConfigRespOld); + ConfigRespOld = NULL; + + if (RetVal) { + break; + } } + + return RetVal; } + /** Find menu which will show next time. @@ -981,170 +1852,92 @@ UpdateNvInfoInForm ( about the Selection, form and formset to be displayed. On output, Selection return the screen item that is selected by user. - @param Repaint Whether need to repaint the menu. - @param NewLine Whether need to show at new line. + @param SettingLevel Input Settting level, if it is FormLevel, just exit current form. + else, we need to exit current formset. - @retval TRUE Need return. - @retval FALSE No need to return. + @retval TRUE Exit current form. + @retval FALSE User press ESC and keep in current form. **/ BOOLEAN FindNextMenu ( - IN OUT UI_MENU_SELECTION *Selection, - IN BOOLEAN *Repaint, - IN BOOLEAN *NewLine + IN OUT UI_MENU_SELECTION *Selection, + IN BROWSER_SETTING_SCOPE SettingLevel ) { - UI_MENU_LIST *CurrentMenu; - CHAR16 YesResponse; - CHAR16 NoResponse; - EFI_INPUT_KEY Key; - BROWSER_SETTING_SCOPE Scope; + FORM_ENTRY_INFO *CurrentMenu; + FORM_ENTRY_INFO *ParentMenu; + BROWSER_SETTING_SCOPE Scope; CurrentMenu = Selection->CurrentMenu; + ParentMenu = NULL; + Scope = FormSetLevel; - if (CurrentMenu != NULL && CurrentMenu->Parent != NULL) { + if (CurrentMenu != NULL && (ParentMenu = UiFindParentMenu(CurrentMenu)) != NULL) { // // we have a parent, so go to the parent menu // - if (CompareGuid (&CurrentMenu->FormSetGuid, &CurrentMenu->Parent->FormSetGuid)) { - // - // The parent menu and current menu are in the same formset - // - Selection->Action = UI_ACTION_REFRESH_FORM; - Scope = FormLevel; - } else { - Selection->Action = UI_ACTION_REFRESH_FORMSET; - CopyMem (&Selection->FormSetGuid, &CurrentMenu->Parent->FormSetGuid, sizeof (EFI_GUID)); - Selection->Handle = CurrentMenu->Parent->HiiHandle; - Scope = FormSetLevel; - } - - // - // Form Level Check whether the data is changed. - // - if ((gBrowserSettingScope == FormLevel && Selection->Form->NvUpdateRequired) || - (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequired(Selection->FormSet) && Scope == FormSetLevel)) { - gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); - - YesResponse = gYesResponse[0]; - NoResponse = gNoResponse[0]; - - // - // If NV flag is up, prompt user - // - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString); - } while - ( - (Key.ScanCode != SCAN_ESC) && - ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) && - ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET)) - ); - - if (Key.ScanCode == SCAN_ESC) { + if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) { + if (SettingLevel == FormSetLevel) { // - // User hits the ESC key, Ingore. + // Find a menu which has different formset guid with current. // - if (Repaint != NULL) { - *Repaint = TRUE; - } - if (NewLine != NULL) { - *NewLine = TRUE; + while (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) { + CurrentMenu = ParentMenu; + if ((ParentMenu = UiFindParentMenu(CurrentMenu)) == NULL) { + break; + } } - Selection->Action = UI_ACTION_NONE; - return FALSE; - } - - if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) { - // - // If the user hits the YesResponse key - // - SubmitForm (Selection->FormSet, Selection->Form, Scope); + if (ParentMenu != NULL) { + Scope = FormSetLevel; + } } else { - // - // If the user hits the NoResponse key - // - DiscardForm (Selection->FormSet, Selection->Form, Scope); + Scope = FormLevel; } + } else { + Scope = FormSetLevel; } - - Selection->Statement = NULL; - - Selection->FormId = CurrentMenu->Parent->FormId; - Selection->QuestionId = CurrentMenu->Parent->QuestionId; - - // - // Clear highlight record for this menu - // - CurrentMenu->QuestionId = 0; - return FALSE; - } - - if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) { - // - // We never exit FrontPage, so skip the ESC - // - Selection->Action = UI_ACTION_NONE; - return FALSE; } // - // We are going to leave current FormSet, so check uncommited data in this FormSet + // Form Level Check whether the data is changed. // - if (gBrowserSettingScope != SystemLevel && IsNvUpdateRequired(Selection->FormSet)) { - gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); - - YesResponse = gYesResponse[0]; - NoResponse = gNoResponse[0]; - - // - // If NV flag is up, prompt user - // - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString); - } while - ( - (Key.ScanCode != SCAN_ESC) && - ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) && - ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET)) - ); - - if (Key.ScanCode == SCAN_ESC) { - // - // User hits the ESC key - // - if (Repaint != NULL) { - *Repaint = TRUE; - } - - if (NewLine != NULL) { - *NewLine = TRUE; - } - - Selection->Action = UI_ACTION_NONE; + if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) || + (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) { + if (!ProcessChangedData(Selection, Scope)) { return FALSE; } + } - if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) { - // - // If the user hits the YesResponse key - // - SubmitForm (Selection->FormSet, Selection->Form, FormSetLevel); + if (ParentMenu != NULL) { + // + // ParentMenu is found. Then, go to it. + // + if (Scope == FormLevel) { + Selection->Action = UI_ACTION_REFRESH_FORM; } else { - // - // If the user hits the NoResponse key - // - DiscardForm (Selection->FormSet, Selection->Form, FormSetLevel); + Selection->Action = UI_ACTION_REFRESH_FORMSET; + CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID)); + Selection->Handle = ParentMenu->HiiHandle; } - } - Selection->Statement = NULL; - if (CurrentMenu != NULL) { + Selection->Statement = NULL; + + Selection->FormId = ParentMenu->FormId; + Selection->QuestionId = ParentMenu->QuestionId; + + // + // Clear highlight record for this menu + // CurrentMenu->QuestionId = 0; + return FALSE; } + // + // Current in root page, exit the SendForm + // Selection->Action = UI_ACTION_EXIT; + return TRUE; } @@ -1246,17 +2039,17 @@ ProcessCallBackFunction ( case EFI_BROWSER_ACTION_REQUEST_RESET: DiscardFormIsRequired = TRUE; gResetRequired = TRUE; - Selection->Action = UI_ACTION_EXIT; + NeedExit = TRUE; break; case EFI_BROWSER_ACTION_REQUEST_SUBMIT: SubmitFormIsRequired = TRUE; - Selection->Action = UI_ACTION_EXIT; + NeedExit = TRUE; break; case EFI_BROWSER_ACTION_REQUEST_EXIT: DiscardFormIsRequired = TRUE; - Selection->Action = UI_ACTION_EXIT; + NeedExit = TRUE; break; case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT: @@ -1267,7 +2060,7 @@ ProcessCallBackFunction ( case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT: DiscardFormIsRequired = TRUE; - SettingLevel = FormLevel; + SettingLevel = FormLevel; NeedExit = TRUE; break; @@ -1320,7 +2113,7 @@ ProcessCallBackFunction ( } if (NeedExit) { - FindNextMenu (Selection, NULL, NULL); + FindNextMenu (Selection, SettingLevel); } return Status; @@ -1400,9 +2193,7 @@ SetupBrowser ( EFI_HANDLE NotifyHandle; FORM_BROWSER_STATEMENT *Statement; EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; - EFI_INPUT_KEY Key; - gMenuRefreshHead = NULL; ConfigAccess = Selection->FormSet->ConfigAccess; // @@ -1423,21 +2214,17 @@ SetupBrowser ( // // Initialize current settings of Questions in this FormSet // - Status = InitializeCurrentSetting (Selection->FormSet); - if (EFI_ERROR (Status)) { - goto Done; - } + InitializeCurrentSetting (Selection->FormSet); // - // Update gOldFormSet on maintain back up FormSet list. - // And, make gOldFormSet point to current FormSet. + // Initilize Action field. // - if (gOldFormSet != NULL) { - RemoveEntryList (&gOldFormSet->Link); - DestroyFormSet (gOldFormSet); - } - gOldFormSet = Selection->FormSet; - InsertTailList (&gBrowserFormSetList, &gOldFormSet->Link); + Selection->Action = UI_ACTION_REFRESH_FORM; + + // + // Clean the mCurFakeQestId value is formset refreshed. + // + mCurFakeQestId = 0; do { // @@ -1480,10 +2267,7 @@ SetupBrowser ( // // Form is suppressed. // - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - + gBrowserStatus = BROWSER_FORM_SUPPRESS; Status = EFI_NOT_FOUND; goto Done; } @@ -1498,7 +2282,6 @@ SetupBrowser ( ((Selection->Handle != mCurrentHiiHandle) || (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) || (Selection->FormId != mCurrentFormId))) { - // // Keep current form information // @@ -1511,12 +2294,6 @@ SetupBrowser ( goto Done; } - // - // EXIT requests to close form. - // - if (Selection->Action == UI_ACTION_EXIT) { - goto Done; - } // // IFR is updated during callback of open form, force to reparse the IFR binary // @@ -1535,12 +2312,6 @@ SetupBrowser ( goto Done; } - // - // EXIT requests to close form. - // - if (Selection->Action == UI_ACTION_EXIT) { - goto Done; - } // // IFR is updated during callback of read value, force to reparse the IFR binary // @@ -1550,15 +2321,10 @@ SetupBrowser ( break; } - // - // Displays the Header and Footer borders - // - DisplayPageFrame (Selection); - // // Display form // - Status = DisplayForm (Selection); + Status = DisplayForm (); if (EFI_ERROR (Status)) { goto Done; } @@ -1568,20 +2334,16 @@ SetupBrowser ( // Statement = Selection->Statement; if (Statement != NULL) { - if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED) { - gResetRequired = TRUE; - } - if ((ConfigAccess != NULL) && ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) { - Status = ProcessCallBackFunction(Selection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE); - if (Statement->Operand == EFI_IFR_REF_OP && Selection->Action != UI_ACTION_EXIT) { + Status = ProcessCallBackFunction(Selection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE); + if (Statement->Operand == EFI_IFR_REF_OP) { // // Process dynamic update ref opcode. // if (!EFI_ERROR (Status)) { - Status = ProcessGotoOpCode(Statement, Selection, NULL, NULL); + Status = ProcessGotoOpCode(Statement, Selection); } // @@ -1602,6 +2364,27 @@ SetupBrowser ( } } + // + // Check whether Exit flag is TRUE. + // + if (gExitRequired) { + switch (gBrowserSettingScope) { + case SystemLevel: + Selection->Action = UI_ACTION_EXIT; + break; + + case FormSetLevel: + case FormLevel: + FindNextMenu (Selection, gBrowserSettingScope); + break; + + default: + break; + } + + gExitRequired = FALSE; + } + // // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE // for each question with callback flag. diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Print.c b/MdeModulePkg/Universal/SetupBrowserDxe/Print.c deleted file mode 100644 index eeadf2494f..0000000000 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Print.c +++ /dev/null @@ -1,272 +0,0 @@ -/** @file -Basic Ascii AvSPrintf() function named VSPrint(). VSPrint() enables very -simple implemenation of SPrint() and Print() to support debug. - -You can not Print more than EFI_DRIVER_LIB_MAX_PRINT_BUFFER characters at a -time. This makes the implementation very simple. - -VSPrint, Print, SPrint format specification has the follwoing form - -%type - -type: - 'S','s' - argument is an Unicode string - 'c' - argument is an ascii character - '%' - Print a % - - -Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "Setup.h" - -/** - The internal function prints to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL - protocol instance. - - @param Column The position of the output string. - @param Row The position of the output string. - @param Out The EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance. - @param Fmt The format string. - @param Args The additional argument for the variables in the format string. - - @return Number of Unicode character printed. - -**/ -UINTN -PrintInternal ( - IN UINTN Column, - IN UINTN Row, - IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out, - IN CHAR16 *Fmt, - IN VA_LIST Args - ) -{ - CHAR16 *Buffer; - CHAR16 *BackupBuffer; - UINTN Index; - UINTN PreviousIndex; - UINTN Count; - - // - // For now, allocate an arbitrarily long buffer - // - Buffer = AllocateZeroPool (0x10000); - BackupBuffer = AllocateZeroPool (0x10000); - ASSERT (Buffer); - ASSERT (BackupBuffer); - - if (Column != (UINTN) -1) { - Out->SetCursorPosition (Out, Column, Row); - } - - UnicodeVSPrint (Buffer, 0x10000, Fmt, Args); - - Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; - - Out->SetAttribute (Out, Out->Mode->Attribute); - - Index = 0; - PreviousIndex = 0; - Count = 0; - - do { - for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) { - BackupBuffer[Index] = Buffer[Index]; - } - - if (Buffer[Index] == 0) { - break; - } - // - // Null-terminate the temporary string - // - BackupBuffer[Index] = 0; - - // - // Print this out, we are about to switch widths - // - Out->OutputString (Out, &BackupBuffer[PreviousIndex]); - Count += StrLen (&BackupBuffer[PreviousIndex]); - - // - // Preserve the current index + 1, since this is where we will start printing from next - // - PreviousIndex = Index + 1; - - // - // We are at a narrow or wide character directive. Set attributes and strip it and print it - // - if (Buffer[Index] == NARROW_CHAR) { - // - // Preserve bits 0 - 6 and zero out the rest - // - Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; - Out->SetAttribute (Out, Out->Mode->Attribute); - } else { - // - // Must be wide, set bit 7 ON - // - Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE; - Out->SetAttribute (Out, Out->Mode->Attribute); - } - - Index++; - - } while (Buffer[Index] != 0); - - // - // We hit the end of the string - print it - // - Out->OutputString (Out, &BackupBuffer[PreviousIndex]); - Count += StrLen (&BackupBuffer[PreviousIndex]); - - FreePool (Buffer); - FreePool (BackupBuffer); - return Count; -} - - -/** - Prints a formatted unicode string to the default console. - - @param Fmt Format string - @param ... Variable argument list for format string. - - @return Length of string printed to the console. - -**/ -UINTN -EFIAPI -ConsolePrint ( - IN CHAR16 *Fmt, - ... - ) -{ - VA_LIST Args; - UINTN LengthOfPrinted; - - VA_START (Args, Fmt); - LengthOfPrinted = PrintInternal ((UINTN) -1, (UINTN) -1, gST->ConOut, Fmt, Args); - VA_END (Args); - return LengthOfPrinted; -} - - -/** - Prints a unicode string to the default console, - using L"%s" format. - - @param String String pointer. - - @return Length of string printed to the console - -**/ -UINTN -PrintString ( - IN CHAR16 *String - ) -{ - return ConsolePrint (L"%s", String); -} - - -/** - Prints a chracter to the default console, - using L"%c" format. - - @param Character Character to print. - - @return Length of string printed to the console. - -**/ -UINTN -PrintChar ( - CHAR16 Character - ) -{ - return ConsolePrint (L"%c", Character); -} - - -/** - Prints a formatted unicode string to the default console, at - the supplied cursor position. - - @param Column The cursor position to print the string at. - @param Row The cursor position to print the string at. - @param Fmt Format string. - @param ... Variable argument list for format string. - - @return Length of string printed to the console - -**/ -UINTN -EFIAPI -PrintAt ( - IN UINTN Column, - IN UINTN Row, - IN CHAR16 *Fmt, - ... - ) -{ - VA_LIST Args; - UINTN LengthOfPrinted; - - VA_START (Args, Fmt); - LengthOfPrinted = PrintInternal (Column, Row, gST->ConOut, Fmt, Args); - VA_END (Args); - return LengthOfPrinted; -} - - -/** - Prints a unicode string to the default console, at - the supplied cursor position, using L"%s" format. - - @param Column The cursor position to print the string at. - @param Row The cursor position to print the string at - @param String String pointer. - - @return Length of string printed to the console - -**/ -UINTN -PrintStringAt ( - IN UINTN Column, - IN UINTN Row, - IN CHAR16 *String - ) -{ - return PrintAt (Column, Row, L"%s", String); -} - - -/** - Prints a chracter to the default console, at - the supplied cursor position, using L"%c" format. - - @param Column The cursor position to print the string at. - @param Row The cursor position to print the string at. - @param Character Character to print. - - @return Length of string printed to the console. - -**/ -UINTN -PrintCharAt ( - IN UINTN Column, - IN UINTN Row, - CHAR16 Character - ) -{ - return PrintAt (Column, Row, L"%c", Character); -} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c b/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c deleted file mode 100644 index fecb98e8bf..0000000000 --- a/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c +++ /dev/null @@ -1,1075 +0,0 @@ -/** @file -Implementation for handling the User Interface option processing. - - -Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "Setup.h" - - -/** - Process Question Config. - - @param Selection The UI menu selection. - @param Question The Question to be peocessed. - - @retval EFI_SUCCESS Question Config process success. - @retval Other Question Config process fail. - -**/ -EFI_STATUS -ProcessQuestionConfig ( - IN UI_MENU_SELECTION *Selection, - IN FORM_BROWSER_STATEMENT *Question - ) -{ - EFI_STATUS Status; - CHAR16 *ConfigResp; - CHAR16 *Progress; - EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; - - if (Question->QuestionConfig == 0) { - return EFI_SUCCESS; - } - - // - // Get - // - ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle); - if (ConfigResp == NULL) { - return EFI_NOT_FOUND; - } - - // - // Send config to Configuration Driver - // - ConfigAccess = Selection->FormSet->ConfigAccess; - if (ConfigAccess == NULL) { - return EFI_UNSUPPORTED; - } - Status = ConfigAccess->RouteConfig ( - ConfigAccess, - ConfigResp, - &Progress - ); - - return Status; -} - - -/** - Search an Option of a Question by its value. - - @param Question The Question - @param OptionValue Value for Option to be searched. - - @retval Pointer Pointer to the found Option. - @retval NULL Option not found. - -**/ -QUESTION_OPTION * -ValueToOption ( - IN FORM_BROWSER_STATEMENT *Question, - IN EFI_HII_VALUE *OptionValue - ) -{ - LIST_ENTRY *Link; - QUESTION_OPTION *Option; - INTN Result; - - Link = GetFirstNode (&Question->OptionListHead); - while (!IsNull (&Question->OptionListHead, Link)) { - Option = QUESTION_OPTION_FROM_LINK (Link); - - if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { - // - // Check the suppressif condition, only a valid option can be return. - // - if ((Option->SuppressExpression == NULL) || - ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) { - return Option; - } - } - - Link = GetNextNode (&Question->OptionListHead, Link); - } - - return NULL; -} - - -/** - Return data element in an Array by its Index. - - @param Array The data array. - @param Type Type of the data in this array. - @param Index Zero based index for data in this array. - - @retval Value The data to be returned - -**/ -UINT64 -GetArrayData ( - IN VOID *Array, - IN UINT8 Type, - IN UINTN Index - ) -{ - UINT64 Data; - - ASSERT (Array != NULL); - - Data = 0; - switch (Type) { - case EFI_IFR_TYPE_NUM_SIZE_8: - Data = (UINT64) *(((UINT8 *) Array) + Index); - break; - - case EFI_IFR_TYPE_NUM_SIZE_16: - Data = (UINT64) *(((UINT16 *) Array) + Index); - break; - - case EFI_IFR_TYPE_NUM_SIZE_32: - Data = (UINT64) *(((UINT32 *) Array) + Index); - break; - - case EFI_IFR_TYPE_NUM_SIZE_64: - Data = (UINT64) *(((UINT64 *) Array) + Index); - break; - - default: - break; - } - - return Data; -} - - -/** - Set value of a data element in an Array by its Index. - - @param Array The data array. - @param Type Type of the data in this array. - @param Index Zero based index for data in this array. - @param Value The value to be set. - -**/ -VOID -SetArrayData ( - IN VOID *Array, - IN UINT8 Type, - IN UINTN Index, - IN UINT64 Value - ) -{ - - ASSERT (Array != NULL); - - switch (Type) { - case EFI_IFR_TYPE_NUM_SIZE_8: - *(((UINT8 *) Array) + Index) = (UINT8) Value; - break; - - case EFI_IFR_TYPE_NUM_SIZE_16: - *(((UINT16 *) Array) + Index) = (UINT16) Value; - break; - - case EFI_IFR_TYPE_NUM_SIZE_32: - *(((UINT32 *) Array) + Index) = (UINT32) Value; - break; - - case EFI_IFR_TYPE_NUM_SIZE_64: - *(((UINT64 *) Array) + Index) = (UINT64) Value; - break; - - default: - break; - } -} - -/** - Check whether this value already in the array, if yes, return the index. - - @param Array The data array. - @param Type Type of the data in this array. - @param Value The value to be find. - @param Index The index in the array which has same value with Value. - - @retval TRUE Found the value in the array. - @retval FALSE Not found the value. - -**/ -BOOLEAN -FindArrayData ( - IN VOID *Array, - IN UINT8 Type, - IN UINT64 Value, - OUT UINTN *Index OPTIONAL - ) -{ - UINTN Count; - UINT64 TmpValue; - - ASSERT (Array != NULL); - - Count = 0; - TmpValue = 0; - - while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) { - if (Value == TmpValue) { - if (Index != NULL) { - *Index = Count; - } - return TRUE; - } - - Count ++; - } - - return FALSE; -} - -/** - Print Question Value according to it's storage width and display attributes. - - @param Question The Question to be printed. - @param FormattedNumber Buffer for output string. - @param BufferSize The FormattedNumber buffer size in bytes. - - @retval EFI_SUCCESS Print success. - @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number. - -**/ -EFI_STATUS -PrintFormattedNumber ( - IN FORM_BROWSER_STATEMENT *Question, - IN OUT CHAR16 *FormattedNumber, - IN UINTN BufferSize - ) -{ - INT64 Value; - CHAR16 *Format; - EFI_HII_VALUE *QuestionValue; - - if (BufferSize < (21 * sizeof (CHAR16))) { - return EFI_BUFFER_TOO_SMALL; - } - - QuestionValue = &Question->HiiValue; - - Value = (INT64) QuestionValue->Value.u64; - switch (Question->Flags & EFI_IFR_DISPLAY) { - case EFI_IFR_DISPLAY_INT_DEC: - switch (QuestionValue->Type) { - case EFI_IFR_NUMERIC_SIZE_1: - Value = (INT64) ((INT8) QuestionValue->Value.u8); - break; - - case EFI_IFR_NUMERIC_SIZE_2: - Value = (INT64) ((INT16) QuestionValue->Value.u16); - break; - - case EFI_IFR_NUMERIC_SIZE_4: - Value = (INT64) ((INT32) QuestionValue->Value.u32); - break; - - case EFI_IFR_NUMERIC_SIZE_8: - default: - break; - } - - if (Value < 0) { - Value = -Value; - Format = L"-%ld"; - } else { - Format = L"%ld"; - } - break; - - case EFI_IFR_DISPLAY_UINT_DEC: - Format = L"%ld"; - break; - - case EFI_IFR_DISPLAY_UINT_HEX: - Format = L"%lx"; - break; - - default: - return EFI_UNSUPPORTED; - break; - } - - UnicodeSPrint (FormattedNumber, BufferSize, Format, Value); - - return EFI_SUCCESS; -} - - -/** - Password may be stored as encrypted by Configuration Driver. When change a - password, user will be challenged with old password. To validate user input old - password, we will send the clear text to Configuration Driver via Callback(). - Configuration driver is responsible to check the passed in password and return - the validation result. If validation pass, state machine in password Callback() - will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD. - After user type in new password twice, Callback() will be invoked to send the - new password to Configuration Driver. - - @param Selection Pointer to UI_MENU_SELECTION. - @param MenuOption The MenuOption for this password Question. - @param String The clear text of password. - - @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input. - @return In state of BROWSER_STATE_VALIDATE_PASSWORD: - @retval EFI_SUCCESS Password correct, Browser will prompt for new - password. - @retval EFI_NOT_READY Password incorrect, Browser will show error - message. - @retval Other Browser will do nothing. - @return In state of BROWSER_STATE_SET_PASSWORD: - @retval EFI_SUCCESS Set password success. - @retval Other Set password failed. - -**/ -EFI_STATUS -PasswordCallback ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption, - IN CHAR16 *String - ) -{ - EFI_STATUS Status; - EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; - EFI_BROWSER_ACTION_REQUEST ActionRequest; - EFI_IFR_TYPE_VALUE IfrTypeValue; - - ConfigAccess = Selection->FormSet->ConfigAccess; - if (ConfigAccess == NULL) { - return EFI_UNSUPPORTED; - } - - // - // Prepare password string in HII database - // - if (String != NULL) { - IfrTypeValue.string = NewString (String, Selection->FormSet->HiiHandle); - } else { - IfrTypeValue.string = 0; - } - - // - // Send password to Configuration Driver for validation - // - Status = ConfigAccess->Callback ( - ConfigAccess, - EFI_BROWSER_ACTION_CHANGING, - MenuOption->ThisTag->QuestionId, - MenuOption->ThisTag->HiiValue.Type, - &IfrTypeValue, - &ActionRequest - ); - - // - // Remove password string from HII database - // - if (String != NULL) { - DeleteString (IfrTypeValue.string, Selection->FormSet->HiiHandle); - } - - return Status; -} - - -/** - Display error message for invalid password. - -**/ -VOID -PasswordInvalid ( - VOID - ) -{ - EFI_INPUT_KEY Key; - - // - // Invalid password, prompt error message - // - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); -} - - -/** - Process a Question's Option (whether selected or un-selected). - - @param Selection Pointer to UI_MENU_SELECTION. - @param MenuOption The MenuOption for this Question. - @param Selected TRUE: if Question is selected. - @param OptionString Pointer of the Option String to be displayed. - - @retval EFI_SUCCESS Question Option process success. - @retval Other Question Option process fail. - -**/ -EFI_STATUS -ProcessOptions ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption, - IN BOOLEAN Selected, - OUT CHAR16 **OptionString - ) -{ - EFI_STATUS Status; - CHAR16 *StringPtr; - CHAR16 *TempString; - UINTN Index; - FORM_BROWSER_STATEMENT *Question; - CHAR16 FormattedNumber[21]; - UINT16 Number; - CHAR16 Character[2]; - EFI_INPUT_KEY Key; - UINTN BufferSize; - QUESTION_OPTION *OneOfOption; - LIST_ENTRY *Link; - EFI_HII_VALUE HiiValue; - EFI_HII_VALUE *QuestionValue; - UINT16 Maximum; - QUESTION_OPTION *Option; - UINTN Index2; - UINT8 *ValueArray; - UINT8 ValueType; - EFI_STRING_ID StringId; - - Status = EFI_SUCCESS; - - StringPtr = NULL; - Character[1] = L'\0'; - *OptionString = NULL; - StringId = 0; - - ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); - BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow; - - Question = MenuOption->ThisTag; - QuestionValue = &Question->HiiValue; - Maximum = (UINT16) Question->Maximum; - - ValueArray = Question->BufferValue; - ValueType = Question->ValueType; - - switch (Question->Operand) { - case EFI_IFR_ORDERED_LIST_OP: - // - // Check whether there are Options of this OrderedList - // - if (IsListEmpty (&Question->OptionListHead)) { - break; - } - // - // Initialize Option value array - // - if (GetArrayData (ValueArray, ValueType, 0) == 0) { - GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0); - } - - if (Selected) { - // - // Go ask for input - // - Status = GetSelectionInputPopUp (Selection, MenuOption); - } else { - // - // We now know how many strings we will have, so we can allocate the - // space required for the array or strings. - // - *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize); - ASSERT (*OptionString); - - HiiValue.Type = ValueType; - HiiValue.Value.u64 = 0; - for (Index = 0; Index < Question->MaxContainers; Index++) { - HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index); - if (HiiValue.Value.u64 == 0) { - // - // Values for the options in ordered lists should never be a 0 - // - break; - } - - OneOfOption = ValueToOption (Question, &HiiValue); - if (OneOfOption == NULL) { - // - // Show error message - // - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - - // - // The initial value of the orderedlist is invalid, force to be valid value - // - Link = GetFirstNode (&Question->OptionListHead); - Index2 = 0; - while (!IsNull (&Question->OptionListHead, Link) && Index2 < Question->MaxContainers) { - Option = QUESTION_OPTION_FROM_LINK (Link); - Link = GetNextNode (&Question->OptionListHead, Link); - if ((Option->SuppressExpression != NULL) && - ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) { - continue; - } - SetArrayData (ValueArray, ValueType, Index2, Option->Value.Value.u64); - Index2++; - } - SetArrayData (ValueArray, ValueType, Index2, 0); - - Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer); - UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); - - FreePool (*OptionString); - *OptionString = NULL; - return EFI_NOT_FOUND; - } - - Character[0] = LEFT_ONEOF_DELIMITER; - NewStrCat (OptionString[0], Character); - StringPtr = GetToken (OneOfOption->Text, Selection->Handle); - ASSERT (StringPtr != NULL); - NewStrCat (OptionString[0], StringPtr); - Character[0] = RIGHT_ONEOF_DELIMITER; - NewStrCat (OptionString[0], Character); - Character[0] = CHAR_CARRIAGE_RETURN; - NewStrCat (OptionString[0], Character); - FreePool (StringPtr); - } - - // - // Search the other options, try to find the one not in the container. - // - Link = GetFirstNode (&Question->OptionListHead); - while (!IsNull (&Question->OptionListHead, Link)) { - OneOfOption = QUESTION_OPTION_FROM_LINK (Link); - Link = GetNextNode (&Question->OptionListHead, Link); - if ((OneOfOption->SuppressExpression != NULL) && - ((EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) { - continue; - } - - if (FindArrayData (ValueArray, ValueType, OneOfOption->Value.Value.u64, NULL)) { - continue; - } - - SetArrayData (ValueArray, ValueType, Index++, OneOfOption->Value.Value.u64); - - Character[0] = LEFT_ONEOF_DELIMITER; - NewStrCat (OptionString[0], Character); - StringPtr = GetToken (OneOfOption->Text, Selection->Handle); - ASSERT (StringPtr != NULL); - NewStrCat (OptionString[0], StringPtr); - Character[0] = RIGHT_ONEOF_DELIMITER; - NewStrCat (OptionString[0], Character); - Character[0] = CHAR_CARRIAGE_RETURN; - NewStrCat (OptionString[0], Character); - FreePool (StringPtr); - } - } - break; - - case EFI_IFR_ONE_OF_OP: - // - // Check whether there are Options of this OneOf - // - if (IsListEmpty (&Question->OptionListHead)) { - break; - } - if (Selected) { - // - // Go ask for input - // - Status = GetSelectionInputPopUp (Selection, MenuOption); - } else { - *OptionString = AllocateZeroPool (BufferSize); - ASSERT (*OptionString); - - OneOfOption = ValueToOption (Question, QuestionValue); - if (OneOfOption == NULL) { - // - // Show error message - // - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - - // - // Force the Question value to be valid - // - Link = GetFirstNode (&Question->OptionListHead); - while (!IsNull (&Question->OptionListHead, Link)) { - Option = QUESTION_OPTION_FROM_LINK (Link); - - if ((Option->SuppressExpression == NULL) || - (EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse)) { - CopyMem (QuestionValue, &Option->Value, sizeof (EFI_HII_VALUE)); - SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer); - UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); - break; - } - - Link = GetNextNode (&Question->OptionListHead, Link); - } - - FreePool (*OptionString); - *OptionString = NULL; - return EFI_NOT_FOUND; - } - - Character[0] = LEFT_ONEOF_DELIMITER; - NewStrCat (OptionString[0], Character); - StringPtr = GetToken (OneOfOption->Text, Selection->Handle); - ASSERT (StringPtr != NULL); - NewStrCat (OptionString[0], StringPtr); - Character[0] = RIGHT_ONEOF_DELIMITER; - NewStrCat (OptionString[0], Character); - - FreePool (StringPtr); - } - break; - - case EFI_IFR_CHECKBOX_OP: - *OptionString = AllocateZeroPool (BufferSize); - ASSERT (*OptionString); - - *OptionString[0] = LEFT_CHECKBOX_DELIMITER; - - if (Selected) { - // - // Since this is a BOOLEAN operation, flip it upon selection - // - QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE); - - // - // Perform inconsistent check - // - Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); - if (EFI_ERROR (Status)) { - // - // Inconsistent check fail, restore Question Value - // - QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE); - FreePool (*OptionString); - *OptionString = NULL; - return Status; - } - - // - // Save Question value - // - Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer); - UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); - } - - if (QuestionValue->Value.b) { - *(OptionString[0] + 1) = CHECK_ON; - } else { - *(OptionString[0] + 1) = CHECK_OFF; - } - *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER; - break; - - case EFI_IFR_NUMERIC_OP: - if (Selected) { - // - // Go ask for input - // - Status = GetNumericInput (Selection, MenuOption); - } else { - *OptionString = AllocateZeroPool (BufferSize); - ASSERT (*OptionString); - - *OptionString[0] = LEFT_NUMERIC_DELIMITER; - - // - // Formatted print - // - PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); - Number = (UINT16) GetStringWidth (FormattedNumber); - CopyMem (OptionString[0] + 1, FormattedNumber, Number); - - *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER; - } - break; - - case EFI_IFR_DATE_OP: - if (Selected) { - // - // This is similar to numerics - // - Status = GetNumericInput (Selection, MenuOption); - } else { - *OptionString = AllocateZeroPool (BufferSize); - ASSERT (*OptionString); - - switch (MenuOption->Sequence) { - case 0: - *OptionString[0] = LEFT_NUMERIC_DELIMITER; - UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month); - *(OptionString[0] + 3) = DATE_SEPARATOR; - break; - - case 1: - SetUnicodeMem (OptionString[0], 4, L' '); - UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day); - *(OptionString[0] + 6) = DATE_SEPARATOR; - break; - - case 2: - SetUnicodeMem (OptionString[0], 7, L' '); - UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year); - *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER; - break; - } - } - break; - - case EFI_IFR_TIME_OP: - if (Selected) { - // - // This is similar to numerics - // - Status = GetNumericInput (Selection, MenuOption); - } else { - *OptionString = AllocateZeroPool (BufferSize); - ASSERT (*OptionString); - - switch (MenuOption->Sequence) { - case 0: - *OptionString[0] = LEFT_NUMERIC_DELIMITER; - UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour); - *(OptionString[0] + 3) = TIME_SEPARATOR; - break; - - case 1: - SetUnicodeMem (OptionString[0], 4, L' '); - UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute); - *(OptionString[0] + 6) = TIME_SEPARATOR; - break; - - case 2: - SetUnicodeMem (OptionString[0], 7, L' '); - UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second); - *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER; - break; - } - } - break; - - case EFI_IFR_STRING_OP: - if (Selected) { - StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); - ASSERT (StringPtr); - CopyMem(StringPtr, Question->BufferValue, Maximum * sizeof (CHAR16)); - - Status = ReadString (MenuOption, gPromptForData, StringPtr); - if (!EFI_ERROR (Status)) { - HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL); - Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); - if (EFI_ERROR (Status)) { - HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL); - } else { - CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16)); - SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer); - - UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); - } - } - - FreePool (StringPtr); - } else { - *OptionString = AllocateZeroPool (BufferSize); - ASSERT (*OptionString); - - if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) { - *(OptionString[0]) = '_'; - } else { - if ((Maximum * sizeof (CHAR16)) < BufferSize) { - BufferSize = Maximum * sizeof (CHAR16); - } - CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize); - } - } - break; - - case EFI_IFR_PASSWORD_OP: - if (Selected) { - StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); - ASSERT (StringPtr); - - // - // For interactive passwords, old password is validated by callback - // - if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { - // - // Use a NULL password to test whether old password is required - // - *StringPtr = 0; - Status = PasswordCallback (Selection, MenuOption, StringPtr); - if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) { - // - // Callback is not supported, or - // Callback request to terminate password input - // - FreePool (StringPtr); - return EFI_SUCCESS; - } - - if (EFI_ERROR (Status)) { - // - // Old password exist, ask user for the old password - // - Status = ReadString (MenuOption, gPromptForPassword, StringPtr); - if (EFI_ERROR (Status)) { - FreePool (StringPtr); - return Status; - } - - // - // Check user input old password - // - Status = PasswordCallback (Selection, MenuOption, StringPtr); - if (EFI_ERROR (Status)) { - if (Status == EFI_NOT_READY) { - // - // Typed in old password incorrect - // - PasswordInvalid (); - } else { - Status = EFI_SUCCESS; - } - - FreePool (StringPtr); - return Status; - } - } - } else { - // - // For non-interactive password, validate old password in local - // - if (*((CHAR16 *) Question->BufferValue) != 0) { - // - // There is something there! Prompt for password - // - Status = ReadString (MenuOption, gPromptForPassword, StringPtr); - if (EFI_ERROR (Status)) { - FreePool (StringPtr); - return Status; - } - - TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue); - ASSERT (TempString != NULL); - - TempString[Maximum] = L'\0'; - - if (StrCmp (StringPtr, TempString) != 0) { - // - // Typed in old password incorrect - // - PasswordInvalid (); - - FreePool (StringPtr); - FreePool (TempString); - return Status; - } - - FreePool (TempString); - } - } - - // - // Ask for new password - // - ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); - Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr); - if (EFI_ERROR (Status)) { - // - // Reset state machine for interactive password - // - if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { - PasswordCallback (Selection, MenuOption, NULL); - } - - FreePool (StringPtr); - return Status; - } - - // - // Confirm new password - // - TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); - ASSERT (TempString); - Status = ReadString (MenuOption, gConfirmPassword, TempString); - if (EFI_ERROR (Status)) { - // - // Reset state machine for interactive password - // - if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { - PasswordCallback (Selection, MenuOption, NULL); - } - - FreePool (StringPtr); - FreePool (TempString); - return Status; - } - - // - // Compare two typed-in new passwords - // - if (StrCmp (StringPtr, TempString) == 0) { - // - // Prepare the Question->HiiValue.Value.string for ValidateQuestion use. - // - if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { - StringId = Question->HiiValue.Value.string; - Question->HiiValue.Value.string = NewString (StringPtr, Selection->FormSet->HiiHandle); - } else { - HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL); - } - - Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); - - // - // Researve the Question->HiiValue.Value.string. - // - if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { - DeleteString(Question->HiiValue.Value.string, Selection->FormSet->HiiHandle); - Question->HiiValue.Value.string = StringId; - } - - if (EFI_ERROR (Status)) { - // - // Reset state machine for interactive password - // - if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { - PasswordCallback (Selection, MenuOption, NULL); - } else { - // - // Researve the Question->HiiValue.Value.string. - // - HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL); - } - } else { - // - // Two password match, send it to Configuration Driver - // - if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { - PasswordCallback (Selection, MenuOption, StringPtr); - } else { - CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16)); - SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithHiiDriver); - } - } - } else { - // - // Reset state machine for interactive password - // - if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { - PasswordCallback (Selection, MenuOption, NULL); - } - - // - // Two password mismatch, prompt error message - // - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - } - - FreePool (TempString); - FreePool (StringPtr); - } - break; - - default: - break; - } - - return Status; -} - - -/** - Process the help string: Split StringPtr to several lines of strings stored in - FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth. - - @param StringPtr The entire help string. - @param FormattedString The oupput formatted string. - @param EachLineWidth The max string length of each line in the formatted string. - @param RowCount TRUE: if Question is selected. - -**/ -UINTN -ProcessHelpString ( - IN CHAR16 *StringPtr, - OUT CHAR16 **FormattedString, - OUT UINT16 *EachLineWidth, - IN UINTN RowCount - ) -{ - UINTN Index; - CHAR16 *OutputString; - UINTN TotalRowNum; - UINTN CheckedNum; - UINT16 GlyphWidth; - UINT16 LineWidth; - UINT16 MaxStringLen; - UINT16 StringLen; - - TotalRowNum = 0; - CheckedNum = 0; - GlyphWidth = 1; - Index = 0; - MaxStringLen = 0; - StringLen = 0; - - // - // Set default help string width. - // - LineWidth = (UINT16) (gHelpBlockWidth - 1); - - // - // Get row number of the String. - // - while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) { - if (StringLen > MaxStringLen) { - MaxStringLen = StringLen; - } - - TotalRowNum ++; - FreePool (OutputString); - } - *EachLineWidth = MaxStringLen; - - *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16)); - ASSERT (*FormattedString != NULL); - - // - // Generate formatted help string array. - // - GlyphWidth = 1; - Index = 0; - while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) { - CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16)); - CheckedNum ++; - FreePool (OutputString); - } - - return TotalRowNum; -} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c index ed904161b6..ba72d1220b 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -26,167 +26,281 @@ SETUP_DRIVER_PRIVATE_DATA mPrivateData = { RegisterHotKey, RegiserExitHandler, SaveReminder + }, + { + BROWSER_EXTENSION2_VERSION_1, + SetScope, + RegisterHotKey, + RegiserExitHandler, + IsBrowserDataModified, + ExecuteAction, } }; EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; -EFI_HII_STRING_PROTOCOL *mHiiString; EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText; +EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay; UINTN gBrowserContextCount = 0; LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList); LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList); LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList); -LIST_ENTRY gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList); +LIST_ENTRY gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList); -BANNER_DATA *gBannerData; -EFI_HII_HANDLE gFrontPageHandle; -UINTN gClassOfVfr; -UINTN gFunctionKeySetting; BOOLEAN gResetRequired; -EFI_HII_HANDLE gHiiHandle; -UINT16 gDirection; -EFI_SCREEN_DESCRIPTOR gScreenDimensions; +BOOLEAN gExitRequired; BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel; BOOLEAN mBrowserScopeFirstSet = TRUE; EXIT_HANDLER ExitHandlerFunction = NULL; -UINTN gFooterHeight; // // Browser Global Strings // -CHAR16 *gSaveFailed; -CHAR16 *gDiscardFailed; -CHAR16 *gDefaultFailed; -CHAR16 *gEnterString; -CHAR16 *gEnterCommitString; -CHAR16 *gEnterEscapeString; -CHAR16 *gEscapeString; -CHAR16 *gMoveHighlight; -CHAR16 *gMakeSelection; -CHAR16 *gDecNumericInput; -CHAR16 *gHexNumericInput; -CHAR16 *gToggleCheckBox; -CHAR16 *gPromptForData; -CHAR16 *gPromptForPassword; -CHAR16 *gPromptForNewPassword; -CHAR16 *gConfirmPassword; -CHAR16 *gConfirmError; -CHAR16 *gPassowordInvalid; -CHAR16 *gPressEnter; CHAR16 *gEmptyString; -CHAR16 *gAreYouSure; -CHAR16 *gYesResponse; -CHAR16 *gNoResponse; -CHAR16 *gMiniString; -CHAR16 *gPlusString; -CHAR16 *gMinusString; -CHAR16 *gAdjustNumber; -CHAR16 *gSaveChanges; -CHAR16 *gOptionMismatch; -CHAR16 *gFormSuppress; -CHAR16 *gProtocolNotFound; - CHAR16 *mUnknownString = L"!"; -CHAR16 gPromptBlockWidth; -CHAR16 gOptionBlockWidth; -CHAR16 gHelpBlockWidth; - EFI_GUID gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; -EFI_GUID gSetupBrowserGuid = { - 0xab368524, 0xb60c, 0x495b, {0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32} -}; -FORM_BROWSER_FORMSET *gOldFormSet = NULL; +extern UINT32 gBrowserStatus; +extern CHAR16 *gErrorInfo; +extern EFI_GUID mCurrentFormSetGuid; +extern EFI_HII_HANDLE mCurrentHiiHandle; +extern UINT16 mCurrentFormId; +extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData; + +/** + Create a menu with specified formset GUID and form ID, and add it as a child + of the given parent menu. + + @param HiiHandle Hii handle related to this formset. + @param FormSetGuid The Formset Guid of menu to be added. + @param FormId The Form ID of menu to be added. + @param QuestionId The question id of this menu to be added. + + @return A pointer to the newly added menu or NULL if memory is insufficient. + +**/ +FORM_ENTRY_INFO * +UiAddMenuList ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid, + IN UINT16 FormId, + IN UINT16 QuestionId + ) +{ + FORM_ENTRY_INFO *MenuList; + + MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO)); + if (MenuList == NULL) { + return NULL; + } + + MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE; + + MenuList->HiiHandle = HiiHandle; + CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); + MenuList->FormId = FormId; + MenuList->QuestionId = QuestionId; -FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = { // - // Boot Manager + // If parent is not specified, it is the root Form of a Formset // - { - { - 0x847bc3fe, - 0xb974, - 0x446d, - { - 0x94, - 0x49, - 0x5a, - 0xd5, - 0x41, - 0x2e, - 0x99, - 0x3b + InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link); + + return MenuList; +} + +/** + Return the form id for the input hiihandle and formset. + + @param HiiHandle HiiHandle for FormSet. + @param FormSetGuid The Formset GUID of the menu to search. + + @return First form's id for this form set. + +**/ +EFI_FORM_ID +GetFirstFormId ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORM *Form; + + Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead); + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + return Form->FormId; +} + +/** + Search Menu with given FormSetGuid and FormId in all cached menu list. + + @param HiiHandle HiiHandle for FormSet. + @param FormSetGuid The Formset GUID of the menu to search. + @param FormId The Form ID of menu to search. + + @return A pointer to menu found or NULL if not found. + +**/ +FORM_ENTRY_INFO * +UiFindMenuList ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid, + IN UINT16 FormId + ) +{ + LIST_ENTRY *Link; + FORM_ENTRY_INFO *MenuList; + FORM_ENTRY_INFO *RetMenu; + EFI_FORM_ID FirstFormId; + + RetMenu = NULL; + + Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead); + while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) { + MenuList = FORM_ENTRY_INFO_FROM_LINK (Link); + Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link); + + // + // If already find the menu, free the menus behind it. + // + if (RetMenu != NULL) { + RemoveEntryList (&MenuList->Link); + FreePool (MenuList); + continue; + } + + // + // Find the same FromSet. + // + if (MenuList->HiiHandle == HiiHandle) { + if (CompareGuid (&MenuList->FormSetGuid, &gZeroGuid)) { + // + // FormSetGuid is not specified. + // + RetMenu = MenuList; + } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) { + if (MenuList->FormId == FormId) { + RetMenu = MenuList; + } else if (FormId == 0 || MenuList->FormId == 0 ) { + FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid); + if ((FormId == 0 && FirstFormId == MenuList->FormId) || (MenuList->FormId ==0 && FirstFormId == FormId)) { + RetMenu = MenuList; + } + } } - }, - NONE_FUNCTION_KEY_SETTING - }, + } + } + + return RetMenu; +} + +/** + Find parent menu for current menu. + + @param CurrentMenu Current Menu + + @retval The parent menu for current menu. +**/ +FORM_ENTRY_INFO * +UiFindParentMenu ( + IN FORM_ENTRY_INFO *CurrentMenu + ) +{ + FORM_ENTRY_INFO *ParentMenu; + + ParentMenu = NULL; + if (CurrentMenu->Link.BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) { + ParentMenu = FORM_ENTRY_INFO_FROM_LINK (CurrentMenu->Link.BackLink); + } + + return ParentMenu; +} + +/** + Free Menu list linked list. + + @param MenuListHead One Menu list point in the menu list. + +**/ +VOID +UiFreeMenuList ( + LIST_ENTRY *MenuListHead + ) +{ + FORM_ENTRY_INFO *MenuList; + + while (!IsListEmpty (MenuListHead)) { + MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink); + RemoveEntryList (&MenuList->Link); + + FreePool (MenuList); + } +} + +/** + Load all hii formset to the browser. + +**/ +VOID +LoadAllHiiFormset ( + VOID + ) +{ + FORM_BROWSER_FORMSET *LocalFormSet; + EFI_HII_HANDLE *HiiHandles; + UINTN Index; + EFI_GUID ZeroGuid; + EFI_STATUS Status; + // - // Device Manager + // Get all the Hii handles // - { - { - 0x3ebfa8e6, - 0x511d, - 0x4b5b, - { - 0xa9, - 0x5f, - 0xfb, - 0x38, - 0x26, - 0xf, - 0x1c, - 0x27 - } - }, - NONE_FUNCTION_KEY_SETTING - }, + HiiHandles = HiiGetHiiHandles (NULL); + ASSERT (HiiHandles != NULL); + // - // BMM FormSet. + // Search for formset of each class type // - { - { - 0x642237c7, - 0x35d4, - 0x472d, - { - 0x83, - 0x65, - 0x12, - 0xe0, - 0xcc, - 0xf2, - 0x7a, - 0x22 - } - }, - NONE_FUNCTION_KEY_SETTING - }, + for (Index = 0; HiiHandles[Index] != NULL; Index++) { + // + // Check HiiHandles[Index] does exist in global maintain list. + // + if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) { + continue; + } + + // + // Initilize FormSet Setting + // + LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); + ASSERT (LocalFormSet != NULL); + ZeroMem (&ZeroGuid, sizeof (ZeroGuid)); + Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet); + if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) { + DestroyFormSet (LocalFormSet); + continue; + } + InitializeCurrentSetting (LocalFormSet); + + // + // Initilize Questions' Value + // + Status = LoadFormSetConfig (NULL, LocalFormSet); + if (EFI_ERROR (Status)) { + DestroyFormSet (LocalFormSet); + continue; + } + } + // - // BMM File Explorer FormSet. + // Free resources, and restore gOldFormSet and gClassOfVfr // - { - { - 0x1f2d63e1, - 0xfebd, - 0x4dc7, - { - 0x9c, - 0xc5, - 0xba, - 0x2b, - 0x1c, - 0xef, - 0x9c, - 0x5b - } - }, - NONE_FUNCTION_KEY_SETTING - }, -}; + FreePool (HiiHandles); +} /** This is the routine which an external caller uses to direct the browser @@ -229,26 +343,14 @@ SendForm ( UI_MENU_SELECTION *Selection; UINTN Index; FORM_BROWSER_FORMSET *FormSet; - LIST_ENTRY *Link; + FORM_ENTRY_INFO *MenuList; // - // Calculate total number of Register HotKeys. + // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED. // - Index = 0; - Link = GetFirstNode (&gBrowserHotKeyList); - while (!IsNull (&gBrowserHotKeyList, Link)) { - Link = GetNextNode (&gBrowserHotKeyList, Link); - Index ++; + if (mFormDisplay == NULL) { + return EFI_UNSUPPORTED; } - // - // Show three HotKeys help information on one ROW. - // - gFooterHeight = FOOTER_HEIGHT + (Index / 3); - - // - // Clean the history menu list. - // - InitializeListHead (&gMenuList); // // Save globals used by SendForm() @@ -256,65 +358,10 @@ SendForm ( SaveBrowserContext (); gResetRequired = FALSE; - Status = EFI_SUCCESS; - ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - - // - // Seed the dimensions in the global - // - gST->ConOut->QueryMode ( - gST->ConOut, - gST->ConOut->Mode->Mode, - &gScreenDimensions.RightColumn, - &gScreenDimensions.BottomRow - ); - - if (ScreenDimensions != NULL) { - // - // Check local dimension vs. global dimension. - // - if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) || - (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow) - ) { - Status = EFI_INVALID_PARAMETER; - goto Done; - } else { - // - // Local dimension validation. - // - if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) && - (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) && - ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) && - ( - (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT + - SCROLL_ARROW_HEIGHT * - 2 + - FRONT_PAGE_HEADER_HEIGHT + - gFooterHeight + - 1 - ) - ) { - CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - } else { - Status = EFI_INVALID_PARAMETER; - goto Done; - } - } - } - - gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3); - gPromptBlockWidth = (CHAR16) (gOptionBlockWidth + LEFT_SKIPPED_COLUMNS); - gHelpBlockWidth = (CHAR16) (gOptionBlockWidth - LEFT_SKIPPED_COLUMNS); - - // - // Initialize the strings for the browser, upon exit of the browser, the strings will be freed - // - InitializeBrowserStrings (); - - // - // Ensure we are in Text mode - // - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gExitRequired = FALSE; + Status = EFI_SUCCESS; + gEmptyString = L""; + gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions; for (Index = 0; Index < HandleCount; Index++) { Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION)); @@ -335,18 +382,13 @@ SendForm ( // // Initialize internal data structures of FormSet // - Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet, TRUE); + Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet); if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) { DestroyFormSet (FormSet); break; } Selection->FormSet = FormSet; - // - // Try to find pre FormSet in the maintain backup list. - // - gOldFormSet = GetFormSetFromHiiHandle (Selection->Handle); - // // Display this formset // @@ -356,27 +398,36 @@ SendForm ( gCurrentSelection = NULL; - if (EFI_ERROR (Status)) { - break; - } - - } while (Selection->Action == UI_ACTION_REFRESH_FORMSET); - - if (gOldFormSet != NULL) { // // If no data is changed, don't need to save current FormSet into the maintain list. // - if (!IsNvUpdateRequired (gOldFormSet)) { - CleanBrowserStorage(gOldFormSet); - RemoveEntryList (&gOldFormSet->Link); - DestroyFormSet (gOldFormSet); + if (!IsNvUpdateRequiredForFormSet (FormSet) && !IsStorageDataChangedForFormSet(FormSet)) { + CleanBrowserStorage(FormSet); + RemoveEntryList (&FormSet->Link); + DestroyFormSet (FormSet); } - gOldFormSet = NULL; - } + + if (EFI_ERROR (Status)) { + break; + } + } while (Selection->Action == UI_ACTION_REFRESH_FORMSET); FreePool (Selection); } + // + // Still has error info, pop up a message. + // + if (gBrowserStatus != BROWSER_SUCCESS) { + gDisplayFormData.BrowserStatus = gBrowserStatus; + gDisplayFormData.ErrorString = gErrorInfo; + + gBrowserStatus = BROWSER_SUCCESS; + gErrorInfo = NULL; + + mFormDisplay->FormDisplay (&gDisplayFormData, NULL); + } + if (ActionRequest != NULL) { *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; if (gResetRequired) { @@ -384,13 +435,17 @@ SendForm ( } } - FreeBrowserStrings (); - UiFreeMenuList(&gMenuList); + mFormDisplay->ExitDisplay(); - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); - gST->ConOut->ClearScreen (gST->ConOut); + // + // Clear the menu history data. + // + while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) { + MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink); + RemoveEntryList (&MenuList->Link); + FreePool (MenuList); + } -Done: // // Restore globals used by SendForm() // @@ -399,10 +454,93 @@ Done: return Status; } +/** + Get or set data to the storage. + + @param ResultsDataSize The size of the buffer associatedwith ResultsData. + @param ResultsData A string returned from an IFR browser or + equivalent. The results string will have no + routing information in them. + @param RetrieveData A BOOLEAN field which allows an agent to retrieve + (if RetrieveData = TRUE) data from the uncommitted + browser state information or set (if RetrieveData + = FALSE) data in the uncommitted browser state + information. + @param Storage The pointer to the storage. + + @retval EFI_SUCCESS The results have been distributed or are awaiting + distribution. + +**/ +EFI_STATUS +ProcessStorage ( + IN OUT UINTN *ResultsDataSize, + IN OUT EFI_STRING *ResultsData, + IN BOOLEAN RetrieveData, + IN BROWSER_STORAGE *Storage + ) +{ + CHAR16 *ConfigResp; + EFI_STATUS Status; + CHAR16 *StrPtr; + UINTN BufferSize; + UINTN TmpSize; + + if (RetrieveData) { + // + // Generate + // + Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Skip and '&' to point to when first copy the configbody. + // Also need to consider add "\0" at first time. + // + StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1; + BufferSize = StrSize (StrPtr); + + + // + // Copy the data if the input buffer is bigger enough. + // + if (*ResultsDataSize >= BufferSize) { + StrCpy (*ResultsData, StrPtr); + } + + *ResultsDataSize = BufferSize; + FreePool (ConfigResp); + } else { + // + // Prepare + // + TmpSize = StrLen (*ResultsData); + BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16); + ConfigResp = AllocateZeroPool (BufferSize); + ASSERT (ConfigResp != NULL); + + StrCpy (ConfigResp, Storage->ConfigHdr); + StrCat (ConfigResp, L"&"); + StrCat (ConfigResp, *ResultsData); + + // + // Update Browser uncommited data + // + Status = ConfigRespToStorage (Storage, ConfigResp); + FreePool (ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} /** - This function is called by a callback handler to retrieve uncommitted state - data from the browser. + This routine called this service in the browser to retrieve or set certain uncommitted + state information that resides in the open formsets. @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL instance. @@ -440,60 +578,69 @@ BrowserCallback ( { EFI_STATUS Status; LIST_ENTRY *Link; - FORMSET_STORAGE *Storage; + BROWSER_STORAGE *Storage; + FORMSET_STORAGE *FormsetStorage; FORM_BROWSER_FORMSET *FormSet; + UINTN TotalSize; BOOLEAN Found; - CHAR16 *ConfigResp; - CHAR16 *StrPtr; - UINTN BufferSize; - UINTN TmpSize; if (ResultsDataSize == NULL || ResultsData == NULL) { return EFI_INVALID_PARAMETER; } - if (gCurrentSelection == NULL) { - return EFI_NOT_READY; - } - - Storage = NULL; - ConfigResp = NULL; - FormSet = gCurrentSelection->FormSet; + TotalSize = *ResultsDataSize; + Storage = NULL; + Found = FALSE; + Status = EFI_SUCCESS; // - // Find target storage + // If set browser data, pre load all hii formset to avoid set the varstore which is not + // saved in browser. // - Link = GetFirstNode (&FormSet->StorageListHead); - if (IsNull (&FormSet->StorageListHead, Link)) { - return EFI_UNSUPPORTED; + if (!RetrieveData && (gBrowserSettingScope == SystemLevel)) { + LoadAllHiiFormset(); } if (VariableGuid != NULL) { // - // Try to find target storage + // Try to find target storage in the current formset. // - Found = FALSE; - while (!IsNull (&FormSet->StorageListHead, Link)) { - Storage = FORMSET_STORAGE_FROM_LINK (Link); - Link = GetNextNode (&FormSet->StorageListHead, Link); + Link = GetFirstNode (&gBrowserStorageList); + while (!IsNull (&gBrowserStorageList, Link)) { + Storage = BROWSER_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&gBrowserStorageList, Link); + // + // Check the current storage. + // + if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) { + continue; + } - if (CompareGuid (&Storage->BrowserStorage->Guid, (EFI_GUID *) VariableGuid)) { - if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER || - Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { - // - // Buffer storage require both GUID and Name - // - if (VariableName == NULL) { - return EFI_NOT_FOUND; - } + if (Storage->Type == EFI_HII_VARSTORE_BUFFER || + Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { + // + // Buffer storage require both GUID and Name + // + if (VariableName == NULL) { + return EFI_NOT_FOUND; + } - if (StrCmp (Storage->BrowserStorage->Name, (CHAR16 *) VariableName) != 0) { - continue; - } + if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) { + continue; } - Found = TRUE; - break; } + + Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Different formsets may have same varstore, so here just set the flag + // not exit the circle. + // + Found = TRUE; + break; } if (!Found) { @@ -503,65 +650,62 @@ BrowserCallback ( // // GUID/Name is not specified, take the first storage in FormSet // - Storage = FORMSET_STORAGE_FROM_LINK (Link); - } - - if (RetrieveData) { - // - // Skip if there is no RequestElement - // - if (Storage->ElementCount == 0) { - return EFI_SUCCESS; + if (gCurrentSelection == NULL) { + return EFI_NOT_READY; } // // Generate // - Status = StorageToConfigResp (Storage->BrowserStorage, &ConfigResp, Storage->ConfigRequest); + FormSet = gCurrentSelection->FormSet; + Link = GetFirstNode (&FormSet->StorageListHead); + if (IsNull (&FormSet->StorageListHead, Link)) { + return EFI_UNSUPPORTED; + } + + FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link); + + Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage); if (EFI_ERROR (Status)) { return Status; } + } - // - // Skip and '&' to point to - // - StrPtr = ConfigResp + StrLen (Storage->BrowserStorage->ConfigHdr) + 1; + if (RetrieveData) { + Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL; + *ResultsDataSize = TotalSize; + } + + return Status; - BufferSize = StrSize (StrPtr); - if (*ResultsDataSize < BufferSize) { - *ResultsDataSize = BufferSize; +} - FreePool (ConfigResp); - return EFI_BUFFER_TOO_SMALL; - } - *ResultsDataSize = BufferSize; - CopyMem (ResultsData, StrPtr, BufferSize); +/** + Callback function for SimpleTextInEx protocol install events - FreePool (ConfigResp); - } else { - // - // Prepare - // - TmpSize = StrLen (ResultsData); - BufferSize = (TmpSize + StrLen (Storage->BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16); - ConfigResp = AllocateZeroPool (BufferSize); - ASSERT (ConfigResp != NULL); + @param Event the event that is signaled. + @param Context not used here. - StrCpy (ConfigResp, Storage->BrowserStorage->ConfigHdr); - StrCat (ConfigResp, L"&"); - StrCat (ConfigResp, ResultsData); +**/ +VOID +EFIAPI +FormDisplayCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; - // - // Update Browser uncommited data - // - Status = ConfigRespToStorage (Storage->BrowserStorage, ConfigResp); - if (EFI_ERROR (Status)) { - return Status; - } + if (mFormDisplay != NULL) { + return; } - return EFI_SUCCESS; + Status = gBS->LocateProtocol ( + &gEdkiiFormDisplayEngineProtocolGuid, + NULL, + (VOID **) &mFormDisplay + ); } /** @@ -582,8 +726,7 @@ InitializeSetup ( ) { EFI_STATUS Status; - EFI_INPUT_KEY DefaultHotKey; - EFI_STRING HelpString; + VOID *Registration; // // Locate required Hii relative protocols @@ -595,13 +738,6 @@ InitializeSetup ( ); ASSERT_EFI_ERROR (Status); - Status = gBS->LocateProtocol ( - &gEfiHiiStringProtocolGuid, - NULL, - (VOID **) &mHiiString - ); - ASSERT_EFI_ERROR (Status); - Status = gBS->LocateProtocol ( &gEfiHiiConfigRoutingProtocolGuid, NULL, @@ -615,30 +751,6 @@ InitializeSetup ( (VOID **) &mPathFromText ); - // - // Publish our HII data - // - gHiiHandle = HiiAddPackages ( - &gSetupBrowserGuid, - ImageHandle, - SetupBrowserStrings, - NULL - ); - ASSERT (gHiiHandle != NULL); - - // - // Initialize Driver private data - // - gBannerData = AllocateZeroPool (sizeof (BANNER_DATA)); - ASSERT (gBannerData != NULL); - - // - // Initialize generic help strings. - // - gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle); - gDiscardFailed = GetToken (STRING_TOKEN (DISCARD_FAILED), gHiiHandle); - gDefaultFailed = GetToken (STRING_TOKEN (DEFAULT_FAILED), gHiiHandle); - // // Install FormBrowser2 protocol // @@ -652,25 +764,18 @@ InitializeSetup ( ASSERT_EFI_ERROR (Status); // - // Install default HotKey F10 for Save - // - DefaultHotKey.UnicodeChar = CHAR_NULL; - HelpString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle); - DefaultHotKey.ScanCode = SCAN_F10; - RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_SUBMIT, 0, HelpString); - FreePool (HelpString); - // - // Install default HotKey F9 for Reset To Defaults - // - DefaultHotKey.ScanCode = SCAN_F9; - HelpString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle); - RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, HelpString); - FreePool (HelpString); - - // - // Install FormBrowserEx protocol + // Install FormBrowserEx2 protocol // + InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead); mPrivateData.Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEdkiiFormBrowserEx2ProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.FormBrowserEx2 + ); + ASSERT_EFI_ERROR (Status); + Status = gBS->InstallProtocolInterface ( &mPrivateData.Handle, &gEfiFormBrowserExProtocolGuid, @@ -679,7 +784,25 @@ InitializeSetup ( ); ASSERT_EFI_ERROR (Status); - return Status; + InitializeDisplayFormData (); + + Status = gBS->LocateProtocol ( + &gEdkiiFormDisplayEngineProtocolGuid, + NULL, + (VOID **) &mFormDisplay + ); + + if (EFI_ERROR (Status)) { + EfiCreateProtocolNotifyEvent ( + &gEdkiiFormDisplayEngineProtocolGuid, + TPL_CALLBACK, + FormDisplayCallback, + NULL, + &Registration + ); + } + + return EFI_SUCCESS; } @@ -815,58 +938,6 @@ NewStringCat ( *Dest = NewString; } - -/** - Synchronize or restore Storage's Edit copy and Shadow copy. - - @param Storage The Storage to be synchronized. - @param SyncOrRestore Sync the buffer to editbuffer or Restore the - editbuffer to buffer - if TRUE, copy the editbuffer to the buffer. - if FALSE, copy the buffer to the editbuffer. - -**/ -VOID -SynchronizeStorage ( - IN BROWSER_STORAGE *Storage, - IN BOOLEAN SyncOrRestore - ) -{ - LIST_ENTRY *Link; - NAME_VALUE_NODE *Node; - - switch (Storage->Type) { - case EFI_HII_VARSTORE_BUFFER: - case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: - if (SyncOrRestore) { - CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size); - } else { - CopyMem (Storage->EditBuffer, Storage->Buffer, Storage->Size); - } - break; - - case EFI_HII_VARSTORE_NAME_VALUE: - Link = GetFirstNode (&Storage->NameValueListHead); - while (!IsNull (&Storage->NameValueListHead, Link)) { - Node = NAME_VALUE_NODE_FROM_LINK (Link); - - if (SyncOrRestore) { - NewStringCpy (&Node->Value, Node->EditValue); - } else { - NewStringCpy (&Node->EditValue, Node->Value); - } - - Link = GetNextNode (&Storage->NameValueListHead, Link); - } - break; - - case EFI_HII_VARSTORE_EFI_VARIABLE: - default: - break; - } -} - - /** Get Value for given Name from a NameValue Storage. @@ -923,6 +994,7 @@ GetValueByName ( @param Name The Name. @param Value The Value to set. @param SetValueTo Whether update editValue or Value. + @param ReturnNode The node use the input name. @retval EFI_SUCCESS Value found for given Name. @retval EFI_NOT_FOUND No such Name found in NameValue storage. @@ -930,10 +1002,11 @@ GetValueByName ( **/ EFI_STATUS SetValueByName ( - IN BROWSER_STORAGE *Storage, - IN CHAR16 *Name, - IN CHAR16 *Value, - IN GET_SET_QUESTION_VALUE_WITH SetValueTo + IN BROWSER_STORAGE *Storage, + IN CHAR16 *Name, + IN CHAR16 *Value, + IN GET_SET_QUESTION_VALUE_WITH SetValueTo, + OUT NAME_VALUE_NODE **ReturnNode ) { LIST_ENTRY *Link; @@ -964,6 +1037,11 @@ SetValueByName ( } else { Node->Value = Buffer; } + + if (ReturnNode != NULL) { + *ReturnNode = Node; + } + return EFI_SUCCESS; } @@ -980,6 +1058,7 @@ SetValueByName ( @param Storage The Storage to be conveted. @param ConfigResp The returned . @param ConfigRequest The ConfigRequest string. + @param GetEditBuf Get the data from editbuffer or buffer. @retval EFI_SUCCESS Convert success. @retval EFI_INVALID_PARAMETER Incorrect storage type. @@ -989,23 +1068,26 @@ EFI_STATUS StorageToConfigResp ( IN BROWSER_STORAGE *Storage, IN CHAR16 **ConfigResp, - IN CHAR16 *ConfigRequest + IN CHAR16 *ConfigRequest, + IN BOOLEAN GetEditBuf ) { EFI_STATUS Status; EFI_STRING Progress; LIST_ENTRY *Link; NAME_VALUE_NODE *Node; + UINT8 *SourceBuf; Status = EFI_SUCCESS; switch (Storage->Type) { case EFI_HII_VARSTORE_BUFFER: case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: + SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer; Status = mHiiConfigRouting->BlockToConfig ( mHiiConfigRouting, ConfigRequest, - Storage->EditBuffer, + SourceBuf, Storage->Size, ConfigResp, &Progress @@ -1024,7 +1106,11 @@ StorageToConfigResp ( NewStringCat (ConfigResp, L"&"); NewStringCat (ConfigResp, Node->Name); NewStringCat (ConfigResp, L"="); - NewStringCat (ConfigResp, Node->EditValue); + if (GetEditBuf) { + NewStringCat (ConfigResp, Node->EditValue); + } else { + NewStringCat (ConfigResp, Node->Value); + } } Link = GetNextNode (&Storage->NameValueListHead, Link); } @@ -1105,7 +1191,7 @@ ConfigRespToStorage ( if (StrPtr != NULL) { *StrPtr = 0; } - SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer); + SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL); } break; @@ -1531,7 +1617,7 @@ GetQuestionValue ( if (IsBufferStorage) { CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth); } else { - SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer); + SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL); } if (Result != NULL) { @@ -1581,8 +1667,10 @@ SetQuestionValue ( CHAR16 *TemName; CHAR16 *TemString; UINTN Index; + NAME_VALUE_NODE *Node; Status = EFI_SUCCESS; + Node = NULL; if (SetValueTo >= GetSetValueWithMax) { return EFI_INVALID_PARAMETER; @@ -1717,6 +1805,14 @@ SetQuestionValue ( // CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); } + // + // Check whether question value has been changed. + // + if (CompareMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth) != 0) { + Question->ValueChanged = TRUE; + } else { + Question->ValueChanged = FALSE; + } } else { if (IsString) { // @@ -1748,8 +1844,19 @@ SetQuestionValue ( } } - Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo); + Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node); FreePool (Value); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Check whether question value has been changed. + // + if (StrCmp (Node->Value, Node->EditValue) != 0) { + Question->ValueChanged = TRUE; + } else { + Question->ValueChanged = FALSE; + } } } else if (SetValueTo == GetSetValueWithHiiDriver) { if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { @@ -1868,12 +1975,12 @@ SetQuestionValue ( /** - Perform inconsistent check for a Form. + Perform nosubmitif check for a Form. @param FormSet FormSet data structure. @param Form Form data structure. @param Question The Question to be validated. - @param Type Validation type: InConsistent or NoSubmit + @param Type Validation type: NoSubmit @retval EFI_SUCCESS Form validation pass. @retval other Form validation failed. @@ -1891,12 +1998,9 @@ ValidateQuestion ( LIST_ENTRY *Link; LIST_ENTRY *ListHead; EFI_STRING PopUp; - EFI_INPUT_KEY Key; FORM_EXPRESSION *Expression; - if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) { - ListHead = &Question->InconsistentListHead; - } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { + if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { ListHead = &Question->NoSubmitListHead; } else { return EFI_UNSUPPORTED; @@ -1920,10 +2024,10 @@ ValidateQuestion ( // if (Expression->Error != 0) { PopUp = GetToken (Expression->Error, FormSet->HiiHandle); - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - FreePool (PopUp); + if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { + gBrowserStatus = BROWSER_NO_SUBMIT_IF; + gErrorInfo = PopUp; + } } return EFI_NOT_READY; @@ -1987,7 +2091,8 @@ NoSubmitCheck ( Fill storage's edit copy with settings requested from Configuration Driver. @param FormSet FormSet data structure. - @param ConfigInfo The config info related to this form. + @param Storage The storage which need to sync. + @param ConfigRequest The config request string which used to sync storage. @param SyncOrRestore Sync the buffer to editbuffer or Restore the editbuffer to buffer if TRUE, copy the editbuffer to the buffer. @@ -1997,10 +2102,11 @@ NoSubmitCheck ( **/ EFI_STATUS -SynchronizeStorageForForm ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_CONFIG_REQUEST *ConfigInfo, - IN BOOLEAN SyncOrRestore +SynchronizeStorage ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT BROWSER_STORAGE *Storage, + IN CHAR16 *ConfigRequest, + IN BOOLEAN SyncOrRestore ) { EFI_STATUS Status; @@ -2014,57 +2120,52 @@ SynchronizeStorageForForm ( Status = EFI_SUCCESS; Result = NULL; - if (FormSet->ConfigAccess == NULL && ConfigInfo->Storage->Type != EFI_HII_VARSTORE_NAME_VALUE) { - return EFI_NOT_FOUND; - } - - if (ConfigInfo->ElementCount == 0) { - // - // Skip if there is no RequestElement - // - return EFI_SUCCESS; - } - if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_BUFFER || - (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { - BufferSize = ConfigInfo->Storage->Size; + if (Storage->Type == EFI_HII_VARSTORE_BUFFER || + (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { + BufferSize = Storage->Size; if (SyncOrRestore) { - Src = ConfigInfo->Storage->EditBuffer; - Dst = ConfigInfo->Storage->Buffer; + Src = Storage->EditBuffer; + Dst = Storage->Buffer; } else { - Src = ConfigInfo->Storage->Buffer; - Dst = ConfigInfo->Storage->EditBuffer; + Src = Storage->Buffer; + Dst = Storage->EditBuffer; } - Status = mHiiConfigRouting->BlockToConfig( - mHiiConfigRouting, - ConfigInfo->ConfigRequest, - Src, - BufferSize, - &Result, - &Progress - ); - if (EFI_ERROR (Status)) { - return Status; - } + if (ConfigRequest != NULL) { + Status = mHiiConfigRouting->BlockToConfig( + mHiiConfigRouting, + ConfigRequest, + Src, + BufferSize, + &Result, + &Progress + ); + if (EFI_ERROR (Status)) { + return Status; + } - Status = mHiiConfigRouting->ConfigToBlock ( - mHiiConfigRouting, - Result, - Dst, - &BufferSize, - &Progress - ); - if (Result != NULL) { - FreePool (Result); + Status = mHiiConfigRouting->ConfigToBlock ( + mHiiConfigRouting, + Result, + Dst, + &BufferSize, + &Progress + ); + if (Result != NULL) { + FreePool (Result); + } + } else { + CopyMem (Dst, Src, BufferSize); } - } else if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { - Link = GetFirstNode (&ConfigInfo->Storage->NameValueListHead); - while (!IsNull (&ConfigInfo->Storage->NameValueListHead, Link)) { + } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { Node = NAME_VALUE_NODE_FROM_LINK (Link); - if (StrStr (ConfigInfo->ConfigRequest, Node->Name) != NULL) { + if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) || + (ConfigRequest == NULL)) { if (SyncOrRestore) { NewStringCpy (&Node->Value, Node->EditValue); } else { @@ -2072,7 +2173,7 @@ SynchronizeStorageForForm ( } } - Link = GetNextNode (&ConfigInfo->Storage->NameValueListHead, Link); + Link = GetNextNode (&Storage->NameValueListHead, Link); } } @@ -2095,20 +2196,9 @@ SendDiscardInfoToDriver ( { LIST_ENTRY *Link; FORM_BROWSER_STATEMENT *Question; - EFI_STATUS Status; - EFI_HII_VALUE HiiValue; - UINT8 *BufferValue; - BOOLEAN ValueChanged; EFI_IFR_TYPE_VALUE *TypeValue; EFI_BROWSER_ACTION_REQUEST ActionRequest; - ValueChanged = FALSE; - BufferValue = NULL; - - if(!Form->NvUpdateRequired) { - return; - } - Link = GetFirstNode (&Form->StatementListHead); while (!IsNull (&Form->StatementListHead, Link)) { Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); @@ -2122,45 +2212,10 @@ SendDiscardInfoToDriver ( continue; } - if (Question->BufferValue != NULL) { - BufferValue = AllocateZeroPool (Question->StorageWidth); - ASSERT (BufferValue != NULL); - CopyMem (BufferValue, Question->BufferValue, Question->StorageWidth); - } else { - HiiValue.Type = Question->HiiValue.Type; - CopyMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE)); - } - - Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer); - if (EFI_ERROR (Status)) { - if (BufferValue != NULL) { - FreePool (BufferValue); - BufferValue = NULL; - } - continue; - } - - if (Question->BufferValue != NULL) { - if (CompareMem (BufferValue, Question->BufferValue, Question->StorageWidth)) { - ValueChanged = TRUE; - } - } else { - if (CompareMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE))) { - ValueChanged = TRUE; - } - } - - if (BufferValue != NULL) { - FreePool (BufferValue); - BufferValue = NULL; - } - - if (!ValueChanged) { + if (!Question->ValueChanged) { continue; } - ValueChanged = FALSE; - if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) { TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue; } else { @@ -2225,6 +2280,78 @@ ValidateFormSet ( return Find; } +/** + Check whether need to enable the reset flag in form level. + Also clean all ValueChanged flag in question. + + @param SetFlag Whether need to set the Reset Flag. + @param Form Form data structure. + +**/ +VOID +UpdateFlagForForm ( + IN BOOLEAN SetFlag, + IN FORM_BROWSER_FORM *Form + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + BOOLEAN FindOne; + + FindOne = FALSE; + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (SetFlag && Question->ValueChanged && ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) { + gResetRequired = TRUE; + } + + if (Question->ValueChanged) { + Question->ValueChanged = FALSE; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } +} + +/** + Check whether need to enable the reset flag. + Also clean ValueChanged flag for all statements. + + Form level or formset level, only one. + + @param SetFlag Whether need to set the Reset Flag. + @param FormSet FormSet data structure. + @param Form Form data structure. + +**/ +VOID +ValueChangeResetFlagUpdate ( + IN BOOLEAN SetFlag, + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + FORM_BROWSER_FORM *CurrentForm; + LIST_ENTRY *Link; + + // + // Form != NULL means only check form level. + // + if (Form != NULL) { + UpdateFlagForForm(SetFlag, Form); + return; + } + + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link); + Link = GetNextNode (&FormSet->FormListHead, Link); + + UpdateFlagForForm(SetFlag, CurrentForm); + } +} /** Discard data based on the input setting scope (Form, FormSet or System). @@ -2256,7 +2383,7 @@ DiscardForm ( return EFI_UNSUPPORTED; } - if (SettingScope == FormLevel && Form->NvUpdateRequired) { + if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) { ConfigInfo = NULL; Link = GetFirstNode (&Form->ConfigRequestHead); while (!IsNull (&Form->ConfigRequestHead, Link)) { @@ -2277,7 +2404,7 @@ DiscardForm ( // // Prepare // - SynchronizeStorageForForm(FormSet, ConfigInfo, FALSE); + SynchronizeStorage(FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE); // // Call callback with Changed type to inform the driver. @@ -2285,8 +2412,8 @@ DiscardForm ( SendDiscardInfoToDriver (FormSet, Form); } - Form->NvUpdateRequired = FALSE; - } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) { + ValueChangeResetFlagUpdate (FALSE, NULL, Form); + } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) { // // Discard Buffer storage or Name/Value storage @@ -2307,7 +2434,7 @@ DiscardForm ( continue; } - SynchronizeStorage(Storage->BrowserStorage, FALSE); + SynchronizeStorage(FormSet, Storage->BrowserStorage, Storage->ConfigRequest, FALSE); } Link = GetFirstNode (&FormSet->FormListHead); @@ -2321,7 +2448,7 @@ DiscardForm ( SendDiscardInfoToDriver (FormSet, Form); } - UpdateNvInfoInForm (FormSet, FALSE); + ValueChangeResetFlagUpdate(FALSE, FormSet, NULL); } else if (SettingScope == SystemLevel) { // // System Level Discard. @@ -2401,7 +2528,7 @@ SubmitForm ( return Status; } - if (SettingScope == FormLevel && Form->NvUpdateRequired) { + if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) { ConfigInfo = NULL; Link = GetFirstNode (&Form->ConfigRequestHead); while (!IsNull (&Form->ConfigRequestHead, Link)) { @@ -2423,7 +2550,7 @@ SubmitForm ( // // 1. Prepare // - Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest); + Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE); if (EFI_ERROR (Status)) { return Status; } @@ -2499,14 +2626,14 @@ SubmitForm ( // // 3. Config success, update storage shadow Buffer, only update the data belong to this form. // - SynchronizeStorageForForm(FormSet, ConfigInfo, TRUE); + SynchronizeStorage (FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE); } // // 4. Update the NV flag. // - Form->NvUpdateRequired = FALSE; - } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) { + ValueChangeResetFlagUpdate(TRUE, NULL, Form); + } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) { // // Submit Buffer storage or Name/Value storage // @@ -2530,7 +2657,7 @@ SubmitForm ( // // 1. Prepare // - Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest); + Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE); if (EFI_ERROR (Status)) { return Status; } @@ -2602,13 +2729,13 @@ SubmitForm ( // // 3. Config success, update storage shadow Buffer // - SynchronizeStorage (Storage, TRUE); + SynchronizeStorage (FormSet, Storage, FormSetStorage->ConfigRequest, TRUE); } // // 4. Update the NV flag. // - UpdateNvInfoInForm (FormSet, FALSE); + ValueChangeResetFlagUpdate(TRUE, FormSet, NULL); } else if (SettingScope == SystemLevel) { // // System Level Save. @@ -2818,52 +2945,184 @@ GetDefaultValueFromAltCfg ( } } -Done: - if (ConfigRequest != NULL){ - FreePool (ConfigRequest); - } +Done: + if (ConfigRequest != NULL){ + FreePool (ConfigRequest); + } + + if (ConfigResp != NULL) { + FreePool (ConfigResp); + } + + if (Result != NULL) { + FreePool (Result); + } + + return Status; +} + +/** + Get default Id value used for browser. + + @param DefaultId The default id value used by hii. + + @retval Browser used default value. + +**/ +INTN +GetDefaultIdForCallBack ( + UINTN DefaultId + ) +{ + if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) { + return EFI_BROWSER_ACTION_DEFAULT_STANDARD; + } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING; + } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) { + return EFI_BROWSER_ACTION_DEFAULT_SAFE; + } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) { + return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN; + } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) { + return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN; + } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) { + return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN; + } else { + return -1; + } +} + + + +/** + Return data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + + @retval Value The data to be returned + +**/ +UINT64 +GetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index + ) +{ + UINT64 Data; + + ASSERT (Array != NULL); + + Data = 0; + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Data = (UINT64) *(((UINT8 *) Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Data = (UINT64) *(((UINT16 *) Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Data = (UINT64) *(((UINT32 *) Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + Data = (UINT64) *(((UINT64 *) Array) + Index); + break; + + default: + break; + } + + return Data; +} + + +/** + Set value of a data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + @param Value The value to be set. - if (ConfigResp != NULL) { - FreePool (ConfigResp); - } - - if (Result != NULL) { - FreePool (Result); - } +**/ +VOID +SetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index, + IN UINT64 Value + ) +{ - return Status; + ASSERT (Array != NULL); + + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + *(((UINT8 *) Array) + Index) = (UINT8) Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + *(((UINT16 *) Array) + Index) = (UINT16) Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + *(((UINT32 *) Array) + Index) = (UINT32) Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + *(((UINT64 *) Array) + Index) = (UINT64) Value; + break; + + default: + break; + } } /** - Get default Id value used for browser. + Search an Option of a Question by its value. - @param DefaultId The default id value used by hii. + @param Question The Question + @param OptionValue Value for Option to be searched. - @retval Browser used default value. + @retval Pointer Pointer to the found Option. + @retval NULL Option not found. **/ -INTN -GetDefaultIdForCallBack ( - UINTN DefaultId +QUESTION_OPTION * +ValueToOption ( + IN FORM_BROWSER_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue ) -{ - if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) { - return EFI_BROWSER_ACTION_DEFAULT_STANDARD; - } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) { - return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING; - } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) { - return EFI_BROWSER_ACTION_DEFAULT_SAFE; - } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) { - return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN; - } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) { - return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN; - } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) { - return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN; - } else { - return -1; +{ + LIST_ENTRY *Link; + QUESTION_OPTION *Option; + INTN Result; + + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { + // + // Check the suppressif condition, only a valid option can be return. + // + if ((Option->SuppressExpression == NULL) || + ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) { + return Option; + } + } + + Link = GetNextNode (&Question->OptionListHead, Link); } + + return NULL; } + /** Reset Question to its default value. @@ -3155,11 +3414,7 @@ ExtractDefault ( LIST_ENTRY *FormLink; LIST_ENTRY *Link; FORM_BROWSER_STATEMENT *Question; - FORM_BROWSER_FORMSET *BackUpFormSet; FORM_BROWSER_FORMSET *LocalFormSet; - EFI_HII_HANDLE *HiiHandles; - UINTN Index; - EFI_GUID ZeroGuid; Status = EFI_SUCCESS; @@ -3229,10 +3484,6 @@ ExtractDefault ( if ((Question->Storage != NULL) && (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) { SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); - // - // Update Form NV flag. - // - Form->NvUpdateRequired = TRUE; } } } else if (SettingScope == FormSetLevel) { @@ -3244,65 +3495,9 @@ ExtractDefault ( } } else if (SettingScope == SystemLevel) { // - // Open all FormSet by locate HII packages. - // Initiliaze the maintain FormSet to store default data as back up data. - // - BackUpFormSet = gOldFormSet; - gOldFormSet = NULL; - - // - // Get all the Hii handles - // - HiiHandles = HiiGetHiiHandles (NULL); - ASSERT (HiiHandles != NULL); - - // - // Search for formset of each class type - // - for (Index = 0; HiiHandles[Index] != NULL; Index++) { - // - // Check HiiHandles[Index] does exist in global maintain list. - // - if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) { - continue; - } - - // - // Initilize FormSet Setting - // - LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); - ASSERT (LocalFormSet != NULL); - ZeroMem (&ZeroGuid, sizeof (ZeroGuid)); - Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet, FALSE); - if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) { - DestroyFormSet (LocalFormSet); - continue; - } - Status = InitializeCurrentSetting (LocalFormSet); - if (EFI_ERROR (Status)) { - DestroyFormSet (LocalFormSet); - continue; - } - // - // Initilize Questions' Value - // - Status = LoadFormSetConfig (NULL, LocalFormSet); - if (EFI_ERROR (Status)) { - DestroyFormSet (LocalFormSet); - continue; - } - - // - // Add FormSet into the maintain list. - // - InsertTailList (&gBrowserFormSetList, &LocalFormSet->Link); - } - - // - // Free resources, and restore gOldFormSet and gClassOfVfr + // Preload all Hii formset. // - FreePool (HiiHandles); - gOldFormSet = BackUpFormSet; + LoadAllHiiFormset(); // // Set Default Value for each FormSet in the maintain list. @@ -3321,6 +3516,81 @@ ExtractDefault ( return EFI_SUCCESS; } + +/** + Validate whether this question's value has changed. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Question to be initialized. + @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver. + + @retval TRUE Question's value has changed. + @retval FALSE Question's value has not changed + +**/ +BOOLEAN +IsQuestionValueChanged ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN GET_SET_QUESTION_VALUE_WITH GetValueFrom + ) +{ + EFI_HII_VALUE BackUpValue; + CHAR8 *BackUpBuffer; + EFI_STATUS Status; + BOOLEAN ValueChanged; + UINTN BufferWidth; + + // + // For quetion without storage, always mark it as data not changed. + // + if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) { + return FALSE; + } + + BackUpBuffer = NULL; + ValueChanged = FALSE; + + switch (Question->Operand) { + case EFI_IFR_ORDERED_LIST_OP: + BufferWidth = Question->StorageWidth; + BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue); + ASSERT (BackUpBuffer != NULL); + break; + + case EFI_IFR_STRING_OP: + case EFI_IFR_PASSWORD_OP: + BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16); + BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue); + ASSERT (BackUpBuffer != NULL); + break; + + default: + BufferWidth = 0; + break; + } + CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)); + + Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom); + ASSERT_EFI_ERROR(Status); + + if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 || + CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) { + ValueChanged = TRUE; + } + + CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE)); + CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth); + + if (BackUpBuffer != NULL) { + FreePool (BackUpBuffer); + } + + return ValueChanged; +} + /** Initialize Question's Edit copy from Storage. @@ -3354,7 +3624,11 @@ LoadFormConfig ( // // Initialize local copy of Value for each Question // - Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); + if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) { + Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver); + } else { + Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); + } if (EFI_ERROR (Status)) { return Status; } @@ -3394,6 +3668,11 @@ LoadFormConfig ( Status = ProcessCallBackFunction(Selection, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE); } + // + // Update Question Value changed flag. + // + Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer); + Link = GetNextNode (&Form->StatementListHead, Link); } @@ -3437,6 +3716,11 @@ LoadFormSetConfig ( Link = GetNextNode (&FormSet->FormListHead, Link); } + // + // Finished question initialization. + // + FormSet->QuestionInited = TRUE; + return EFI_SUCCESS; } @@ -3491,6 +3775,13 @@ RemoveConfigRequest ( CHAR16 *NextRequestElement; CHAR16 *SearchKey; + // + // No request element in it, just return. + // + if (ConfigRequest == NULL) { + return; + } + if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { // // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage @@ -3565,6 +3856,7 @@ CleanBrowserStorage ( { LIST_ENTRY *Link; FORMSET_STORAGE *Storage; + CHAR16 *ConfigRequest; Link = GetFirstNode (&FormSet->StorageListHead); while (!IsNull (&FormSet->StorageListHead, Link)) { @@ -3572,7 +3864,8 @@ CleanBrowserStorage ( Link = GetNextNode (&FormSet->StorageListHead, Link); if ((Storage->BrowserStorage->Type != EFI_HII_VARSTORE_BUFFER) && - (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE)) { + (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) && + (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { continue; } @@ -3580,7 +3873,8 @@ CleanBrowserStorage ( continue; } - RemoveConfigRequest (Storage->BrowserStorage, Storage->ConfigRequest); + ConfigRequest = FormSet->QuestionInited ? Storage->ConfigRequest : Storage->ConfigElements; + RemoveConfigRequest (Storage->BrowserStorage, ConfigRequest); } } @@ -3651,7 +3945,6 @@ AppendConfigRequest ( Adjust the config request info, remove the request elements which already in AllConfigRequest string. @param Storage Form set Storage. - @param ConfigRequest Return the ConfigRequest info. @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig @retval FALSE All elements covered by current used elements. @@ -3659,8 +3952,7 @@ AppendConfigRequest ( **/ BOOLEAN ConfigRequestAdjust ( - IN FORMSET_STORAGE *Storage, - OUT CHAR16 **ConfigRequest + IN FORMSET_STORAGE *Storage ) { CHAR16 *RequestElement; @@ -3676,7 +3968,10 @@ ConfigRequestAdjust ( if (Storage->BrowserStorage->ConfigRequest == NULL) { Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest); - *ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest); + if (Storage->ConfigElements != NULL) { + FreePool (Storage->ConfigElements); + } + Storage->ConfigElements = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest); return TRUE; } @@ -3745,7 +4040,10 @@ ConfigRequestAdjust ( } if (RetVal) { - *ConfigRequest = RetBuf; + if (Storage->ConfigElements != NULL) { + FreePool (Storage->ConfigElements); + } + Storage->ConfigElements = RetBuf; } else { FreePool (RetBuf); } @@ -3753,16 +4051,163 @@ ConfigRequestAdjust ( return RetVal; } +/** + + Base on ConfigRequest info to get default value for current formset. + + ConfigRequest info include the info about which questions in current formset need to + get default value. This function only get these questions default value. + + @param FormSet FormSet data structure. + @param Storage Storage need to update value. + @param ConfigRequest The config request string. + +**/ +VOID +GetDefaultForFormset ( + IN FORM_BROWSER_FORMSET *FormSet, + IN BROWSER_STORAGE *Storage, + IN CHAR16 *ConfigRequest + ) +{ + UINT8 *BackUpBuf; + UINTN BufferSize; + LIST_ENTRY BackUpList; + NAME_VALUE_NODE *Node; + LIST_ENTRY *Link; + LIST_ENTRY *NodeLink; + NAME_VALUE_NODE *TmpNode; + EFI_STATUS Status; + EFI_STRING Progress; + EFI_STRING Result; + + BackUpBuf = NULL; + InitializeListHead(&BackUpList); + + // + // Back update the edit buffer. + // + if (Storage->Type == EFI_HII_VARSTORE_BUFFER || + (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { + BackUpBuf = AllocateCopyPool (Storage->Size, Storage->EditBuffer); + ASSERT (BackUpBuf != NULL); + } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + Link = GetNextNode (&Storage->NameValueListHead, Link); + + // + // Only back Node belong to this formset. + // + if (StrStr (Storage->ConfigRequest, Node->Name) == NULL) { + continue; + } + + TmpNode = AllocateCopyPool (sizeof (NAME_VALUE_NODE), Node); + TmpNode->Name = AllocateCopyPool (StrSize(Node->Name) * sizeof (CHAR16), Node->Name); + TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue); + + InsertTailList(&BackUpList, &TmpNode->Link); + } + } + + // + // Get default value. + // + ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE); + + // + // Update the question value based on the input ConfigRequest. + // + if (Storage->Type == EFI_HII_VARSTORE_BUFFER || + (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { + ASSERT (BackUpBuf != NULL); + BufferSize = Storage->Size; + Status = mHiiConfigRouting->BlockToConfig( + mHiiConfigRouting, + ConfigRequest, + Storage->EditBuffer, + BufferSize, + &Result, + &Progress + ); + ASSERT_EFI_ERROR (Status); + + Status = mHiiConfigRouting->ConfigToBlock ( + mHiiConfigRouting, + Result, + BackUpBuf, + &BufferSize, + &Progress + ); + ASSERT_EFI_ERROR (Status); + + if (Result != NULL) { + FreePool (Result); + } + + CopyMem (Storage->EditBuffer, BackUpBuf, Storage->Size); + FreePool (BackUpBuf); + } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + // + // Update question value, only element in ConfigReqeust will be update. + // + Link = GetFirstNode (&BackUpList); + while (!IsNull (&BackUpList, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + Link = GetNextNode (&BackUpList, Link); + + if (StrStr (ConfigRequest, Node->Name) != NULL) { + continue; + } + + NodeLink = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, NodeLink)) { + TmpNode = NAME_VALUE_NODE_FROM_LINK (NodeLink); + NodeLink = GetNextNode (&Storage->NameValueListHead, NodeLink); + + if (StrCmp (Node->Name, TmpNode->Name) != 0) { + continue; + } + + FreePool (TmpNode->EditValue); + TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue); + + RemoveEntryList (&Node->Link); + FreePool (Node->EditValue); + FreePool (Node->Name); + FreePool (Node); + } + } + + // + // Restore the Name/Value node. + // + Link = GetFirstNode (&BackUpList); + while (!IsNull (&BackUpList, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + Link = GetNextNode (&BackUpList, Link); + + // + // Free this node. + // + RemoveEntryList (&Node->Link); + FreePool (Node->EditValue); + FreePool (Node->Name); + FreePool (Node); + } + } +} + /** Fill storage's edit copy with settings requested from Configuration Driver. @param FormSet FormSet data structure. @param Storage Buffer Storage. - @retval EFI_SUCCESS The function completed successfully. - **/ -EFI_STATUS +VOID LoadStorage ( IN FORM_BROWSER_FORMSET *FormSet, IN FORMSET_STORAGE *Storage @@ -3772,18 +4217,17 @@ LoadStorage ( EFI_STRING Progress; EFI_STRING Result; CHAR16 *StrPtr; - CHAR16 *ConfigRequest; - if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { - return EFI_SUCCESS; - } + switch (Storage->BrowserStorage->Type) { + case EFI_HII_VARSTORE_EFI_VARIABLE: + return; + + case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: + if (Storage->BrowserStorage->ReferenceCount > 1) { + ConfigRequestAdjust(Storage); + return; + } - if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { - Status = EFI_SUCCESS; - // - // EFI varstore data all get from variable, so no need to get again. - // - if (Storage->BrowserStorage->ReferenceCount == 1) { Status = gRT->GetVariable ( Storage->BrowserStorage->Name, &Storage->BrowserStorage->Guid, @@ -3791,55 +4235,78 @@ LoadStorage ( (UINTN*)&Storage->BrowserStorage->Size, Storage->BrowserStorage->EditBuffer ); - } - return Status; - } + // + // If get variable fail, extract default from IFR binary + // + if (EFI_ERROR (Status)) { + ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE); + } + + Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest); + // + // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer. + // + SynchronizeStorage(FormSet, Storage->BrowserStorage, NULL, TRUE); + break; - if (FormSet->ConfigAccess == NULL) { - return EFI_NOT_FOUND; - } + case EFI_HII_VARSTORE_BUFFER: + case EFI_HII_VARSTORE_NAME_VALUE: + // + // Skip if there is no RequestElement + // + if (Storage->ElementCount == 0) { + return; + } - if (Storage->ElementCount == 0) { - // - // Skip if there is no RequestElement - // - return EFI_SUCCESS; - } + // + // Adjust the ConfigRequest string, only the field not saved in BrowserStorage->AllConfig + // will used to call ExtractConfig. + // If not elements need to udpate, return. + // + if (!ConfigRequestAdjust(Storage)) { + return; + } + ASSERT (Storage->ConfigElements != NULL); - // - // Adjust the ConfigRequest string, only the field not saved in BrowserStorage->AllConfig - // will used to call ExtractConfig. - // - if (!ConfigRequestAdjust(Storage, &ConfigRequest)) { - return EFI_SUCCESS; - } + Status = EFI_NOT_FOUND; + if (FormSet->ConfigAccess != NULL) { + // + // Request current settings from Configuration Driver + // + Status = FormSet->ConfigAccess->ExtractConfig ( + FormSet->ConfigAccess, + Storage->ConfigElements, + &Progress, + &Result + ); + + if (!EFI_ERROR (Status)) { + // + // Convert Result from to + // + StrPtr = StrStr (Result, L"&GUID="); + if (StrPtr != NULL) { + *StrPtr = L'\0'; + } + + Status = ConfigRespToStorage (Storage->BrowserStorage, Result); + FreePool (Result); + } + } - // - // Request current settings from Configuration Driver - // - Status = FormSet->ConfigAccess->ExtractConfig ( - FormSet->ConfigAccess, - ConfigRequest, - &Progress, - &Result - ); - FreePool (ConfigRequest); + if (EFI_ERROR (Status)) { + // + // Base on the configRequest string to get default value. + // + GetDefaultForFormset (FormSet, Storage->BrowserStorage, Storage->ConfigElements); + } - if (EFI_ERROR (Status)) { - return Status; - } + SynchronizeStorage(FormSet, Storage->BrowserStorage, Storage->ConfigElements, TRUE); + break; - // - // Convert Result from to - // - StrPtr = StrStr (Result, L"&GUID="); - if (StrPtr != NULL) { - *StrPtr = L'\0'; + default: + break; } - - Status = ConfigRespToStorage (Storage->BrowserStorage, Result); - FreePool (Result); - return Status; } /** @@ -3847,22 +4314,15 @@ LoadStorage ( @param FormSet FormSet data structure. - @retval EFI_SUCCESS The function completed successfully. - **/ -EFI_STATUS +VOID InitializeCurrentSetting ( IN OUT FORM_BROWSER_FORMSET *FormSet ) { LIST_ENTRY *Link; - LIST_ENTRY *Link2; FORMSET_STORAGE *Storage; - FORMSET_STORAGE *StorageSrc; - FORMSET_STORAGE *OldStorage; - FORM_BROWSER_FORM *Form; - FORM_BROWSER_FORM *Form2; - EFI_STATUS Status; + FORM_BROWSER_FORMSET *OldFormSet; // // Extract default from IFR binary for no storage questions. @@ -3876,77 +4336,21 @@ InitializeCurrentSetting ( while (!IsNull (&FormSet->StorageListHead, Link)) { Storage = FORMSET_STORAGE_FROM_LINK (Link); - OldStorage = NULL; - if (gOldFormSet != NULL) { - // - // Try to find the Storage in backup formset gOldFormSet - // - Link2 = GetFirstNode (&gOldFormSet->StorageListHead); - while (!IsNull (&gOldFormSet->StorageListHead, Link2)) { - StorageSrc = FORMSET_STORAGE_FROM_LINK (Link2); - - if (StorageSrc->VarStoreId == Storage->VarStoreId) { - OldStorage = StorageSrc; - break; - } - - Link2 = GetNextNode (&gOldFormSet->StorageListHead, Link2); - } - } - - // - // Storage is not found in backup formset and current global storage not has other driver used, - // request it from ConfigDriver - // - if (OldStorage == NULL) { - Status = LoadStorage (FormSet, Storage); - - if (EFI_ERROR (Status)) { - // - // If get last time changed value failed, extract default from IFR binary - // - ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE); - // - // ExtractDefault will set the NV flag to TRUE, so need this function to clean the flag - // in current situation. - // - UpdateNvInfoInForm (FormSet, FALSE); - } - - // - // Now Edit Buffer is filled with default values(lower priority) or current - // settings(higher priority), sychronize it to shadow Buffer - // - SynchronizeStorage (Storage->BrowserStorage, TRUE); - } + LoadStorage (FormSet, Storage); Link = GetNextNode (&FormSet->StorageListHead, Link); } // - // If has old formset, get the old nv update status. + // Try to find pre FormSet in the maintain backup list. + // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList. // - if (gOldFormSet != NULL) { - Link = GetFirstNode (&FormSet->FormListHead); - while (!IsNull (&FormSet->FormListHead, Link)) { - Form = FORM_BROWSER_FORM_FROM_LINK (Link); - - Link2 = GetFirstNode (&gOldFormSet->FormListHead); - while (!IsNull (&gOldFormSet->FormListHead, Link2)) { - Form2 = FORM_BROWSER_FORM_FROM_LINK (Link2); - - if (Form->FormId == Form2->FormId) { - Form->NvUpdateRequired = Form2->NvUpdateRequired; - break; - } - - Link2 = GetNextNode (&gOldFormSet->FormListHead, Link2); - } - Link = GetNextNode (&FormSet->FormListHead, Link); - } + OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle); + if (OldFormSet != NULL) { + RemoveEntryList (&OldFormSet->Link); + DestroyFormSet (OldFormSet); } - - return EFI_SUCCESS; + InsertTailList (&gBrowserFormSetList, &FormSet->Link); } @@ -4129,7 +4533,6 @@ GetIfrBinaryData ( found in package list. On output, GUID of the formset found(if not NULL). @param FormSet FormSet data structure. - @param UpdateGlobalVar Whether need to update the global variable. @retval EFI_SUCCESS The function completed successfully. @retval EFI_NOT_FOUND The specified FormSet could not be found. @@ -4139,13 +4542,11 @@ EFI_STATUS InitializeFormSet ( IN EFI_HII_HANDLE Handle, IN OUT EFI_GUID *FormSetGuid, - OUT FORM_BROWSER_FORMSET *FormSet, - IN BOOLEAN UpdateGlobalVar + OUT FORM_BROWSER_FORMSET *FormSet ) { EFI_STATUS Status; EFI_HANDLE DriverHandle; - UINT16 Index; Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData); if (EFI_ERROR (Status)) { @@ -4155,6 +4556,7 @@ InitializeFormSet ( FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE; FormSet->HiiHandle = Handle; CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID)); + FormSet->QuestionInited = FALSE; // // Retrieve ConfigAccess Protocol associated with this HiiPackageList @@ -4181,55 +4583,8 @@ InitializeFormSet ( // Parse the IFR binary OpCodes // Status = ParseOpCodes (FormSet); - if (EFI_ERROR (Status)) { - return Status; - } - // - // If not need to update the global variable, just return. - // - if (!UpdateGlobalVar) { - return Status; - } - - // - // Set VFR type by FormSet SubClass field - // - gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP; - if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) { - gClassOfVfr = FORMSET_CLASS_FRONT_PAGE; - } - - // - // Set VFR type by FormSet class guid - // - for (Index = 0; Index < 3; Index ++) { - if (CompareGuid (&FormSet->ClassGuid[Index], &gEfiHiiPlatformSetupFormsetGuid)) { - gClassOfVfr |= FORMSET_CLASS_PLATFORM_SETUP; - break; - } - } - - gFunctionKeySetting = ENABLE_FUNCTION_KEY_SETTING; - - if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) { - gFrontPageHandle = FormSet->HiiHandle; - gFunctionKeySetting = NONE_FUNCTION_KEY_SETTING; - } - - // - // Match GUID to find out the function key setting. If match fail, use the default setting. - // - for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) { - if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) { - // - // Update the function key setting. - // - gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting; - } - } - - return EFI_SUCCESS; + return Status; } @@ -4245,6 +4600,7 @@ SaveBrowserContext ( ) { BROWSER_CONTEXT *Context; + FORM_ENTRY_INFO *MenuList; gBrowserContextCount++; if (gBrowserContextCount == 1) { @@ -4262,47 +4618,23 @@ SaveBrowserContext ( // // Save FormBrowser context // - Context->BannerData = gBannerData; - Context->ClassOfVfr = gClassOfVfr; - Context->FunctionKeySetting = gFunctionKeySetting; + Context->Selection = gCurrentSelection; Context->ResetRequired = gResetRequired; - Context->Direction = gDirection; - Context->EnterString = gEnterString; - Context->EnterCommitString = gEnterCommitString; - Context->EnterEscapeString = gEnterEscapeString; - Context->EscapeString = gEscapeString; - Context->MoveHighlight = gMoveHighlight; - Context->MakeSelection = gMakeSelection; - Context->DecNumericInput = gDecNumericInput; - Context->HexNumericInput = gHexNumericInput; - Context->ToggleCheckBox = gToggleCheckBox; - Context->PromptForData = gPromptForData; - Context->PromptForPassword = gPromptForPassword; - Context->PromptForNewPassword = gPromptForNewPassword; - Context->ConfirmPassword = gConfirmPassword; - Context->ConfirmError = gConfirmError; - Context->PassowordInvalid = gPassowordInvalid; - Context->PressEnter = gPressEnter; - Context->EmptyString = gEmptyString; - Context->AreYouSure = gAreYouSure; - Context->YesResponse = gYesResponse; - Context->NoResponse = gNoResponse; - Context->MiniString = gMiniString; - Context->PlusString = gPlusString; - Context->MinusString = gMinusString; - Context->AdjustNumber = gAdjustNumber; - Context->SaveChanges = gSaveChanges; - Context->OptionMismatch = gOptionMismatch; - Context->FormSuppress = gFormSuppress; - Context->PromptBlockWidth = gPromptBlockWidth; - Context->OptionBlockWidth = gOptionBlockWidth; - Context->HelpBlockWidth = gHelpBlockWidth; - Context->OldFormSet = gOldFormSet; - Context->MenuRefreshHead = gMenuRefreshHead; - Context->ProtocolNotFound = gProtocolNotFound; - - CopyMem (&Context->ScreenDimensions, &gScreenDimensions, sizeof (gScreenDimensions)); - CopyMem (&Context->MenuOption, &gMenuOption, sizeof (gMenuOption)); + Context->ExitRequired = gExitRequired; + Context->HiiHandle = mCurrentHiiHandle; + Context->FormId = mCurrentFormId; + CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid); + + // + // Save the menu history data. + // + InitializeListHead(&Context->FormHistoryList); + while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) { + MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink); + RemoveEntryList (&MenuList->Link); + + InsertTailList(&Context->FormHistoryList, &MenuList->Link); + } // // Insert to FormBrowser context list @@ -4322,6 +4654,7 @@ RestoreBrowserContext ( { LIST_ENTRY *Link; BROWSER_CONTEXT *Context; + FORM_ENTRY_INFO *MenuList; ASSERT (gBrowserContextCount != 0); gBrowserContextCount--; @@ -4340,47 +4673,22 @@ RestoreBrowserContext ( // // Restore FormBrowser context // - gBannerData = Context->BannerData; - gClassOfVfr = Context->ClassOfVfr; - gFunctionKeySetting = Context->FunctionKeySetting; + gCurrentSelection = Context->Selection; gResetRequired = Context->ResetRequired; - gDirection = Context->Direction; - gEnterString = Context->EnterString; - gEnterCommitString = Context->EnterCommitString; - gEnterEscapeString = Context->EnterEscapeString; - gEscapeString = Context->EscapeString; - gMoveHighlight = Context->MoveHighlight; - gMakeSelection = Context->MakeSelection; - gDecNumericInput = Context->DecNumericInput; - gHexNumericInput = Context->HexNumericInput; - gToggleCheckBox = Context->ToggleCheckBox; - gPromptForData = Context->PromptForData; - gPromptForPassword = Context->PromptForPassword; - gPromptForNewPassword = Context->PromptForNewPassword; - gConfirmPassword = Context->ConfirmPassword; - gConfirmError = Context->ConfirmError; - gPassowordInvalid = Context->PassowordInvalid; - gPressEnter = Context->PressEnter; - gEmptyString = Context->EmptyString; - gAreYouSure = Context->AreYouSure; - gYesResponse = Context->YesResponse; - gNoResponse = Context->NoResponse; - gMiniString = Context->MiniString; - gPlusString = Context->PlusString; - gMinusString = Context->MinusString; - gAdjustNumber = Context->AdjustNumber; - gSaveChanges = Context->SaveChanges; - gOptionMismatch = Context->OptionMismatch; - gFormSuppress = Context->FormSuppress; - gPromptBlockWidth = Context->PromptBlockWidth; - gOptionBlockWidth = Context->OptionBlockWidth; - gHelpBlockWidth = Context->HelpBlockWidth; - gOldFormSet = Context->OldFormSet; - gMenuRefreshHead = Context->MenuRefreshHead; - gProtocolNotFound = Context->ProtocolNotFound; - - CopyMem (&gScreenDimensions, &Context->ScreenDimensions, sizeof (gScreenDimensions)); - CopyMem (&gMenuOption, &Context->MenuOption, sizeof (gMenuOption)); + gExitRequired = Context->ExitRequired; + mCurrentHiiHandle = Context->HiiHandle; + mCurrentFormId = Context->FormId; + CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid); + + // + // Restore the menu history data. + // + while (!IsListEmpty (&Context->FormHistoryList)) { + MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink); + RemoveEntryList (&MenuList->Link); + + InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link); + } // // Remove from FormBrowser context list @@ -4440,7 +4748,7 @@ IsHiiHandleInBrowserContext ( // // HiiHandle is Current FormSet. // - if ((gOldFormSet != NULL) && (gOldFormSet->HiiHandle == Handle)) { + if (mCurrentHiiHandle == Handle) { return TRUE; } @@ -4450,7 +4758,7 @@ IsHiiHandleInBrowserContext ( Link = GetFirstNode (&gBrowserContextList); while (!IsNull (&gBrowserContextList, Link)) { Context = BROWSER_CONTEXT_FROM_LINK (Link); - if (Context->OldFormSet->HiiHandle == Handle) { + if (Context->HiiHandle == Handle) { // // HiiHandle is in BrowserContext // @@ -4462,6 +4770,83 @@ IsHiiHandleInBrowserContext ( return FALSE; } +/** + Perform Password check. + Passwork may be encrypted by driver that requires the specific check. + + @param Form Form where Password Statement is in. + @param Statement Password statement + @param PasswordString Password string to be checked. It may be NULL. + NULL means to restore password. + "" string can be used to checked whether old password does exist. + + @return Status Status of Password check. +**/ +EFI_STATUS +EFIAPI +PasswordCheck ( + IN FORM_DISPLAY_ENGINE_FORM *Form, + IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, + IN EFI_STRING PasswordString OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + EFI_IFR_TYPE_VALUE IfrTypeValue; + FORM_BROWSER_STATEMENT *Question; + + ConfigAccess = gCurrentSelection->FormSet->ConfigAccess; + Question = GetBrowserStatement(Statement); + ASSERT (Question != NULL); + + if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) { + if (ConfigAccess == NULL) { + return EFI_UNSUPPORTED; + } + } else { + if (PasswordString == NULL) { + return EFI_SUCCESS; + } + + if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) { + return EFI_SUCCESS; + } else { + return EFI_NOT_READY; + } + } + + // + // Prepare password string in HII database + // + if (PasswordString != NULL) { + IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle); + } else { + IfrTypeValue.string = 0; + } + + // + // Send password to Configuration Driver for validation + // + Status = ConfigAccess->Callback ( + ConfigAccess, + EFI_BROWSER_ACTION_CHANGING, + Question->QuestionId, + Question->HiiValue.Type, + &IfrTypeValue, + &ActionRequest + ); + + // + // Remove password string from HII database + // + if (PasswordString != NULL) { + DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle); + } + + return Status; +} + /** Find the registered HotKey based on KeyData. @@ -4512,7 +4897,7 @@ SetScope ( if (Scope >= MaxLevel) { return EFI_INVALID_PARAMETER; } - + // // When no hot key registered in system or on the first setting, // Scope can be set. @@ -4636,6 +5021,128 @@ RegiserExitHandler ( return; } +/** + Check whether the browser data has been modified. + + @retval TRUE Browser data is modified. + @retval FALSE No browser data is modified. + +**/ +BOOLEAN +EFIAPI +IsBrowserDataModified ( + VOID + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORMSET *FormSet; + + if (gCurrentSelection == NULL) { + return FALSE; + } + + switch (gBrowserSettingScope) { + case FormLevel: + return IsNvUpdateRequiredForForm (gCurrentSelection->Form); + + case FormSetLevel: + return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet); + + case SystemLevel: + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + if (IsNvUpdateRequiredForFormSet (FormSet)) { + return TRUE; + } + Link = GetNextNode (&gBrowserFormSetList, Link); + } + return FALSE; + + default: + return FALSE; + } +} + +/** + Execute the action requested by the Action parameter. + + @param[in] Action Execute the request action. + @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT. + + @retval EFI_SUCCESS Execute the request action succss. + @retval EFI_INVALID_PARAMETER The input action value is invalid. + +**/ +EFI_STATUS +EFIAPI +ExecuteAction ( + IN UINT32 Action, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + + if (gCurrentSelection == NULL) { + return EFI_NOT_READY; + } + + Status = EFI_SUCCESS; + + // + // Executet the discard action. + // + if ((Action & BROWSER_ACTION_DISCARD) != 0) { + Status = DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Executet the difault action. + // + if ((Action & BROWSER_ACTION_DEFAULT) != 0) { + Status = ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Executet the submit action. + // + if ((Action & BROWSER_ACTION_SUBMIT) != 0) { + Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Executet the reset action. + // + if ((Action & BROWSER_ACTION_RESET) != 0) { + gResetRequired = TRUE; + } + + // + // Executet the exit action. + // + if ((Action & BROWSER_ACTION_EXIT) != 0) { + DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); + if (gBrowserSettingScope == SystemLevel) { + if (ExitHandlerFunction != NULL) { + ExitHandlerFunction (); + } + } + + gExitRequired = TRUE; + } + + return Status; +} + /** Create reminder to let user to choose save or discard the changed browser data. Caller can use it to actively check the changed browser data. @@ -4655,12 +5162,6 @@ SaveReminder ( FORM_BROWSER_FORMSET *FormSet; BOOLEAN IsDataChanged; UINT32 DataSavedAction; - CHAR16 *YesResponse; - CHAR16 *NoResponse; - CHAR16 *EmptyString; - CHAR16 *ChangeReminderString; - CHAR16 *SaveConfirmString; - EFI_INPUT_KEY Key; DataSavedAction = BROWSER_NO_CHANGES; IsDataChanged = FALSE; @@ -4671,7 +5172,7 @@ SaveReminder ( if (!ValidateFormSet(FormSet)) { continue; } - if (IsNvUpdateRequired (FormSet)) { + if (IsNvUpdateRequiredForFormSet (FormSet)) { IsDataChanged = TRUE; break; } @@ -4685,42 +5186,19 @@ SaveReminder ( } // - // If data is changed, prompt user + // If data is changed, prompt user to save or discard it. // - gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); - - YesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle); - ASSERT (YesResponse != NULL); - NoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle); - ASSERT (NoResponse != NULL); - EmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); - ChangeReminderString = GetToken (STRING_TOKEN (CHANGE_REMINDER), gHiiHandle); - SaveConfirmString = GetToken (STRING_TOKEN (SAVE_CONFIRM), gHiiHandle); - do { - CreateDialog (4, TRUE, 0, NULL, &Key, EmptyString, ChangeReminderString, SaveConfirmString, EmptyString); - } while - (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse[0] | UPPER_LOWER_CASE_OFFSET)) && - ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) - ); + DataSavedAction = (UINT32) mFormDisplay->ConfirmDataChange(); - // - // If the user hits the YesResponse key - // - if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) { - SubmitForm (NULL, NULL, SystemLevel); - DataSavedAction = BROWSER_SAVE_CHANGES; - } else { - DiscardForm (NULL, NULL, SystemLevel); - DataSavedAction = BROWSER_DISCARD_CHANGES; - gResetRequired = FALSE; - } - - FreePool (YesResponse); - FreePool (NoResponse); - FreePool (EmptyString); - FreePool (SaveConfirmString); - FreePool (ChangeReminderString); + if (DataSavedAction == BROWSER_SAVE_CHANGES) { + SubmitForm (NULL, NULL, SystemLevel); + break; + } else if (DataSavedAction == BROWSER_DISCARD_CHANGES) { + DiscardForm (NULL, NULL, SystemLevel); + break; + } + } while (1); return DataSavedAction; } diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h index 9a0c739094..030cf32eac 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h @@ -22,7 +22,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include -#include +#include +#include #include #include #include @@ -47,105 +48,28 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include -#include "Colors.h" // // This is the generated header file which includes whatever needs to be exported (strings + IFR) // -extern UINT8 SetupBrowserStrings[]; +#define UI_ACTION_NONE 0 +#define UI_ACTION_REFRESH_FORM 1 +#define UI_ACTION_REFRESH_FORMSET 2 +#define UI_ACTION_EXIT 3 // -// Screen definitions -// -#define BANNER_HEIGHT 6 -#define BANNER_COLUMNS 3 -#define BANNER_LEFT_COLUMN_INDENT 1 - -#define FRONT_PAGE_HEADER_HEIGHT 6 -#define NONE_FRONT_PAGE_HEADER_HEIGHT 3 -#define LEFT_SKIPPED_COLUMNS 3 -#define FOOTER_HEIGHT 4 -#define STATUS_BAR_HEIGHT 1 -#define SCROLL_ARROW_HEIGHT 1 -#define POPUP_PAD_SPACE_COUNT 5 -#define POPUP_FRAME_WIDTH 2 - -// -// Definition for function key setting -// -#define NONE_FUNCTION_KEY_SETTING 0 -#define ENABLE_FUNCTION_KEY_SETTING 1 - -typedef struct { - EFI_GUID FormSetGuid; - UINTN KeySetting; -} FUNCTIION_KEY_SETTING; - -// -// Character definitions -// -#define CHAR_SPACE 0x0020 -#define UPPER_LOWER_CASE_OFFSET 0x20 - // // Time definitions // #define ONE_SECOND 10000000 -// -// Display definitions -// -#define LEFT_HYPER_DELIMITER L'<' -#define RIGHT_HYPER_DELIMITER L'>' - -#define LEFT_ONEOF_DELIMITER L'<' -#define RIGHT_ONEOF_DELIMITER L'>' - -#define LEFT_NUMERIC_DELIMITER L'[' -#define RIGHT_NUMERIC_DELIMITER L']' - -#define LEFT_CHECKBOX_DELIMITER L'[' -#define RIGHT_CHECKBOX_DELIMITER L']' - -#define CHECK_ON L'X' -#define CHECK_OFF L' ' - -#define TIME_SEPARATOR L':' -#define DATE_SEPARATOR L'/' - -#define YES_ANSWER L'Y' -#define NO_ANSWER L'N' - -// -// This is the Input Error Message -// -#define INPUT_ERROR 1 - -// -// This is the NV RAM update required Message -// -#define NV_UPDATE_REQUIRED 2 - -// -// Refresh the Status Bar with flags -// -#define REFRESH_STATUS_BAR 0xff - -// // Incremental string lenght of ConfigRequest // #define CONFIG_REQUEST_STRING_INCREMENTAL 1024 -// -// HII value compare result -// -#define HII_VALUE_UNDEFINED 0 -#define HII_VALUE_EQUAL 1 -#define HII_VALUE_LESS_THAN 2 -#define HII_VALUE_GREATER_THAN 3 - // // Incremental size of stack for expression // @@ -163,15 +87,12 @@ typedef struct { // // Produced protocol // - EFI_FORM_BROWSER2_PROTOCOL FormBrowser2; - - EFI_FORM_BROWSER_EXTENSION_PROTOCOL FormBrowserEx; + EFI_FORM_BROWSER2_PROTOCOL FormBrowser2; + EFI_FORM_BROWSER_EXTENSION_PROTOCOL FormBrowserEx; -} SETUP_DRIVER_PRIVATE_DATA; + EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL FormBrowserEx2; -typedef struct { - EFI_STRING_ID Banner[BANNER_HEIGHT][BANNER_COLUMNS]; -} BANNER_DATA; +} SETUP_DRIVER_PRIVATE_DATA; // // IFR relative definition @@ -194,16 +115,6 @@ typedef struct { #define FORM_INCONSISTENT_VALIDATION 0 #define FORM_NO_SUBMIT_VALIDATION 1 -#define FORMSET_CLASS_PLATFORM_SETUP 0x0001 -#define FORMSET_CLASS_FRONT_PAGE 0x0002 - -typedef struct { - UINT8 Type; - UINT8 *Buffer; - UINT16 BufferLen; - EFI_IFR_TYPE_VALUE Value; -} EFI_HII_VALUE; - #define NAME_VALUE_NODE_SIGNATURE SIGNATURE_32 ('N', 'V', 'S', 'T') typedef struct { @@ -255,6 +166,7 @@ typedef struct { BROWSER_STORAGE *BrowserStorage; CHAR16 *ConfigRequest; // = + + CHAR16 *ConfigElements;// Elements need to load initial data. UINTN ElementCount; // Number of in the UINTN SpareStrLen; // Spare length of ConfigRequest string buffer } FORMSET_STORAGE; @@ -344,6 +256,8 @@ typedef struct { typedef struct { UINTN Signature; LIST_ENTRY Link; + + EFI_IFR_ONE_OF_OPTION *OpCode; // OneOfOption Data EFI_STRING_ID Text; UINT8 Flags; @@ -376,6 +290,7 @@ typedef struct { LIST_ENTRY Link; UINT8 Operand; // The operand (first byte) of this Statement or Question + EFI_IFR_OP_HEADER *OpCode; // // Statement Header @@ -384,6 +299,11 @@ typedef struct { EFI_STRING_ID Help; EFI_STRING_ID TextTwo; // For EFI_IFR_TEXT + // + // Fake Question Id, used for statement not has true QuestionId. + // + EFI_QUESTION_ID FakeQuestionId; + // // Question Header // @@ -417,6 +337,7 @@ typedef struct { EFI_DEFAULT_ID DefaultId; // for EFI_IFR_RESET_BUTTON EFI_GUID RefreshGuid; // for EFI_IFR_REFRESH_ID BOOLEAN Locked; // Whether this statement is locked. + BOOLEAN ValueChanged; // Whether this statement's value is changed. // // Get from IFR parsing // @@ -467,8 +388,6 @@ typedef struct { BOOLEAN ModalForm; // Whether this is a modal form. BOOLEAN Locked; // Whether this form is locked. - BOOLEAN NvUpdateRequired; // Whether this form has NV update request. - LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION) LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT) LIST_ENTRY ConfigRequestHead; // List of configreques for all storage. @@ -502,6 +421,7 @@ typedef struct { UINTN IfrBinaryLength; UINT8 *IfrBinaryData; + BOOLEAN QuestionInited; // Have finished question initilization? EFI_GUID Guid; EFI_STRING_ID FormSetTitle; EFI_STRING_ID Help; @@ -514,84 +434,82 @@ typedef struct { FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode + LIST_ENTRY StatementListOSF; // Statement list out side of the form. LIST_ENTRY StorageListHead; // Storage list (FORMSET_STORAGE) LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE) LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM) LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION) } FORM_BROWSER_FORMSET; - #define FORM_BROWSER_FORMSET_FROM_LINK(a) CR (a, FORM_BROWSER_FORMSET, Link, FORM_BROWSER_FORMSET_SIGNATURE) -#define BROWSER_CONTEXT_SIGNATURE SIGNATURE_32 ('B', 'C', 'T', 'X') +typedef struct { + LIST_ENTRY Link; + EFI_EVENT RefreshEvent; +} FORM_BROWSER_REFRESH_EVENT_NODE; + +#define FORM_BROWSER_REFRESH_EVENT_FROM_LINK(a) BASE_CR (a, FORM_BROWSER_REFRESH_EVENT_NODE, Link) + typedef struct { - UINTN Signature; - LIST_ENTRY Link; + EFI_HII_HANDLE Handle; // - // Globals defined in Setup.c + // Target formset/form/Question information // - BANNER_DATA *BannerData; - UINTN ClassOfVfr; - UINTN FunctionKeySetting; - BOOLEAN ResetRequired; - UINT16 Direction; - EFI_SCREEN_DESCRIPTOR ScreenDimensions; - CHAR16 *EnterString; - CHAR16 *EnterCommitString; - CHAR16 *EnterEscapeString; - CHAR16 *EscapeString; - CHAR16 *MoveHighlight; - CHAR16 *MakeSelection; - CHAR16 *DecNumericInput; - CHAR16 *HexNumericInput; - CHAR16 *ToggleCheckBox; - CHAR16 *PromptForData; - CHAR16 *PromptForPassword; - CHAR16 *PromptForNewPassword; - CHAR16 *ConfirmPassword; - CHAR16 *ConfirmError; - CHAR16 *PassowordInvalid; - CHAR16 *PressEnter; - CHAR16 *EmptyString; - CHAR16 *AreYouSure; - CHAR16 *YesResponse; - CHAR16 *NoResponse; - CHAR16 *MiniString; - CHAR16 *PlusString; - CHAR16 *MinusString; - CHAR16 *AdjustNumber; - CHAR16 *SaveChanges; - CHAR16 *OptionMismatch; - CHAR16 *FormSuppress; - CHAR16 *ProtocolNotFound; - CHAR16 PromptBlockWidth; - CHAR16 OptionBlockWidth; - CHAR16 HelpBlockWidth; - FORM_BROWSER_FORMSET *OldFormSet; + EFI_GUID FormSetGuid; + UINT16 FormId; + UINT16 QuestionId; + UINTN Sequence; // used for time/date only. + + UINTN TopRow; + UINTN BottomRow; + UINTN PromptCol; + UINTN OptionCol; + UINTN CurrentRow; // - // Globals defined in Ui.c + // Ation for Browser to taken: + // UI_ACTION_NONE - navigation inside a form + // UI_ACTION_REFRESH_FORM - re-evaluate expressions and repaint form + // UI_ACTION_REFRESH_FORMSET - re-parse formset IFR binary // - LIST_ENTRY MenuOption; - VOID *MenuRefreshHead; -} BROWSER_CONTEXT; + UINTN Action; -#define BROWSER_CONTEXT_FROM_LINK(a) CR (a, BROWSER_CONTEXT, Link, BROWSER_CONTEXT_SIGNATURE) + // + // Current selected fomset/form/Question + // + FORM_BROWSER_FORMSET *FormSet; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_STATEMENT *Statement; -#define BROWSER_HOT_KEY_SIGNATURE SIGNATURE_32 ('B', 'H', 'K', 'S') + // + // Whether the Form is editable + // + BOOLEAN FormEditable; + + FORM_ENTRY_INFO *CurrentMenu; +} UI_MENU_SELECTION; + +#define BROWSER_CONTEXT_SIGNATURE SIGNATURE_32 ('B', 'C', 'T', 'X') typedef struct { UINTN Signature; LIST_ENTRY Link; - - EFI_INPUT_KEY *KeyData; - IN UINT32 Action; - IN UINT16 DefaultId; - IN EFI_STRING HelpString; -} BROWSER_HOT_KEY; -#define BROWSER_HOT_KEY_FROM_LINK(a) CR (a, BROWSER_HOT_KEY, Link, BROWSER_HOT_KEY_SIGNATURE) + // + // Globals defined in Setup.c + // + BOOLEAN ResetRequired; + BOOLEAN ExitRequired; + EFI_HII_HANDLE HiiHandle; + EFI_GUID FormSetGuid; + EFI_FORM_ID FormId; + UI_MENU_SELECTION *Selection; + + LIST_ENTRY FormHistoryList; +} BROWSER_CONTEXT; + +#define BROWSER_CONTEXT_FROM_LINK(a) CR (a, BROWSER_CONTEXT, Link, BROWSER_CONTEXT_SIGNATURE) // // Scope for get defaut value. It may be GetDefaultForNoStorage, GetDefaultForStorage or GetDefaultForAll. @@ -614,72 +532,31 @@ typedef enum { } GET_SET_QUESTION_VALUE_WITH; extern EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; -extern EFI_HII_STRING_PROTOCOL *mHiiString; extern EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; extern EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText; +extern EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay; -extern BANNER_DATA *gBannerData; -extern EFI_HII_HANDLE gFrontPageHandle; -extern UINTN gClassOfVfr; -extern UINTN gFunctionKeySetting; extern BOOLEAN gResetRequired; -extern EFI_HII_HANDLE gHiiHandle; -extern UINT16 gDirection; -extern EFI_SCREEN_DESCRIPTOR gScreenDimensions; +extern BOOLEAN gExitRequired; -extern FORM_BROWSER_FORMSET *gOldFormSet; extern LIST_ENTRY gBrowserFormSetList; extern LIST_ENTRY gBrowserHotKeyList; extern BROWSER_SETTING_SCOPE gBrowserSettingScope; extern EXIT_HANDLER ExitHandlerFunction; -extern UINTN gFooterHeight; - +extern EFI_HII_HANDLE mCurrentHiiHandle; // // Browser Global Strings // -extern CHAR16 *gDiscardFailed; -extern CHAR16 *gDefaultFailed; -extern CHAR16 *gEnterString; -extern CHAR16 *gEnterCommitString; -extern CHAR16 *gEnterEscapeString; -extern CHAR16 *gEscapeString; -extern CHAR16 *gSaveFailed; -extern CHAR16 *gMoveHighlight; -extern CHAR16 *gMakeSelection; -extern CHAR16 *gDecNumericInput; -extern CHAR16 *gHexNumericInput; -extern CHAR16 *gToggleCheckBox; -extern CHAR16 *gPromptForData; -extern CHAR16 *gPromptForPassword; -extern CHAR16 *gPromptForNewPassword; -extern CHAR16 *gConfirmPassword; -extern CHAR16 *gConfirmError; -extern CHAR16 *gPassowordInvalid; -extern CHAR16 *gPressEnter; extern CHAR16 *gEmptyString; -extern CHAR16 *gAreYouSure; -extern CHAR16 *gYesResponse; -extern CHAR16 *gNoResponse; -extern CHAR16 *gMiniString; -extern CHAR16 *gPlusString; -extern CHAR16 *gMinusString; -extern CHAR16 *gAdjustNumber; -extern CHAR16 *gSaveChanges; -extern CHAR16 *gOptionMismatch; -extern CHAR16 *gFormSuppress; -extern CHAR16 *gProtocolNotFound; - -extern CHAR16 gPromptBlockWidth; -extern CHAR16 gOptionBlockWidth; -extern CHAR16 gHelpBlockWidth; extern EFI_GUID gZeroGuid; -extern EFI_GUID gTianoHiiIfrGuid; -#include "Ui.h" +extern UI_MENU_SELECTION *gCurrentSelection; + // // Global Procedure Defines // +#include "Expression.h" /** Initialize the HII String Token to the correct values. @@ -690,91 +567,6 @@ InitializeBrowserStrings ( VOID ); -/** - Prints a unicode string to the default console, - using L"%s" format. - - @param String String pointer. - - @return Length of string printed to the console - -**/ -UINTN -PrintString ( - IN CHAR16 *String - ); - -/** - Prints a chracter to the default console, - using L"%c" format. - - @param Character Character to print. - - @return Length of string printed to the console. - -**/ -UINTN -PrintChar ( - CHAR16 Character - ); - -/** - Prints a formatted unicode string to the default console, at - the supplied cursor position. - - @param Column The cursor position to print the string at. - @param Row The cursor position to print the string at - @param Fmt Format string - @param ... Variable argument list for formating string. - - @return Length of string printed to the console - -**/ -UINTN -EFIAPI -PrintAt ( - IN UINTN Column, - IN UINTN Row, - IN CHAR16 *Fmt, - ... - ); - -/** - Prints a unicode string to the default console, at - the supplied cursor position, using L"%s" format. - - @param Column The cursor position to print the string at. - @param Row The cursor position to print the string at - @param String String pointer. - - @return Length of string printed to the console - -**/ -UINTN -PrintStringAt ( - IN UINTN Column, - IN UINTN Row, - IN CHAR16 *String - ); - -/** - Prints a chracter to the default console, at - the supplied cursor position, using L"%c" format. - - @param Column The cursor position to print the string at. - @param Row The cursor position to print the string at. - @param Character Character to print. - - @return Length of string printed to the console. - -**/ -UINTN -PrintCharAt ( - IN UINTN Column, - IN UINTN Row, - CHAR16 Character - ); - /** Parse opcodes in the formset IFR binary. @@ -800,17 +592,6 @@ DestroyFormSet ( IN OUT FORM_BROWSER_FORMSET *FormSet ); -/** - This function displays the page frame. - - @param Selection Selection contains the information about - the Selection, form and formset to be displayed. - Selection action may be updated in retrieve callback. -**/ -VOID -DisplayPageFrame ( - IN UI_MENU_SELECTION *Selection - ); /** Create a new string in HII Package List. @@ -859,59 +640,6 @@ GetToken ( IN EFI_HII_HANDLE HiiHandle ); -/** - Draw a pop up windows based on the dimension, number of lines and - strings specified. - - @param RequestedWidth The width of the pop-up. - @param NumberOfLines The number of lines. - @param Marker The variable argument list for the list of string to be printed. - -**/ -VOID -CreateSharedPopUp ( - IN UINTN RequestedWidth, - IN UINTN NumberOfLines, - IN VA_LIST Marker - ); - -/** - Routine used to abstract a generic dialog interface and return the selected key or string - - @param NumberOfLines The number of lines for the dialog box - @param HotKey Defines whether a single character is parsed - (TRUE) and returned in KeyValue or a string is - returned in StringBuffer. Two special characters - are considered when entering a string, a SCAN_ESC - and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates - string input and returns - @param MaximumStringSize The maximum size in bytes of a typed in string - (each character is a CHAR16) and the minimum - string returned is two bytes - @param StringBuffer The passed in pointer to the buffer which will - hold the typed in string if HotKey is FALSE - @param KeyValue The EFI_KEY value returned if HotKey is TRUE.. - @param ... A series of (quantity == NumberOfLines) text - strings which will be used to construct the dialog - box - - @retval EFI_SUCCESS Displayed dialog and received user interaction - @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g. - (StringBuffer == NULL) && (HotKey == FALSE)) - @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine - -**/ -EFI_STATUS -EFIAPI -CreateDialog ( - IN UINTN NumberOfLines, - IN BOOLEAN HotKey, - IN UINTN MaximumStringSize, - OUT CHAR16 *StringBuffer, - OUT EFI_INPUT_KEY *KeyValue, - ... - ); - /** Get Value for given Name from a NameValue Storage. @@ -939,6 +667,7 @@ GetValueByName ( @param Name The Name. @param Value The Value to set. @param SetValueTo Whether update editValue or Value. + @param ReturnNode The node use the input name. @retval EFI_SUCCESS Value found for given Name. @retval EFI_NOT_FOUND No such Name found in NameValue storage. @@ -946,10 +675,31 @@ GetValueByName ( **/ EFI_STATUS SetValueByName ( - IN BROWSER_STORAGE *Storage, - IN CHAR16 *Name, - IN CHAR16 *Value, - IN GET_SET_QUESTION_VALUE_WITH SetValueTo + IN BROWSER_STORAGE *Storage, + IN CHAR16 *Name, + IN CHAR16 *Value, + IN GET_SET_QUESTION_VALUE_WITH SetValueTo, + OUT NAME_VALUE_NODE **ReturnNode + ); + +/** + Validate whether this question's value has changed. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Question to be initialized. + @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver. + + @retval TRUE Question's value has changed. + @retval FALSE Question's value has not changed + +**/ +BOOLEAN +IsQuestionValueChanged ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN GET_SET_QUESTION_VALUE_WITH GetValueFrom ); /** @@ -1071,10 +821,8 @@ GetQuestionDefault ( @param FormSet FormSet data structure. - @retval EFI_SUCCESS The function completed successfully. - **/ -EFI_STATUS +VOID InitializeCurrentSetting ( IN OUT FORM_BROWSER_FORMSET *FormSet ); @@ -1087,7 +835,6 @@ InitializeCurrentSetting ( GUID), take the first FormSet found in package list. @param FormSet FormSet data structure. - @param UpdateGlobalVar Whether need to update the global variable. @retval EFI_SUCCESS The function completed successfully. @retval EFI_NOT_FOUND The specified FormSet could not be found. @@ -1097,8 +844,7 @@ EFI_STATUS InitializeFormSet ( IN EFI_HII_HANDLE Handle, IN OUT EFI_GUID *FormSetGuid, - OUT FORM_BROWSER_FORMSET *FormSet, - IN BOOLEAN UpdateGlobalVar + OUT FORM_BROWSER_FORMSET *FormSet ); /** @@ -1176,6 +922,7 @@ LoadFormSetConfig ( @param Storage The Storage to be conveted. @param ConfigResp The returned . @param ConfigRequest The ConfigRequest string. + @param GetEditBuf Get the data from editbuffer or buffer. @retval EFI_SUCCESS Convert success. @retval EFI_INVALID_PARAMETER Incorrect storage type. @@ -1185,7 +932,8 @@ EFI_STATUS StorageToConfigResp ( IN BROWSER_STORAGE *Storage, IN CHAR16 **ConfigResp, - IN CHAR16 *ConfigRequest + IN CHAR16 *ConfigRequest, + IN BOOLEAN GetEditBuf ); /** @@ -1210,10 +958,8 @@ ConfigRespToStorage ( @param FormSet FormSet data structure. @param Storage Buffer Storage. - @retval EFI_SUCCESS The function completed successfully. - **/ -EFI_STATUS +VOID LoadStorage ( IN FORM_BROWSER_FORMSET *FormSet, IN FORMSET_STORAGE *Storage @@ -1349,30 +1095,29 @@ BrowserCallback ( about the Selection, form and formset to be displayed. On output, Selection return the screen item that is selected by user. - @param Repaint Whether need to repaint the menu. - @param NewLine Whether need to show at new line. + @param SettingLevel Input Settting level, if it is FormLevel, just exit current form. + else, we need to exit current formset. - @retval TRUE Need return. - @retval FALSE No need to return. + @retval TRUE Exit current form. + @retval FALSE User press ESC and keep in current form. **/ BOOLEAN FindNextMenu ( - IN OUT UI_MENU_SELECTION *Selection, - IN BOOLEAN *Repaint, - IN BOOLEAN *NewLine + IN OUT UI_MENU_SELECTION *Selection, + IN BROWSER_SETTING_SCOPE SettingLevel ); /** - check whether the formset need to update the NV. + check whether the form need to update the NV. - @param FormSet FormSet data structure. - @param SetValue Whether set new value or clear old value. + @param Form Form data structure. + @retval TRUE Need to update the NV. + @retval FALSE No need to update the NV. **/ -VOID -UpdateNvInfoInForm ( - IN FORM_BROWSER_FORMSET *FormSet, - IN BOOLEAN SetValue +BOOLEAN +IsNvUpdateRequiredForForm ( + IN FORM_BROWSER_FORM *Form ); /** @@ -1383,11 +1128,24 @@ UpdateNvInfoInForm ( @retval TRUE Need to update the NV. @retval FALSE No need to update the NV. **/ -BOOLEAN -IsNvUpdateRequired ( +BOOLEAN +IsNvUpdateRequiredForFormSet ( IN FORM_BROWSER_FORMSET *FormSet ); +/** + Check whether the storage data for current form set is changed. + + @param FormSet FormSet data structure. + + @retval TRUE Data is changed. + @retval FALSE Data is not changed. +**/ +BOOLEAN +IsStorageDataChangedForFormSet ( + IN FORM_BROWSER_FORMSET *FormSet + ); + /** Call the call back function for the question and process the return action. @@ -1516,6 +1274,38 @@ RegiserExitHandler ( IN EXIT_HANDLER Handler ); +/** + + Check whether the browser data has been modified. + + @retval TRUE Browser data is changed. + @retval FALSE No browser data is changed. + +**/ +BOOLEAN +EFIAPI +IsBrowserDataModified ( + VOID + ); + +/** + + Execute the action requested by the Action parameter. + + @param[in] Action Execute the request action. + @param[in] DefaultId The default Id info when need to load default value. + + @retval EFI_SUCCESS Execute the request action succss. + @retval EFI_INVALID_PARAMETER The input action value is invalid. + +**/ +EFI_STATUS +EFIAPI +ExecuteAction ( + IN UINT32 Action, + IN UINT16 DefaultId + ); + /** Create reminder to let user to choose save or discard the changed browser data. Caller can use it to actively check the changed browser data. @@ -1544,6 +1334,267 @@ GetHotKeyFromRegisterList ( IN EFI_INPUT_KEY *KeyData ); +/** + + Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info. + + @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT. + + @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info. + +**/ +FORM_BROWSER_STATEMENT * +GetBrowserStatement ( + IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement + ); + +/** + Password may be stored as encrypted by Configuration Driver. When change a + password, user will be challenged with old password. To validate user input old + password, we will send the clear text to Configuration Driver via Callback(). + Configuration driver is responsible to check the passed in password and return + the validation result. If validation pass, state machine in password Callback() + will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD. + After user type in new password twice, Callback() will be invoked to send the + new password to Configuration Driver. + + @param Selection Pointer to UI_MENU_SELECTION. + @param MenuOption The MenuOption for this password Question. + @param String The clear text of password. + + @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input. + @return In state of BROWSER_STATE_VALIDATE_PASSWORD: + @retval EFI_SUCCESS Password correct, Browser will prompt for new + password. + @retval EFI_NOT_READY Password incorrect, Browser will show error + message. + @retval Other Browser will do nothing. + @return In state of BROWSER_STATE_SET_PASSWORD: + @retval EFI_SUCCESS Set password success. + @retval Other Set password failed. + +**/ +EFI_STATUS +PasswordCallback ( + IN UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_STATEMENT *Question, + IN CHAR16 *String + ); + +/** + Display error message for invalid password. + +**/ +VOID +PasswordInvalid ( + VOID + ); + +/** + The worker function that send the displays to the screen. On output, + the selection made by user is returned. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. + + @retval EFI_SUCCESS The page is displayed successfully. + @return Other value if the page failed to be diplayed. + +**/ +EFI_STATUS +SetupBrowser ( + IN OUT UI_MENU_SELECTION *Selection + ); + +/** + Free up the resource allocated for all strings required + by Setup Browser. + +**/ +VOID +FreeBrowserStrings ( + VOID + ); + +/** + Create a menu with specified formset GUID and form ID, and add it as a child + of the given parent menu. + + @param HiiHandle Hii handle related to this formset. + @param FormSetGuid The Formset Guid of menu to be added. + @param FormId The Form ID of menu to be added. + @param QuestionId The question id of this menu to be added. + + @return A pointer to the newly added menu or NULL if memory is insufficient. + +**/ +FORM_ENTRY_INFO * +UiAddMenuList ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid, + IN UINT16 FormId, + IN UINT16 QuestionId + ); + +/** + Search Menu with given FormSetGuid and FormId in all cached menu list. + + @param HiiHandle HiiHandle for FormSet. + @param FormSetGuid The Formset GUID of the menu to search. + @param FormId The Form ID of menu to search. + + @return A pointer to menu found or NULL if not found. + +**/ +FORM_ENTRY_INFO * +UiFindMenuList ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid, + IN UINT16 FormId + ); + +/** + Free Menu list linked list. + + @param MenuListHead One Menu list point in the menu list. + +**/ +VOID +UiFreeMenuList ( + LIST_ENTRY *MenuListHead + ); + +/** + Find parent menu for current menu. + + @param CurrentMenu Current Menu + + @retval The parent menu for current menu. +**/ +FORM_ENTRY_INFO * +UiFindParentMenu ( + IN FORM_ENTRY_INFO *CurrentMenu + ); + +/** + Search an Option of a Question by its value. + + @param Question The Question + @param OptionValue Value for Option to be searched. + + @retval Pointer Pointer to the found Option. + @retval NULL Option not found. + +**/ +QUESTION_OPTION * +ValueToOption ( + IN FORM_BROWSER_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue + ); +/** + Return data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + + @retval Value The data to be returned + +**/ +UINT64 +GetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index + ); + +/** + Set value of a data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + @param Value The value to be set. + +**/ +VOID +SetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index, + IN UINT64 Value + ); + +/** + Compare two Hii value. + + @param Value1 Expression value to compare on left-hand. + @param Value2 Expression value to compare on right-hand. + @param Result Return value after compare. + retval 0 Two operators equal. + return Positive value if Value1 is greater than Value2. + retval Negative value if Value1 is less than Value2. + @param HiiHandle Only required for string compare. + + @retval other Could not perform compare on two values. + @retval EFI_SUCCESS Compare the value success. + +**/ +EFI_STATUS +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + OUT INTN *Result, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ); + +/** + Perform Password check. + Passwork may be encrypted by driver that requires the specific check. + + @param Form Form where Password Statement is in. + @param Statement Password statement + @param PasswordString Password string to be checked. It may be NULL. + NULL means to restore password. + "" string can be used to checked whether old password does exist. + + @return Status Status of Password check. +**/ +EFI_STATUS +EFIAPI +PasswordCheck ( + IN FORM_DISPLAY_ENGINE_FORM *Form, + IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, + IN EFI_STRING PasswordString OPTIONAL + ); + +/** + + Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info. + + @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT. + + @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info. + +**/ +FORM_BROWSER_STATEMENT * +GetBrowserStatement ( + IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement + ); + +/** + + Initialize the Display form structure data. + +**/ +VOID +InitializeDisplayFormData ( + VOID + ); + + /** Base on the current formset info, clean the ConfigRequest string in browser storage. @@ -1554,5 +1605,5 @@ VOID CleanBrowserStorage ( IN OUT FORM_BROWSER_FORMSET *FormSet ); - + #endif diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf index 7e740bc099..a3f3a6fc2c 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf @@ -19,7 +19,7 @@ BASE_NAME = SetupBrowser FILE_GUID = EBf342FE-B1D3-4EF8-957C-8048606FF671 MODULE_TYPE = DXE_DRIVER - VERSION_STRING = 1.0 + VERSION_STRING = 2.0 ENTRY_POINT = InitializeSetup # @@ -29,19 +29,12 @@ # [Sources] - SetupBrowserStr.uni Setup.c Setup.h IfrParse.c Expression.c - InputHandler.c - Print.c Presentation.c - ProcessOptions.c - Ui.c - Ui.h - Colors.h - + Expression.h [Packages] MdePkg/MdePkg.dec @@ -59,34 +52,27 @@ HiiLib DevicePathLib PcdLib + UefiLib [Guids] - gEfiIfrTianoGuid ## CONSUMES ## GUID gEfiIfrFrameworkGuid ## CONSUMES ## GUID gEfiHiiPlatformSetupFormsetGuid gEfiHiiStandardFormGuid ## SOMETIMES_CONSUMES ## GUID [Protocols] gEfiHiiConfigAccessProtocolGuid ## CONSUMES - gEfiHiiStringProtocolGuid ## CONSUMES gEfiFormBrowser2ProtocolGuid ## PRODUCES - gEfiFormBrowserExProtocolGuid ## PRODUCES + gEdkiiFormBrowserEx2ProtocolGuid ## PRODUCES gEfiHiiConfigRoutingProtocolGuid ## CONSUMES gEfiHiiDatabaseProtocolGuid ## CONSUMES gEfiUnicodeCollation2ProtocolGuid ## CONSUMES gEfiUserManagerProtocolGuid ## SOMETIMES_CONSUMES gEfiDevicePathFromTextProtocolGuid ## SOMETIMES_CONSUMES + gEdkiiFormDisplayEngineProtocolGuid ## PRODUCE + gEfiFormBrowserExProtocolGuid ## PRODUCE [FeaturePcd] gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserGrayOutTextStatement ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdBrowerGrayOutReadOnlyMenu ## CONSUMES - -[Pcd] - gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserSubtitleTextColor ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextColor ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextHighlightColor ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldBackgroundHighlightColor ## CONSUMES [Depex] gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c deleted file mode 100644 index 7c246b60e1..0000000000 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c +++ /dev/null @@ -1,4027 +0,0 @@ -/** @file -Utility functions for User Interface functions. - -Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "Setup.h" - -LIST_ENTRY gMenuOption; -LIST_ENTRY gMenuList; -MENU_REFRESH_ENTRY *gMenuRefreshHead; // Menu list used for refresh timer opcode. -MENU_REFRESH_ENTRY *gMenuEventGuidRefreshHead; // Menu list used for refresh event guid opcode. - -// -// Search table for UiDisplayMenu() -// -SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = { - { - SCAN_UP, - UiUp, - }, - { - SCAN_DOWN, - UiDown, - }, - { - SCAN_PAGE_UP, - UiPageUp, - }, - { - SCAN_PAGE_DOWN, - UiPageDown, - }, - { - SCAN_ESC, - UiReset, - }, - { - SCAN_LEFT, - UiLeft, - }, - { - SCAN_RIGHT, - UiRight, - } -}; - -UINTN mScanCodeNumber = sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); - -SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = { - { - UiNoOperation, - CfUiNoOperation, - }, - { - UiSelect, - CfUiSelect, - }, - { - UiUp, - CfUiUp, - }, - { - UiDown, - CfUiDown, - }, - { - UiLeft, - CfUiLeft, - }, - { - UiRight, - CfUiRight, - }, - { - UiReset, - CfUiReset, - }, - { - UiPageUp, - CfUiPageUp, - }, - { - UiPageDown, - CfUiPageDown - }, - { - UiHotKey, - CfUiHotKey - } -}; - -BOOLEAN mInputError; -BOOLEAN GetLineByWidthFinished = FALSE; - - -/** - Set Buffer to Value for Size bytes. - - @param Buffer Memory to set. - @param Size Number of bytes to set - @param Value Value of the set operation. - -**/ -VOID -SetUnicodeMem ( - IN VOID *Buffer, - IN UINTN Size, - IN CHAR16 Value - ) -{ - CHAR16 *Ptr; - - Ptr = Buffer; - while ((Size--) != 0) { - *(Ptr++) = Value; - } -} - - -/** - Initialize Menu option list. - -**/ -VOID -UiInitMenu ( - VOID - ) -{ - InitializeListHead (&gMenuOption); -} - - -/** - Free Menu option linked list. - -**/ -VOID -UiFreeMenu ( - VOID - ) -{ - UI_MENU_OPTION *MenuOption; - - while (!IsListEmpty (&gMenuOption)) { - MenuOption = MENU_OPTION_FROM_LINK (gMenuOption.ForwardLink); - RemoveEntryList (&MenuOption->Link); - - // - // We allocated space for this description when we did a GetToken, free it here - // - if (MenuOption->Skip != 0) { - // - // For date/time, MenuOption->Description is shared by three Menu Options - // Data format : [01/02/2004] [11:22:33] - // Line number : 0 0 1 0 0 1 - // - FreePool (MenuOption->Description); - } - FreePool (MenuOption); - } -} - - -/** - Create a menu with specified formset GUID and form ID, and add it as a child - of the given parent menu. - - @param Parent The parent of menu to be added. - @param HiiHandle Hii handle related to this formset. - @param FormSetGuid The Formset Guid of menu to be added. - @param FormId The Form ID of menu to be added. - - @return A pointer to the newly added menu or NULL if memory is insufficient. - -**/ -UI_MENU_LIST * -UiAddMenuList ( - IN OUT UI_MENU_LIST *Parent, - IN EFI_HII_HANDLE HiiHandle, - IN EFI_GUID *FormSetGuid, - IN UINT16 FormId - ) -{ - UI_MENU_LIST *MenuList; - - MenuList = AllocateZeroPool (sizeof (UI_MENU_LIST)); - if (MenuList == NULL) { - return NULL; - } - - MenuList->Signature = UI_MENU_LIST_SIGNATURE; - InitializeListHead (&MenuList->ChildListHead); - - MenuList->HiiHandle = HiiHandle; - CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); - MenuList->FormId = FormId; - MenuList->Parent = Parent; - - if (Parent == NULL) { - // - // If parent is not specified, it is the root Form of a Formset - // - InsertTailList (&gMenuList, &MenuList->Link); - } else { - InsertTailList (&Parent->ChildListHead, &MenuList->Link); - } - - return MenuList; -} - - -/** - Search Menu with given FormId, FormSetGuid and Handle in all cached menu list. - - @param Parent The parent of menu to search. - @param Handle Hii handle related to this formset. - @param FormSetGuid The Formset GUID of the menu to search. - @param FormId The Form ID of menu to search. - - @return A pointer to menu found or NULL if not found. - -**/ -UI_MENU_LIST * -UiFindChildMenuList ( - IN UI_MENU_LIST *Parent, - IN EFI_HII_HANDLE Handle, - IN EFI_GUID *FormSetGuid, - IN UINT16 FormId - ) -{ - LIST_ENTRY *Link; - UI_MENU_LIST *Child; - UI_MENU_LIST *MenuList; - - ASSERT (Parent != NULL); - - if (Parent->FormId == FormId && CompareGuid (FormSetGuid, &Parent->FormSetGuid) && Parent->HiiHandle == Handle) { - return Parent; - } - - Link = GetFirstNode (&Parent->ChildListHead); - while (!IsNull (&Parent->ChildListHead, Link)) { - Child = UI_MENU_LIST_FROM_LINK (Link); - - MenuList = UiFindChildMenuList (Child, Handle, FormSetGuid, FormId); - if (MenuList != NULL) { - return MenuList; - } - - Link = GetNextNode (&Parent->ChildListHead, Link); - } - - return NULL; -} - - -/** - Search Menu with given Handle, FormSetGuid and FormId in all cached menu list. - - @param Handle Hii handle related to this formset. - @param FormSetGuid The Formset GUID of the menu to search. - @param FormId The Form ID of menu to search. - - @return A pointer to menu found or NULL if not found. - -**/ -UI_MENU_LIST * -UiFindMenuList ( - IN EFI_HII_HANDLE Handle, - IN EFI_GUID *FormSetGuid, - IN UINT16 FormId - ) -{ - LIST_ENTRY *Link; - UI_MENU_LIST *MenuList; - UI_MENU_LIST *Child; - - Link = GetFirstNode (&gMenuList); - while (!IsNull (&gMenuList, Link)) { - MenuList = UI_MENU_LIST_FROM_LINK (Link); - - Child = UiFindChildMenuList(MenuList, Handle, FormSetGuid, FormId); - if (Child != NULL) { - - // - // If this form already in the menu history list, - // just free the list between old this form. - // - UiFreeMenuList(&Child->ChildListHead); - return Child; - } - - Link = GetNextNode (&gMenuList, Link); - } - - return NULL; -} - -/** - Free Menu list linked list. - - @param MenuListHead One Menu list point in the menu list. - -**/ -VOID -UiFreeMenuList ( - LIST_ENTRY *MenuListHead - ) -{ - UI_MENU_LIST *MenuList; - - while (!IsListEmpty (MenuListHead)) { - MenuList = UI_MENU_LIST_FROM_LINK (MenuListHead->ForwardLink); - RemoveEntryList (&MenuList->Link); - - UiFreeMenuList(&MenuList->ChildListHead); - FreePool (MenuList); - } - -} - -/** - Free Menu option linked list. - -**/ -VOID -UiFreeRefreshList ( - VOID - ) -{ - MENU_REFRESH_ENTRY *OldMenuRefreshEntry; - - while (gMenuRefreshHead != NULL) { - OldMenuRefreshEntry = gMenuRefreshHead->Next; - FreePool (gMenuRefreshHead); - gMenuRefreshHead = OldMenuRefreshEntry; - } - - while (gMenuEventGuidRefreshHead != NULL) { - OldMenuRefreshEntry = gMenuEventGuidRefreshHead->Next; - if (gMenuEventGuidRefreshHead != NULL) { - gBS->CloseEvent(gMenuEventGuidRefreshHead->Event); - } - FreePool (gMenuEventGuidRefreshHead); - gMenuEventGuidRefreshHead = OldMenuRefreshEntry; - } -} - - -/** - Process option string for date/time opcode. - - @param MenuOption Menu option point to date/time. - @param OptionString Option string input for process. - @param AddOptCol Whether need to update MenuOption->OptCol. - -**/ -VOID -ProcessStringForDateTime ( - UI_MENU_OPTION *MenuOption, - CHAR16 *OptionString, - BOOLEAN AddOptCol - ) -{ - UINTN Index; - UINTN Count; - FORM_BROWSER_STATEMENT *Statement; - - ASSERT (MenuOption != NULL && OptionString != NULL); - - Statement = MenuOption->ThisTag; - - // - // If leading spaces on OptionString - remove the spaces - // - for (Index = 0; OptionString[Index] == L' '; Index++) { - // - // Base on the blockspace to get the option column info. - // - if (AddOptCol) { - MenuOption->OptCol++; - } - } - - for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { - OptionString[Count] = OptionString[Index]; - Count++; - } - OptionString[Count] = CHAR_NULL; - - // - // Enable to suppress field in the opcode base on the flag. - // - if (Statement->Operand == EFI_IFR_DATE_OP) { - // - // OptionString format is: <**: **: ****> - // |month|day|year| - // 4 3 5 - // - if ((Statement->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) { - // - // At this point, only "<**:" in the optionstring. - // Clean the day's ** field, after clean, the format is "< :" - // - SetUnicodeMem (&OptionString[1], 2, L' '); - } else if ((Statement->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) { - // - // At this point, only "**:" in the optionstring. - // Clean the month's "**" field, after clean, the format is " :" - // - SetUnicodeMem (&OptionString[0], 2, L' '); - } else if ((Statement->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) { - // - // At this point, only "****>" in the optionstring. - // Clean the year's "****" field, after clean, the format is " >" - // - SetUnicodeMem (&OptionString[0], 4, L' '); - } - } else if (Statement->Operand == EFI_IFR_TIME_OP) { - // - // OptionString format is: <**: **: **> - // |hour|minute|second| - // 4 3 3 - // - if ((Statement->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) { - // - // At this point, only "<**:" in the optionstring. - // Clean the hour's ** field, after clean, the format is "< :" - // - SetUnicodeMem (&OptionString[1], 2, L' '); - } else if ((Statement->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) { - // - // At this point, only "**:" in the optionstring. - // Clean the minute's "**" field, after clean, the format is " :" - // - SetUnicodeMem (&OptionString[0], 2, L' '); - } else if ((Statement->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) { - // - // At this point, only "**>" in the optionstring. - // Clean the second's "**" field, after clean, the format is " >" - // - SetUnicodeMem (&OptionString[0], 2, L' '); - } - } -} - -/** - Refresh question. - - @param MenuRefreshEntry Menu refresh structure which has info about the refresh question. -**/ -EFI_STATUS -RefreshQuestion ( - IN MENU_REFRESH_ENTRY *MenuRefreshEntry - ) -{ - CHAR16 *OptionString; - EFI_STATUS Status; - UI_MENU_SELECTION *Selection; - FORM_BROWSER_STATEMENT *Question; - - Selection = MenuRefreshEntry->Selection; - Question = MenuRefreshEntry->MenuOption->ThisTag; - - Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithHiiDriver); - if (EFI_ERROR (Status)) { - return Status; - } - - OptionString = NULL; - ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString); - - if (OptionString != NULL) { - // - // If old Text is longer than new string, need to clean the old string before paint the newer. - // This option is no need for time/date opcode, because time/data opcode has fixed string length. - // - if ((MenuRefreshEntry->MenuOption->ThisTag->Operand != EFI_IFR_DATE_OP) && - (MenuRefreshEntry->MenuOption->ThisTag->Operand != EFI_IFR_TIME_OP)) { - ClearLines ( - MenuRefreshEntry->CurrentColumn, - MenuRefreshEntry->CurrentColumn + gOptionBlockWidth - 1, - MenuRefreshEntry->CurrentRow, - MenuRefreshEntry->CurrentRow, - PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND - ); - } - - gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute); - ProcessStringForDateTime(MenuRefreshEntry->MenuOption, OptionString, FALSE); - PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString); - FreePool (OptionString); - } - - // - // Question value may be changed, need invoke its Callback() - // - Status = ProcessCallBackFunction (Selection, Question, EFI_BROWSER_ACTION_CHANGING, FALSE); - - return Status; -} - -/** - Refresh the question which has refresh guid event attribute. - - @param Event The event which has this function related. - @param Context The input context info related to this event or the status code return to the caller. -**/ -VOID -EFIAPI -RefreshQuestionNotify( - IN EFI_EVENT Event, - IN VOID *Context - ) -{ - MENU_REFRESH_ENTRY *MenuRefreshEntry; - UI_MENU_SELECTION *Selection; - - // - // Reset FormPackage update flag - // - mHiiPackageListUpdated = FALSE; - - MenuRefreshEntry = (MENU_REFRESH_ENTRY *)Context; - ASSERT (MenuRefreshEntry != NULL); - Selection = MenuRefreshEntry->Selection; - - RefreshQuestion (MenuRefreshEntry); - - if (mHiiPackageListUpdated) { - // - // Package list is updated, force to reparse IFR binary of target Formset - // - mHiiPackageListUpdated = FALSE; - Selection->Action = UI_ACTION_REFRESH_FORMSET; - } -} - - -/** - Refresh screen. - -**/ -EFI_STATUS -RefreshForm ( - VOID - ) -{ - MENU_REFRESH_ENTRY *MenuRefreshEntry; - EFI_STATUS Status; - UI_MENU_SELECTION *Selection; - - if (gMenuRefreshHead != NULL) { - // - // call from refresh interval process. - // - MenuRefreshEntry = gMenuRefreshHead; - Selection = MenuRefreshEntry->Selection; - // - // Reset FormPackage update flag - // - mHiiPackageListUpdated = FALSE; - - do { - Status = RefreshQuestion (MenuRefreshEntry); - if (EFI_ERROR (Status)) { - return Status; - } - - MenuRefreshEntry = MenuRefreshEntry->Next; - - } while (MenuRefreshEntry != NULL); - - if (mHiiPackageListUpdated) { - // - // Package list is updated, force to reparse IFR binary of target Formset - // - mHiiPackageListUpdated = FALSE; - Selection->Action = UI_ACTION_REFRESH_FORMSET; - return EFI_SUCCESS; - } - } - - return EFI_TIMEOUT; -} - - -/** - Wait for a given event to fire, or for an optional timeout to expire. - - @param Event The event to wait for - @param Timeout An optional timeout value in 100 ns units. - @param RefreshInterval Menu refresh interval (in seconds). - - @retval EFI_SUCCESS Event fired before Timeout expired. - @retval EFI_TIME_OUT Timout expired before Event fired. - -**/ -EFI_STATUS -UiWaitForSingleEvent ( - IN EFI_EVENT Event, - IN UINT64 Timeout, OPTIONAL - IN UINT8 RefreshInterval OPTIONAL - ) -{ - EFI_STATUS Status; - UINTN Index; - EFI_EVENT TimerEvent; - EFI_EVENT WaitList[2]; - - if (Timeout != 0) { - // - // Create a timer event - // - Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); - if (!EFI_ERROR (Status)) { - // - // Set the timer event - // - gBS->SetTimer ( - TimerEvent, - TimerRelative, - Timeout - ); - - // - // Wait for the original event or the timer - // - WaitList[0] = Event; - WaitList[1] = TimerEvent; - Status = gBS->WaitForEvent (2, WaitList, &Index); - gBS->CloseEvent (TimerEvent); - - // - // If the timer expired, change the return to timed out - // - if (!EFI_ERROR (Status) && Index == 1) { - Status = EFI_TIMEOUT; - } - } - } else { - // - // Update screen every second - // - if (RefreshInterval == 0) { - Timeout = ONE_SECOND; - } else { - Timeout = RefreshInterval * ONE_SECOND; - } - - do { - Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); - - // - // Set the timer event - // - gBS->SetTimer ( - TimerEvent, - TimerRelative, - Timeout - ); - - // - // Wait for the original event or the timer - // - WaitList[0] = Event; - WaitList[1] = TimerEvent; - Status = gBS->WaitForEvent (2, WaitList, &Index); - - // - // If the timer expired, update anything that needs a refresh and keep waiting - // - if (!EFI_ERROR (Status) && Index == 1) { - Status = EFI_TIMEOUT; - if (RefreshInterval != 0) { - Status = RefreshForm (); - } - } - - gBS->CloseEvent (TimerEvent); - } while (Status == EFI_TIMEOUT); - } - - return Status; -} - - -/** - Add one menu option by specified description and context. - - @param String String description for this option. - @param Handle Hii handle for the package list. - @param Form The form this statement belong to. - @param Statement Statement of this Menu Option. - @param NumberOfLines Display lines for this Menu Option. - @param MenuItemCount The index for this Option in the Menu. - - @retval Pointer Pointer to the added Menu Option. - -**/ -UI_MENU_OPTION * -UiAddMenuOption ( - IN CHAR16 *String, - IN EFI_HII_HANDLE Handle, - IN FORM_BROWSER_FORM *Form, - IN FORM_BROWSER_STATEMENT *Statement, - IN UINT16 NumberOfLines, - IN UINT16 MenuItemCount - ) -{ - UI_MENU_OPTION *MenuOption; - UINTN Index; - UINTN Count; - - Count = 1; - MenuOption = NULL; - - if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { - // - // Add three MenuOptions for Date/Time - // Data format : [01/02/2004] [11:22:33] - // Line number : 0 0 1 0 0 1 - // - NumberOfLines = 0; - Count = 3; - - if (Statement->Storage == NULL) { - // - // For RTC type of date/time, set default refresh interval to be 1 second - // - if (Statement->RefreshInterval == 0) { - Statement->RefreshInterval = 1; - } - } - } - - for (Index = 0; Index < Count; Index++) { - MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION)); - ASSERT (MenuOption); - - MenuOption->Signature = UI_MENU_OPTION_SIGNATURE; - MenuOption->Description = String; - MenuOption->Handle = Handle; - MenuOption->ThisTag = Statement; - MenuOption->EntryNumber = MenuItemCount; - - if (Index == 2) { - // - // Override LineNumber for the MenuOption in Date/Time sequence - // - MenuOption->Skip = 1; - } else { - MenuOption->Skip = NumberOfLines; - } - MenuOption->Sequence = Index; - - if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut ) { - MenuOption->GrayOut = TRUE; - } else { - MenuOption->GrayOut = FALSE; - } - - // - // If the form or the question has the lock attribute, deal same as grayout. - // - if (Form->Locked || Statement->Locked) { - MenuOption->GrayOut = TRUE; - } - - switch (Statement->Operand) { - case EFI_IFR_ORDERED_LIST_OP: - case EFI_IFR_ONE_OF_OP: - case EFI_IFR_NUMERIC_OP: - case EFI_IFR_TIME_OP: - case EFI_IFR_DATE_OP: - case EFI_IFR_CHECKBOX_OP: - case EFI_IFR_PASSWORD_OP: - case EFI_IFR_STRING_OP: - // - // User could change the value of these items - // - MenuOption->IsQuestion = TRUE; - break; - - case EFI_IFR_TEXT_OP: - if (FeaturePcdGet (PcdBrowserGrayOutTextStatement)) { - // - // Initializing GrayOut option as TRUE for Text setup options - // so that those options will be Gray in colour and un selectable. - // - MenuOption->GrayOut = TRUE; - } - // - // break skipped on purpose - // - default: - MenuOption->IsQuestion = FALSE; - break; - } - - if ((Statement->ValueExpression != NULL) || - ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) { - MenuOption->ReadOnly = TRUE; - if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu)) { - MenuOption->GrayOut = TRUE; - } - } - - InsertTailList (&gMenuOption, &MenuOption->Link); - } - - return MenuOption; -} - - -/** - Routine used to abstract a generic dialog interface and return the selected key or string - - @param NumberOfLines The number of lines for the dialog box - @param HotKey Defines whether a single character is parsed - (TRUE) and returned in KeyValue or a string is - returned in StringBuffer. Two special characters - are considered when entering a string, a SCAN_ESC - and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates - string input and returns - @param MaximumStringSize The maximum size in bytes of a typed in string - (each character is a CHAR16) and the minimum - string returned is two bytes - @param StringBuffer The passed in pointer to the buffer which will - hold the typed in string if HotKey is FALSE - @param KeyValue The EFI_KEY value returned if HotKey is TRUE.. - @param ... A series of (quantity == NumberOfLines) text - strings which will be used to construct the dialog - box - - @retval EFI_SUCCESS Displayed dialog and received user interaction - @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g. - (StringBuffer == NULL) && (HotKey == FALSE)) - @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine - -**/ -EFI_STATUS -EFIAPI -CreateDialog ( - IN UINTN NumberOfLines, - IN BOOLEAN HotKey, - IN UINTN MaximumStringSize, - OUT CHAR16 *StringBuffer, - OUT EFI_INPUT_KEY *KeyValue, - ... - ) -{ - VA_LIST Marker; - UINTN Count; - EFI_INPUT_KEY Key; - UINTN LargestString; - CHAR16 *TempString; - CHAR16 *BufferedString; - CHAR16 *StackString; - CHAR16 KeyPad[2]; - UINTN Start; - UINTN Top; - UINTN Index; - EFI_STATUS Status; - BOOLEAN SelectionComplete; - UINTN InputOffset; - UINTN CurrentAttribute; - UINTN DimensionsWidth; - UINTN DimensionsHeight; - - DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; - DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; - - SelectionComplete = FALSE; - InputOffset = 0; - TempString = AllocateZeroPool (MaximumStringSize * 2); - BufferedString = AllocateZeroPool (MaximumStringSize * 2); - CurrentAttribute = gST->ConOut->Mode->Attribute; - - ASSERT (TempString); - ASSERT (BufferedString); - - // - // Zero the outgoing buffer - // - ZeroMem (StringBuffer, MaximumStringSize); - - if (HotKey) { - if (KeyValue == NULL) { - return EFI_INVALID_PARAMETER; - } - } else { - if (StringBuffer == NULL) { - return EFI_INVALID_PARAMETER; - } - } - // - // Disable cursor - // - gST->ConOut->EnableCursor (gST->ConOut, FALSE); - - LargestString = 0; - - VA_START (Marker, KeyValue); - - // - // Determine the largest string in the dialog box - // Notice we are starting with 1 since String is the first string - // - for (Count = 0; Count < NumberOfLines; Count++) { - StackString = VA_ARG (Marker, CHAR16 *); - - if (StackString[0] == L' ') { - InputOffset = Count + 1; - } - - if ((GetStringWidth (StackString) / 2) > LargestString) { - // - // Size of the string visually and subtract the width by one for the null-terminator - // - LargestString = (GetStringWidth (StackString) / 2); - } - } - VA_END (Marker); - - Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1; - Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; - - Count = 0; - - // - // Display the Popup - // - VA_START (Marker, KeyValue); - CreateSharedPopUp (LargestString, NumberOfLines, Marker); - VA_END (Marker); - - // - // Take the first key typed and report it back? - // - if (HotKey) { - Status = WaitForKeyStroke (&Key); - ASSERT_EFI_ERROR (Status); - CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY)); - - } else { - do { - Status = WaitForKeyStroke (&Key); - - switch (Key.UnicodeChar) { - case CHAR_NULL: - switch (Key.ScanCode) { - case SCAN_ESC: - FreePool (TempString); - FreePool (BufferedString); - gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - return EFI_DEVICE_ERROR; - - default: - break; - } - - break; - - case CHAR_CARRIAGE_RETURN: - SelectionComplete = TRUE; - FreePool (TempString); - FreePool (BufferedString); - gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - return EFI_SUCCESS; - break; - - case CHAR_BACKSPACE: - if (StringBuffer[0] != CHAR_NULL) { - for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) { - TempString[Index] = StringBuffer[Index]; - } - // - // Effectively truncate string by 1 character - // - TempString[Index - 1] = CHAR_NULL; - StrCpy (StringBuffer, TempString); - } - // - // break skipped on purpose - // - - default: - // - // If it is the beginning of the string, don't worry about checking maximum limits - // - if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { - StrnCpy (StringBuffer, &Key.UnicodeChar, 1); - StrnCpy (TempString, &Key.UnicodeChar, 1); - } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) { - KeyPad[0] = Key.UnicodeChar; - KeyPad[1] = CHAR_NULL; - StrCat (StringBuffer, KeyPad); - StrCat (TempString, KeyPad); - } - // - // If the width of the input string is now larger than the screen, we nee to - // adjust the index to start printing portions of the string - // - SetUnicodeMem (BufferedString, LargestString, L' '); - - PrintStringAt (Start + 1, Top + InputOffset, BufferedString); - - if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) { - Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2; - } else { - Index = 0; - } - - for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) { - BufferedString[Count] = StringBuffer[Index]; - } - - PrintStringAt (Start + 1, Top + InputOffset, BufferedString); - break; - } - } while (!SelectionComplete); - } - - gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - return EFI_SUCCESS; -} - -/** - Draw a pop up windows based on the dimension, number of lines and - strings specified. - - @param RequestedWidth The width of the pop-up. - @param NumberOfLines The number of lines. - @param Marker The variable argument list for the list of string to be printed. - -**/ -VOID -CreateSharedPopUp ( - IN UINTN RequestedWidth, - IN UINTN NumberOfLines, - IN VA_LIST Marker - ) -{ - UINTN Index; - UINTN Count; - CHAR16 Character; - UINTN Start; - UINTN End; - UINTN Top; - UINTN Bottom; - CHAR16 *String; - UINTN DimensionsWidth; - UINTN DimensionsHeight; - - DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; - DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; - - gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); - - if ((RequestedWidth + 2) > DimensionsWidth) { - RequestedWidth = DimensionsWidth - 2; - } - - // - // Subtract the PopUp width from total Columns, allow for one space extra on - // each end plus a border. - // - Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1; - End = Start + RequestedWidth + 1; - - Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; - Bottom = Top + NumberOfLines + 2; - - Character = BOXDRAW_DOWN_RIGHT; - PrintCharAt (Start, Top, Character); - Character = BOXDRAW_HORIZONTAL; - for (Index = Start; Index + 2 < End; Index++) { - PrintChar (Character); - } - - Character = BOXDRAW_DOWN_LEFT; - PrintChar (Character); - Character = BOXDRAW_VERTICAL; - - Count = 0; - for (Index = Top; Index + 2 < Bottom; Index++, Count++) { - String = VA_ARG (Marker, CHAR16*); - - // - // This will clear the background of the line - we never know who might have been - // here before us. This differs from the next clear in that it used the non-reverse - // video for normal printing. - // - if (GetStringWidth (String) / 2 > 1) { - ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND); - } - - // - // Passing in a space results in the assumption that this is where typing will occur - // - if (String[0] == L' ') { - ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND); - } - - // - // Passing in a NULL results in a blank space - // - if (String[0] == CHAR_NULL) { - ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND); - } - - PrintStringAt ( - ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1, - Index + 1, - String - ); - gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); - PrintCharAt (Start, Index + 1, Character); - PrintCharAt (End - 1, Index + 1, Character); - } - - Character = BOXDRAW_UP_RIGHT; - PrintCharAt (Start, Bottom - 1, Character); - Character = BOXDRAW_HORIZONTAL; - for (Index = Start; Index + 2 < End; Index++) { - PrintChar (Character); - } - - Character = BOXDRAW_UP_LEFT; - PrintChar (Character); -} - -/** - Draw a pop up windows based on the dimension, number of lines and - strings specified. - - @param RequestedWidth The width of the pop-up. - @param NumberOfLines The number of lines. - @param ... A series of text strings that displayed in the pop-up. - -**/ -VOID -EFIAPI -CreateMultiStringPopUp ( - IN UINTN RequestedWidth, - IN UINTN NumberOfLines, - ... - ) -{ - VA_LIST Marker; - - VA_START (Marker, NumberOfLines); - - CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker); - - VA_END (Marker); -} - - -/** - Update status bar on the bottom of menu. - - @param Selection Current Selction info. - @param MessageType The type of message to be shown. - @param Flags The flags in Question header. - @param State Set or clear. - -**/ -VOID -UpdateStatusBar ( - IN UI_MENU_SELECTION *Selection, - IN UINTN MessageType, - IN UINT8 Flags, - IN BOOLEAN State - ) -{ - UINTN Index; - CHAR16 *NvUpdateMessage; - CHAR16 *InputErrorMessage; - LIST_ENTRY *Link; - FORM_BROWSER_FORMSET *LocalFormSet; - FORM_BROWSER_STATEMENT *Question; - - NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle); - InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle); - - switch (MessageType) { - case INPUT_ERROR: - if (State) { - gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT); - PrintStringAt ( - gScreenDimensions.LeftColumn + gPromptBlockWidth, - gScreenDimensions.BottomRow - 1, - InputErrorMessage - ); - mInputError = TRUE; - } else { - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor)); - for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) { - PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L" "); - } - - mInputError = FALSE; - } - break; - - case NV_UPDATE_REQUIRED: - // - // Global setting support. Show configuration change on every form. - // - if (State) { - gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED)); - - if (Selection != NULL && Selection->Statement != NULL) { - Question = Selection->Statement; - if (Question->Storage != NULL || Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { - // - // Update only for Question value that need to be saved into Storage. - // - Selection->Form->NvUpdateRequired = TRUE; - } - } - - if (Selection == NULL || IsNvUpdateRequired (Selection->FormSet)) { - gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT); - PrintStringAt ( - gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth, - gScreenDimensions.BottomRow - 1, - NvUpdateMessage - ); - } - } else { - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor)); - for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) { - PrintAt ( - (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index), - gScreenDimensions.BottomRow - 1, - L" " - ); - } - } - break; - - case REFRESH_STATUS_BAR: - if (mInputError) { - UpdateStatusBar (Selection, INPUT_ERROR, Flags, TRUE); - } - - switch (gBrowserSettingScope) { - case SystemLevel: - // - // Check the maintain list to see whether there is any change. - // - Link = GetFirstNode (&gBrowserFormSetList); - while (!IsNull (&gBrowserFormSetList, Link)) { - LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); - if (IsNvUpdateRequired(LocalFormSet)) { - UpdateStatusBar (NULL, NV_UPDATE_REQUIRED, Flags, TRUE); - break; - } - Link = GetNextNode (&gBrowserFormSetList, Link); - } - break; - case FormSetLevel: - case FormLevel: - UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Flags, TRUE); - default: - break; - } - - break; - - default: - break; - } - - FreePool (InputErrorMessage); - FreePool (NvUpdateMessage); - return ; -} - - -/** - Get the supported width for a particular op-code - - @param Statement The FORM_BROWSER_STATEMENT structure passed in. - @param Handle The handle in the HII database being used - - @return Returns the number of CHAR16 characters that is support. - -**/ -UINT16 -GetWidth ( - IN FORM_BROWSER_STATEMENT *Statement, - IN EFI_HII_HANDLE Handle - ) -{ - CHAR16 *String; - UINTN Size; - UINT16 Width; - - Size = 0; - - // - // See if the second text parameter is really NULL - // - if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) { - String = GetToken (Statement->TextTwo, Handle); - Size = StrLen (String); - FreePool (String); - } - - if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) || - (Statement->Operand == EFI_IFR_REF_OP) || - (Statement->Operand == EFI_IFR_PASSWORD_OP) || - (Statement->Operand == EFI_IFR_ACTION_OP) || - (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) || - // - // Allow a wide display if text op-code and no secondary text op-code - // - ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0)) - ) { - Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth); - } else { - Width = (UINT16) gPromptBlockWidth; - } - - if (Statement->InSubtitle) { - Width -= SUBTITLE_INDENT; - } - - return (UINT16) (Width - LEFT_SKIPPED_COLUMNS); -} - -/** - Will copy LineWidth amount of a string in the OutputString buffer and return the - number of CHAR16 characters that were copied into the OutputString buffer. - The output string format is: - Glyph Info + String info + '\0'. - - In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g. - - @param InputString String description for this option. - @param LineWidth Width of the desired string to extract in CHAR16 - characters - @param GlyphWidth The glyph width of the begin of the char in the string. - @param Index Where in InputString to start the copy process - @param OutputString Buffer to copy the string into - - @return Returns the number of CHAR16 characters that were copied into the OutputString - buffer, include extra glyph info and '\0' info. - -**/ -UINT16 -GetLineByWidth ( - IN CHAR16 *InputString, - IN UINT16 LineWidth, - IN OUT UINT16 *GlyphWidth, - IN OUT UINTN *Index, - OUT CHAR16 **OutputString - ) -{ - UINT16 StrOffset; - UINT16 GlyphOffset; - UINT16 OriginalGlyphWidth; - BOOLEAN ReturnFlag; - UINT16 LastSpaceOffset; - UINT16 LastGlyphWidth; - - if (InputString == NULL || Index == NULL || OutputString == NULL) { - return 0; - } - - if (LineWidth == 0 || *GlyphWidth == 0) { - return 0; - } - - // - // Save original glyph width. - // - OriginalGlyphWidth = *GlyphWidth; - LastGlyphWidth = OriginalGlyphWidth; - ReturnFlag = FALSE; - LastSpaceOffset = 0; - - // - // NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen. - // To avoid displaying this empty line in screen, just skip the two CHARs here. - // - if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) { - *Index = *Index + 2; - } - - // - // Fast-forward the string and see if there is a carriage-return in the string - // - for (StrOffset = 0, GlyphOffset = 0; GlyphOffset <= LineWidth; StrOffset++) { - switch (InputString[*Index + StrOffset]) { - case NARROW_CHAR: - *GlyphWidth = 1; - break; - - case WIDE_CHAR: - *GlyphWidth = 2; - break; - - case CHAR_CARRIAGE_RETURN: - case CHAR_LINEFEED: - case CHAR_NULL: - ReturnFlag = TRUE; - break; - - default: - GlyphOffset = GlyphOffset + *GlyphWidth; - - // - // Record the last space info in this line. Will be used in rewind. - // - if ((InputString[*Index + StrOffset] == CHAR_SPACE) && (GlyphOffset <= LineWidth)) { - LastSpaceOffset = StrOffset; - LastGlyphWidth = *GlyphWidth; - } - break; - } - - if (ReturnFlag) { - break; - } - } - - // - // Rewind the string from the maximum size until we see a space to break the line - // - if (GlyphOffset > LineWidth) { - // - // Rewind the string to last space char in this line. - // - if (LastSpaceOffset != 0) { - StrOffset = LastSpaceOffset; - *GlyphWidth = LastGlyphWidth; - } else { - // - // Roll back to last char in the line width. - // - StrOffset--; - } - } - - // - // The CHAR_NULL has process last time, this time just return 0 to stand for the end. - // - if (StrOffset == 0 && (InputString[*Index + StrOffset] == CHAR_NULL)) { - return 0; - } - - // - // Need extra glyph info and '\0' info, so +2. - // - *OutputString = AllocateZeroPool (((UINTN) (StrOffset + 2) * sizeof(CHAR16))); - if (*OutputString == NULL) { - return 0; - } - - // - // Save the glyph info at the begin of the string, will used by Print function. - // - if (OriginalGlyphWidth == 1) { - *(*OutputString) = NARROW_CHAR; - } else { - *(*OutputString) = WIDE_CHAR; - } - - CopyMem ((*OutputString) + 1, &InputString[*Index], StrOffset * sizeof(CHAR16)); - - if (InputString[*Index + StrOffset] == CHAR_SPACE) { - // - // Skip the space info at the begin of next line. - // - *Index = (UINT16) (*Index + StrOffset + 1); - } else if (InputString[*Index + StrOffset] == CHAR_LINEFEED) { - // - // Skip the /n or /n/r info. - // - if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) { - *Index = (UINT16) (*Index + StrOffset + 2); - } else { - *Index = (UINT16) (*Index + StrOffset + 1); - } - } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) { - // - // Skip the /r or /r/n info. - // - if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) { - *Index = (UINT16) (*Index + StrOffset + 2); - } else { - *Index = (UINT16) (*Index + StrOffset + 1); - } - } else { - *Index = (UINT16) (*Index + StrOffset); - } - - // - // Include extra glyph info and '\0' info, so +2. - // - return StrOffset + 2; -} - - -/** - Update display lines for a Menu Option. - - @param Selection The user's selection. - @param MenuOption The MenuOption to be checked. - -**/ -VOID -UpdateOptionSkipLines ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption - ) -{ - UINTN Index; - UINT16 Width; - UINTN Row; - UINTN OriginalRow; - CHAR16 *OutputString; - CHAR16 *OptionString; - UINT16 GlyphWidth; - - Row = 0; - OptionString = NULL; - Width = (UINT16) gOptionBlockWidth; - OriginalRow = 0; - GlyphWidth = 1; - - ProcessOptions (Selection, MenuOption, FALSE, &OptionString); - if (OptionString == NULL) { - return; - } - - for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&OptionString[Index]) != 0) { - Row++; - // - // Since the Number of lines for this menu entry may or may not be reflected accurately - // since the prompt might be 1 lines and option might be many, and vice versa, we need to do - // some testing to ensure we are keeping this in-sync. - // - // If the difference in rows is greater than or equal to the skip value, increase the skip value - // - if ((Row - OriginalRow) >= MenuOption->Skip) { - MenuOption->Skip++; - } - } - - FreePool (OutputString); - } - - if (OptionString != NULL) { - FreePool (OptionString); - } -} - - -/** - Check whether this Menu Option could be highlighted. - - This is an internal function. - - @param MenuOption The MenuOption to be checked. - - @retval TRUE This Menu Option is selectable. - @retval FALSE This Menu Option could not be selected. - -**/ -BOOLEAN -IsSelectable ( - UI_MENU_OPTION *MenuOption - ) -{ - if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) || - MenuOption->GrayOut || MenuOption->ReadOnly) { - return FALSE; - } else { - return TRUE; - } -} - - -/** - Determine if the menu is the last menu that can be selected. - - This is an internal function. - - @param Direction The scroll direction. False is down. True is up. - @param CurrentPos The current focus. - - @return FALSE -- the menu isn't the last menu that can be selected. - @return TRUE -- the menu is the last menu that can be selected. - -**/ -BOOLEAN -ValueIsScroll ( - IN BOOLEAN Direction, - IN LIST_ENTRY *CurrentPos - ) -{ - LIST_ENTRY *Temp; - - Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink; - - if (Temp == &gMenuOption) { - return TRUE; - } - - return FALSE; -} - - -/** - Move to next selectable statement. - - This is an internal function. - - @param Selection Menu selection. - @param GoUp The navigation direction. TRUE: up, FALSE: down. - @param CurrentPosition Current position. - @param GapToTop Gap position to top or bottom. - - @return The row distance from current MenuOption to next selectable MenuOption. - - @retval -1 Reach the begin of the menu, still can't find the selectable menu. - @retval Value Find the selectable menu, maybe the truly selectable, maybe the l - last menu showing at current form. - -**/ -INTN -MoveToNextStatement ( - IN UI_MENU_SELECTION *Selection, - IN BOOLEAN GoUp, - IN OUT LIST_ENTRY **CurrentPosition, - IN UINTN GapToTop - ) -{ - INTN Distance; - LIST_ENTRY *Pos; - UI_MENU_OPTION *NextMenuOption; - UI_MENU_OPTION *PreMenuOption; - - Distance = 0; - Pos = *CurrentPosition; - PreMenuOption = MENU_OPTION_FROM_LINK (Pos); - - while (TRUE) { - NextMenuOption = MENU_OPTION_FROM_LINK (Pos); - // - // NextMenuOption->Row == 0 means this menu has not calculate - // the NextMenuOption->Skip value yet, just calculate here. - // - if (NextMenuOption->Row == 0) { - UpdateOptionSkipLines (Selection, NextMenuOption); - } - - if (GoUp && (PreMenuOption != NextMenuOption)) { - // - // In this case, still can't find the selectable menu, - // return the last one in the showing form. - // - if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) { - NextMenuOption = PreMenuOption; - break; - } - - // - // Current Position doesn't need to be caculated when go up. - // Caculate distanct at first when go up - // - Distance += NextMenuOption->Skip; - } - - if (IsSelectable (NextMenuOption)) { - break; - } - - // - // Arrive at begin of the menu list. - // - if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) { - Distance = -1; - break; - } - - if (!GoUp) { - // - // In this case, still can't find the selectable menu, - // return the last one in the showing form. - // - if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) { - NextMenuOption = PreMenuOption; - break; - } - - Distance += NextMenuOption->Skip; - } - - PreMenuOption = NextMenuOption; - Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink); - } - - *CurrentPosition = &NextMenuOption->Link; - return Distance; -} - - -/** - Adjust Data and Time position accordingly. - Data format : [01/02/2004] [11:22:33] - Line number : 0 0 1 0 0 1 - - This is an internal function. - - @param DirectionUp the up or down direction. False is down. True is - up. - @param CurrentPosition Current position. On return: Point to the last - Option (Year or Second) if up; Point to the first - Option (Month or Hour) if down. - - @return Return line number to pad. It is possible that we stand on a zero-advance - @return data or time opcode, so pad one line when we judge if we are going to scroll outside. - -**/ -UINTN -AdjustDateAndTimePosition ( - IN BOOLEAN DirectionUp, - IN OUT LIST_ENTRY **CurrentPosition - ) -{ - UINTN Count; - LIST_ENTRY *NewPosition; - UI_MENU_OPTION *MenuOption; - UINTN PadLineNumber; - - PadLineNumber = 0; - NewPosition = *CurrentPosition; - MenuOption = MENU_OPTION_FROM_LINK (NewPosition); - - if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || - (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { - // - // Calculate the distance from current position to the last Date/Time MenuOption - // - Count = 0; - while (MenuOption->Skip == 0) { - Count++; - NewPosition = NewPosition->ForwardLink; - MenuOption = MENU_OPTION_FROM_LINK (NewPosition); - PadLineNumber = 1; - } - - NewPosition = *CurrentPosition; - if (DirectionUp) { - // - // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended - // to be one that back to the previous set of MenuOptions, we need to advance to the first - // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate - // checking can be done. - // - while (Count++ < 2) { - NewPosition = NewPosition->BackLink; - } - } else { - // - // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended - // to be one that progresses to the next set of MenuOptions, we need to advance to the last - // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate - // checking can be done. - // - while (Count-- > 0) { - NewPosition = NewPosition->ForwardLink; - } - } - - *CurrentPosition = NewPosition; - } - - return PadLineNumber; -} - -/** - Find HII Handle in the HII database associated with given Device Path. - - If DevicePath is NULL, then ASSERT. - - @param DevicePath Device Path associated with the HII package list - handle. - - @retval Handle HII package list Handle associated with the Device - Path. - @retval NULL Hii Package list handle is not found. - -**/ -EFI_HII_HANDLE -EFIAPI -DevicePathToHiiHandle ( - IN EFI_DEVICE_PATH_PROTOCOL *DevicePath - ) -{ - EFI_STATUS Status; - EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; - UINTN BufferSize; - UINTN HandleCount; - UINTN Index; - EFI_HANDLE Handle; - EFI_HANDLE DriverHandle; - EFI_HII_HANDLE *HiiHandles; - EFI_HII_HANDLE HiiHandle; - - ASSERT (DevicePath != NULL); - - TmpDevicePath = DevicePath; - // - // Locate Device Path Protocol handle buffer - // - Status = gBS->LocateDevicePath ( - &gEfiDevicePathProtocolGuid, - &TmpDevicePath, - &DriverHandle - ); - if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) { - return NULL; - } - - // - // Retrieve all HII Handles from HII database - // - BufferSize = 0x1000; - HiiHandles = AllocatePool (BufferSize); - ASSERT (HiiHandles != NULL); - Status = mHiiDatabase->ListPackageLists ( - mHiiDatabase, - EFI_HII_PACKAGE_TYPE_ALL, - NULL, - &BufferSize, - HiiHandles - ); - if (Status == EFI_BUFFER_TOO_SMALL) { - FreePool (HiiHandles); - HiiHandles = AllocatePool (BufferSize); - ASSERT (HiiHandles != NULL); - - Status = mHiiDatabase->ListPackageLists ( - mHiiDatabase, - EFI_HII_PACKAGE_TYPE_ALL, - NULL, - &BufferSize, - HiiHandles - ); - } - - if (EFI_ERROR (Status)) { - FreePool (HiiHandles); - return NULL; - } - - // - // Search Hii Handle by Driver Handle - // - HiiHandle = NULL; - HandleCount = BufferSize / sizeof (EFI_HII_HANDLE); - for (Index = 0; Index < HandleCount; Index++) { - Status = mHiiDatabase->GetPackageListHandle ( - mHiiDatabase, - HiiHandles[Index], - &Handle - ); - if (!EFI_ERROR (Status) && (Handle == DriverHandle)) { - HiiHandle = HiiHandles[Index]; - break; - } - } - - FreePool (HiiHandles); - return HiiHandle; -} - -/** - Find HII Handle in the HII database associated with given form set guid. - - If FormSetGuid is NULL, then ASSERT. - - @param ComparingGuid FormSet Guid associated with the HII package list - handle. - - @retval Handle HII package list Handle associated with the Device - Path. - @retval NULL Hii Package list handle is not found. - -**/ -EFI_HII_HANDLE -FormSetGuidToHiiHandle ( - EFI_GUID *ComparingGuid - ) -{ - EFI_HII_HANDLE *HiiHandles; - UINTN Index; - EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; - UINTN BufferSize; - UINT32 Offset; - UINT32 Offset2; - UINT32 PackageListLength; - EFI_HII_PACKAGE_HEADER PackageHeader; - UINT8 *Package; - UINT8 *OpCodeData; - EFI_STATUS Status; - EFI_HII_HANDLE HiiHandle; - - ASSERT (ComparingGuid != NULL); - - HiiHandle = NULL; - // - // Get all the Hii handles - // - HiiHandles = HiiGetHiiHandles (NULL); - ASSERT (HiiHandles != NULL); - - // - // Search for formset of each class type - // - for (Index = 0; HiiHandles[Index] != NULL; Index++) { - BufferSize = 0; - HiiPackageList = NULL; - Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList); - if (Status == EFI_BUFFER_TOO_SMALL) { - HiiPackageList = AllocatePool (BufferSize); - ASSERT (HiiPackageList != NULL); - - Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList); - } - if (EFI_ERROR (Status) || HiiPackageList == NULL) { - return NULL; - } - - // - // Get Form package from this HII package List - // - Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); - Offset2 = 0; - CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); - - while (Offset < PackageListLength) { - Package = ((UINT8 *) HiiPackageList) + Offset; - CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); - - if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) { - // - // Search FormSet in this Form Package - // - Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); - while (Offset2 < PackageHeader.Length) { - OpCodeData = Package + Offset2; - - if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { - // - // Try to compare against formset GUID - // - if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { - HiiHandle = HiiHandles[Index]; - break; - } - } - - Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; - } - } - if (HiiHandle != NULL) { - break; - } - Offset += PackageHeader.Length; - } - - FreePool (HiiPackageList); - if (HiiHandle != NULL) { - break; - } - } - - FreePool (HiiHandles); - - return HiiHandle; -} - -/** - Process the goto op code, update the info in the selection structure. - - @param Statement The statement belong to goto op code. - @param Selection The selection info. - @param Repaint Whether need to repaint the menu. - @param NewLine Whether need to create new line. - - @retval EFI_SUCCESS The menu process successfully. - @return Other value if the process failed. -**/ -EFI_STATUS -ProcessGotoOpCode ( - IN OUT FORM_BROWSER_STATEMENT *Statement, - IN OUT UI_MENU_SELECTION *Selection, - OUT BOOLEAN *Repaint, - OUT BOOLEAN *NewLine - ) -{ - CHAR16 *StringPtr; - EFI_DEVICE_PATH_PROTOCOL *DevicePath; - FORM_BROWSER_FORM *RefForm; - EFI_INPUT_KEY Key; - EFI_STATUS Status; - - Status = EFI_SUCCESS; - StringPtr = NULL; - - // - // Prepare the device path check, get the device path info first. - // - if (Statement->HiiValue.Value.ref.DevicePath != 0) { - StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle); - } - - // - // Check whether the device path string is a valid string. - // - if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL) { - if (Selection->Form->ModalForm) { - return Status; - } - - // - // Goto another Hii Package list - // - if (mPathFromText != NULL) { - DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr); - if (DevicePath != NULL) { - Selection->Handle = DevicePathToHiiHandle (DevicePath); - FreePool (DevicePath); - } - FreePool (StringPtr); - } else { - // - // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol. - // - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gProtocolNotFound, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - if (Repaint != NULL) { - *Repaint = TRUE; - } - FreePool (StringPtr); - return Status; - } - - Selection->Action = UI_ACTION_REFRESH_FORMSET; - if (Selection->Handle == NULL) { - // - // If target Hii Handle not found, exit - // - Selection->Action = UI_ACTION_EXIT; - Selection->Statement = NULL; - return Status; - } - - CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID)); - Selection->FormId = Statement->HiiValue.Value.ref.FormId; - Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; - } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) { - if (Selection->Form->ModalForm) { - return Status; - } - // - // Goto another Formset, check for uncommitted data - // - Selection->Action = UI_ACTION_REFRESH_FORMSET; - - Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid); - if (Selection->Handle == NULL) { - // - // If target Hii Handle not found, exit - // - Selection->Action = UI_ACTION_EXIT; - Selection->Statement = NULL; - return Status; - } - - CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID)); - Selection->FormId = Statement->HiiValue.Value.ref.FormId; - Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; - } else if (Statement->HiiValue.Value.ref.FormId != 0) { - // - // Check whether target From is suppressed. - // - RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId); - - if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) { - if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) { - // - // Form is suppressed. - // - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - if (Repaint != NULL) { - *Repaint = TRUE; - } - return Status; - } - } - - // - // Goto another form inside this formset, - // - Selection->Action = UI_ACTION_REFRESH_FORM; - - Selection->FormId = Statement->HiiValue.Value.ref.FormId; - Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; - } else if (Statement->HiiValue.Value.ref.QuestionId != 0) { - // - // Goto another Question - // - Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; - - if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { - Selection->Action = UI_ACTION_REFRESH_FORM; - } else { - if (Repaint != NULL) { - *Repaint = TRUE; - } - if (NewLine != NULL) { - *NewLine = TRUE; - } - } - } else { - if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { - Selection->Action = UI_ACTION_REFRESH_FORM; - } - } - - return Status; -} - -/** - Display menu and wait for user to select one menu option, then return it. - If AutoBoot is enabled, then if user doesn't select any option, - after period of time, it will automatically return the first menu option. - - @param Selection Menu selection. - - @retval EFI_SUCESSS This function always return successfully for now. - -**/ -EFI_STATUS -UiDisplayMenu ( - IN OUT UI_MENU_SELECTION *Selection - ) -{ - INTN SkipValue; - INTN Difference; - UINTN DistanceValue; - UINTN Row; - UINTN Col; - UINTN Temp; - UINTN Temp2; - UINTN TopRow; - UINTN BottomRow; - UINTN OriginalRow; - UINTN Index; - UINT16 Width; - CHAR16 *StringPtr; - CHAR16 *OptionString; - CHAR16 *OutputString; - CHAR16 *HelpString; - CHAR16 *HelpHeaderString; - CHAR16 *HelpBottomString; - BOOLEAN NewLine; - BOOLEAN Repaint; - BOOLEAN SavedValue; - BOOLEAN UpArrow; - BOOLEAN DownArrow; - BOOLEAN InitializedFlag; - EFI_STATUS Status; - EFI_INPUT_KEY Key; - LIST_ENTRY *Link; - LIST_ENTRY *NewPos; - LIST_ENTRY *TopOfScreen; - LIST_ENTRY *SavedListEntry; - UI_MENU_OPTION *MenuOption; - UI_MENU_OPTION *NextMenuOption; - UI_MENU_OPTION *SavedMenuOption; - UI_MENU_OPTION *PreviousMenuOption; - UI_CONTROL_FLAG ControlFlag; - EFI_SCREEN_DESCRIPTOR LocalScreen; - MENU_REFRESH_ENTRY *MenuRefreshEntry; - MENU_REFRESH_ENTRY *MenuUpdateEntry; - UI_SCREEN_OPERATION ScreenOperation; - UINT8 MinRefreshInterval; - UINT16 DefaultId; - FORM_BROWSER_STATEMENT *Statement; - UI_MENU_LIST *CurrentMenu; - UINTN ModalSkipColumn; - BROWSER_HOT_KEY *HotKey; - UINTN HelpPageIndex; - UINTN HelpPageCount; - UINTN RowCount; - UINTN HelpLine; - UINTN HelpHeaderLine; - UINTN HelpBottomLine; - BOOLEAN MultiHelpPage; - UINT16 GlyphWidth; - UINT16 EachLineWidth; - UINT16 HeaderLineWidth; - UINT16 BottomLineWidth; - - CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - - Status = EFI_SUCCESS; - HelpString = NULL; - HelpHeaderString = NULL; - HelpBottomString = NULL; - OptionString = NULL; - ScreenOperation = UiNoOperation; - NewLine = TRUE; - MinRefreshInterval = 0; - DefaultId = 0; - HelpPageCount = 0; - HelpLine = 0; - RowCount = 0; - HelpBottomLine = 0; - HelpHeaderLine = 0; - HelpPageIndex = 0; - MultiHelpPage = FALSE; - EachLineWidth = 0; - HeaderLineWidth = 0; - BottomLineWidth = 0; - OutputString = NULL; - UpArrow = FALSE; - DownArrow = FALSE; - SkipValue = 0; - MenuRefreshEntry = gMenuRefreshHead; - - NextMenuOption = NULL; - PreviousMenuOption = NULL; - SavedMenuOption = NULL; - HotKey = NULL; - ModalSkipColumn = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 6; - - ZeroMem (&Key, sizeof (EFI_INPUT_KEY)); - - if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE){ - TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; - Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; - } else { - TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; - Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; - } - - if (Selection->Form->ModalForm) { - Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS + ModalSkipColumn; - } else { - Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS; - } - - BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - SCROLL_ARROW_HEIGHT - 1; - - Selection->TopRow = TopRow; - Selection->BottomRow = BottomRow; - Selection->PromptCol = Col; - Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn; - Selection->Statement = NULL; - - TopOfScreen = gMenuOption.ForwardLink; - Repaint = TRUE; - MenuOption = NULL; - - // - // Find current Menu - // - CurrentMenu = UiFindMenuList (Selection->Handle, &Selection->FormSetGuid, Selection->FormId); - if (CurrentMenu == NULL) { - // - // Current menu not found, add it to the menu tree - // - CurrentMenu = UiAddMenuList (Selection->CurrentMenu, Selection->Handle, &Selection->FormSetGuid, Selection->FormId); - } - ASSERT (CurrentMenu != NULL); - Selection->CurrentMenu = CurrentMenu; - - if (Selection->QuestionId == 0) { - // - // Highlight not specified, fetch it from cached menu - // - Selection->QuestionId = CurrentMenu->QuestionId; - Selection->Sequence = CurrentMenu->Sequence; - } - - // - // Init option as the current user's selection - // - InitializedFlag = TRUE; - NewPos = gMenuOption.ForwardLink; - - gST->ConOut->EnableCursor (gST->ConOut, FALSE); - UpdateStatusBar (Selection, REFRESH_STATUS_BAR, (UINT8) 0, TRUE); - - ControlFlag = CfInitialization; - Selection->Action = UI_ACTION_NONE; - while (TRUE) { - switch (ControlFlag) { - case CfInitialization: - if (IsListEmpty (&gMenuOption)) { - ControlFlag = CfReadKey; - } else { - ControlFlag = CfCheckSelection; - } - break; - - case CfCheckSelection: - if (Selection->Action != UI_ACTION_NONE) { - ControlFlag = CfExit; - } else { - ControlFlag = CfRepaint; - } - break; - - case CfRepaint: - ControlFlag = CfRefreshHighLight; - - if (Repaint) { - // - // Display menu - // - DownArrow = FALSE; - UpArrow = FALSE; - Row = TopRow; - - Temp = (UINTN) SkipValue; - Temp2 = (UINTN) SkipValue; - - // - // 1. Clear the screen. - // - if (Selection->Form->ModalForm) { - ClearLines ( - LocalScreen.LeftColumn + ModalSkipColumn, - LocalScreen.LeftColumn + ModalSkipColumn + gPromptBlockWidth + gOptionBlockWidth, - TopRow - SCROLL_ARROW_HEIGHT, - BottomRow + SCROLL_ARROW_HEIGHT, - PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND - ); - } else { - ClearLines ( - LocalScreen.LeftColumn, - LocalScreen.RightColumn, - TopRow - SCROLL_ARROW_HEIGHT, - BottomRow + SCROLL_ARROW_HEIGHT, - PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND - ); - } - UiFreeRefreshList (); - MinRefreshInterval = 0; - - // - // 2.Paint the menu. - // - for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) { - MenuOption = MENU_OPTION_FROM_LINK (Link); - MenuOption->Row = Row; - MenuOption->Col = Col; - if (Selection->Form->ModalForm) { - MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn + ModalSkipColumn; - } else { - MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn; - } - - Statement = MenuOption->ThisTag; - if (Statement->InSubtitle) { - MenuOption->Col += SUBTITLE_INDENT; - } - - if (MenuOption->GrayOut) { - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); - } else { - if (Statement->Operand == EFI_IFR_SUBTITLE_OP) { - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND); - } - } - - Width = GetWidth (Statement, MenuOption->Handle); - OriginalRow = Row; - GlyphWidth = 1; - - if (Statement->Operand == EFI_IFR_REF_OP && MenuOption->Col >= 2) { - // - // Print Arrow for Goto button. - // - PrintAt ( - MenuOption->Col - 2, - Row, - L"%c", - GEOMETRICSHAPE_RIGHT_TRIANGLE - ); - } - - // - // 2.1. Paint the description. - // - for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { - // - // Temp means need to skip how many lines from the start. - // - if ((Temp == 0) && (Row <= BottomRow)) { - PrintStringAt (MenuOption->Col, Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&MenuOption->Description[Index]) != 0) { - if (Temp == 0) { - Row++; - } - } - - FreePool (OutputString); - if (Temp != 0) { - Temp--; - } - } - - Temp = 0; - Row = OriginalRow; - - // - // 2.2. Paint the option string. - // - Status = ProcessOptions (Selection, MenuOption, FALSE, &OptionString); - if (EFI_ERROR (Status)) { - // - // Repaint to clear possible error prompt pop-up - // - Repaint = TRUE; - NewLine = TRUE; - ControlFlag = CfRepaint; - break; - } - - if (OptionString != NULL) { - if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { - ProcessStringForDateTime(MenuOption, OptionString, TRUE); - } - - Width = (UINT16) gOptionBlockWidth; - OriginalRow = Row; - GlyphWidth = 1; - - for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { - if ((Temp2 == 0) && (Row <= BottomRow)) { - PrintStringAt (MenuOption->OptCol, Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&OptionString[Index]) != 0) { - if (Temp2 == 0) { - Row++; - // - // Since the Number of lines for this menu entry may or may not be reflected accurately - // since the prompt might be 1 lines and option might be many, and vice versa, we need to do - // some testing to ensure we are keeping this in-sync. - // - // If the difference in rows is greater than or equal to the skip value, increase the skip value - // - if ((Row - OriginalRow) >= MenuOption->Skip) { - MenuOption->Skip++; - } - } - } - - FreePool (OutputString); - if (Temp2 != 0) { - Temp2--; - } - } - - Temp2 = 0; - Row = OriginalRow; - - FreePool (OptionString); - } - - // - // 2.4 Special process for Test opcode with test two. - // - if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) { - if (gMenuEventGuidRefreshHead == NULL) { - MenuUpdateEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); - gMenuEventGuidRefreshHead = MenuUpdateEntry; - } else { - MenuUpdateEntry = gMenuEventGuidRefreshHead; - while (MenuUpdateEntry->Next != NULL) { - MenuUpdateEntry = MenuUpdateEntry->Next; - } - MenuUpdateEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); - MenuUpdateEntry = MenuUpdateEntry->Next; - } - ASSERT (MenuUpdateEntry != NULL); - Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, RefreshQuestionNotify, MenuUpdateEntry, &Statement->RefreshGuid, &MenuUpdateEntry->Event); - ASSERT (!EFI_ERROR (Status)); - MenuUpdateEntry->MenuOption = MenuOption; - MenuUpdateEntry->Selection = Selection; - MenuUpdateEntry->CurrentColumn = MenuOption->OptCol; - MenuUpdateEntry->CurrentRow = MenuOption->Row; - if (MenuOption->GrayOut) { - MenuUpdateEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND; - } else { - MenuUpdateEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND; - } - } - - // - // If Question request refresh, register the op-code - // - if (Statement->RefreshInterval != 0) { - // - // Menu will be refreshed at minimal interval of all Questions - // which have refresh request - // - if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) { - MinRefreshInterval = Statement->RefreshInterval; - } - - if (gMenuRefreshHead == NULL) { - MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); - gMenuRefreshHead = MenuRefreshEntry; - } else { - MenuRefreshEntry = gMenuRefreshHead; - while (MenuRefreshEntry->Next != NULL) { - MenuRefreshEntry = MenuRefreshEntry->Next; - } - MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); - MenuRefreshEntry = MenuRefreshEntry->Next; - } - ASSERT (MenuRefreshEntry != NULL); - MenuRefreshEntry->MenuOption = MenuOption; - MenuRefreshEntry->Selection = Selection; - MenuRefreshEntry->CurrentColumn = MenuOption->OptCol; - MenuRefreshEntry->CurrentRow = MenuOption->Row; - if (MenuOption->GrayOut) { - MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND; - } else { - MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND; - } - } - - // - // If this is a text op with secondary text information - // - if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) { - StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle); - - Width = (UINT16) gOptionBlockWidth; - OriginalRow = Row; - GlyphWidth = 1; - - for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { - if ((Temp == 0) && (Row <= BottomRow)) { - PrintStringAt (MenuOption->OptCol, Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&StringPtr[Index]) != 0) { - if (Temp2 == 0) { - Row++; - // - // Since the Number of lines for this menu entry may or may not be reflected accurately - // since the prompt might be 1 lines and option might be many, and vice versa, we need to do - // some testing to ensure we are keeping this in-sync. - // - // If the difference in rows is greater than or equal to the skip value, increase the skip value - // - if ((Row - OriginalRow) >= MenuOption->Skip) { - MenuOption->Skip++; - } - } - } - - FreePool (OutputString); - if (Temp2 != 0) { - Temp2--; - } - } - - Row = OriginalRow; - FreePool (StringPtr); - } - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND); - - // - // 3. Update the row info which will be used by next menu. - // - if (Link == TopOfScreen) { - Row += MenuOption->Skip - SkipValue; - } else { - Row += MenuOption->Skip; - } - - if (Row > BottomRow) { - if (!ValueIsScroll (FALSE, Link)) { - DownArrow = TRUE; - } - - Row = BottomRow + 1; - break; - } - } - - if (!ValueIsScroll (TRUE, TopOfScreen)) { - UpArrow = TRUE; - } - - if (UpArrow) { - gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); - PrintAt ( - LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, - TopRow - SCROLL_ARROW_HEIGHT, - L"%c", - ARROW_UP - ); - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND); - } - - if (DownArrow) { - gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); - PrintAt ( - LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, - BottomRow + SCROLL_ARROW_HEIGHT, - L"%c", - ARROW_DOWN - ); - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND); - } - - MenuOption = NULL; - } - break; - - case CfRefreshHighLight: - // - // MenuOption: Last menu option that need to remove hilight - // MenuOption is set to NULL in Repaint - // NewPos: Current menu option that need to hilight - // - ControlFlag = CfUpdateHelpString; - if (TopOfScreen == &MenuOption->Link) { - Temp = SkipValue; - } else { - Temp = 0; - } - if (NewPos == TopOfScreen) { - Temp2 = SkipValue; - } else { - Temp2 = 0; - } - if (InitializedFlag) { - InitializedFlag = FALSE; - MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow); - } - - // - // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily - // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing. - // - SavedValue = Repaint; - Repaint = FALSE; - - if (Selection->QuestionId != 0) { - NewPos = gMenuOption.ForwardLink; - SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); - - while ((SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId || - SavedMenuOption->Sequence != Selection->Sequence) && - NewPos->ForwardLink != &gMenuOption) { - NewPos = NewPos->ForwardLink; - SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); - } - if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) { - // - // Target Question found, find its MenuOption - // - Link = TopOfScreen; - - for (Index = TopRow; Index <= BottomRow && Link != NewPos;) { - SavedMenuOption = MENU_OPTION_FROM_LINK (Link); - Index += SavedMenuOption->Skip; - if (Link == TopOfScreen) { - Index -= SkipValue; - } - Link = Link->ForwardLink; - } - if (NewPos == Link) { - SavedMenuOption = MENU_OPTION_FROM_LINK (Link); - } - - // - // Not find the selected menu in current show page. - // Have two case to enter this if: - // 1. Not find the menu at current page. - // 2. Find the menu in current page, but the menu shows at the bottom and not all info shows. - // For case 2, has an exception: The menu can show more than one pages and now only this menu shows. - // - // Base on the selected menu will show at the bottom of the page, - // select the menu which will show at the top of the page. - // - if (Link != NewPos || Index > BottomRow || - (Link == NewPos && (SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow) && (Link != TopOfScreen))) { - // - // Find the MenuOption which has the skip value for Date/Time opcode. - // - AdjustDateAndTimePosition(FALSE, &NewPos); - // - // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page - // - SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); - // - // SavedMenuOption->Row == 0 means the menu not show yet. - // - if (SavedMenuOption->Row == 0) { - UpdateOptionSkipLines (Selection, SavedMenuOption); - } - - // - // Base on the selected menu will show at the bottome of next page, - // select the menu show at the top of the next page. - // - Link = NewPos; - for (Index = TopRow + SavedMenuOption->Skip; Index <= BottomRow + 1; ) { - Link = Link->BackLink; - SavedMenuOption = MENU_OPTION_FROM_LINK (Link); - if (SavedMenuOption->Row == 0) { - UpdateOptionSkipLines (Selection, SavedMenuOption); - } - Index += SavedMenuOption->Skip; - } - - // - // Found the menu which will show at the top of the page. - // - if (Link == NewPos) { - // - // The menu can show more than one pages, just show the menu at the top of the page. - // - SkipValue = 0; - TopOfScreen = Link; - } else { - // - // Check whether need to skip some line for menu shows at the top of the page. - // - SkipValue = Index - BottomRow - 1; - if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) { - TopOfScreen = Link; - } else { - SkipValue = 0; - TopOfScreen = Link->ForwardLink; - } - } - - Repaint = TRUE; - NewLine = TRUE; - ControlFlag = CfRepaint; - break; - } - } else { - // - // Target Question not found, highlight the default menu option - // - NewPos = TopOfScreen; - } - - Selection->QuestionId = 0; - } - - if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) { - if (MenuOption != NULL) { - // - // Remove highlight on last Menu Option - // - gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); - ProcessOptions (Selection, MenuOption, FALSE, &OptionString); - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND); - if (OptionString != NULL) { - if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || - (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) - ) { - ProcessStringForDateTime(MenuOption, OptionString, FALSE); - } - - Width = (UINT16) gOptionBlockWidth; - OriginalRow = MenuOption->Row; - GlyphWidth = 1; - - for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { - if ((Temp == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow)) { - PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&OptionString[Index]) != 0) { - if (Temp == 0) { - MenuOption->Row++; - } - } - - FreePool (OutputString); - if (Temp != 0) { - Temp--; - } - } - - MenuOption->Row = OriginalRow; - - FreePool (OptionString); - } else { - if (NewLine) { - if (MenuOption->GrayOut) { - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); - } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) { - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND); - } - - OriginalRow = MenuOption->Row; - Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle); - GlyphWidth = 1; - - for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { - if ((Temp == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow)) { - PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&MenuOption->Description[Index]) != 0) { - if (Temp == 0) { - MenuOption->Row++; - } - } - - FreePool (OutputString); - if (Temp != 0) { - Temp--; - } - } - - MenuOption->Row = OriginalRow; - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND); - } - } - } - - // - // This is the current selected statement - // - MenuOption = MENU_OPTION_FROM_LINK (NewPos); - Statement = MenuOption->ThisTag; - Selection->Statement = Statement; - if (!IsSelectable (MenuOption)) { - Repaint = SavedValue; - UpdateKeyHelp (Selection, MenuOption, FALSE); - break; - } - - // - // Record highlight for current menu - // - CurrentMenu->QuestionId = Statement->QuestionId; - CurrentMenu->Sequence = MenuOption->Sequence; - - // - // Set reverse attribute - // - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor)); - gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); - - // - // Assuming that we have a refresh linked-list created, lets annotate the - // appropriate entry that we are highlighting with its new attribute. Just prior to this - // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh - // - if (gMenuRefreshHead != NULL) { - for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) { - if (MenuRefreshEntry->MenuOption->GrayOut) { - MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND; - } else { - MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND; - } - if (MenuRefreshEntry->MenuOption == MenuOption) { - MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor); - } - } - } - - ProcessOptions (Selection, MenuOption, FALSE, &OptionString); - if (OptionString != NULL) { - if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { - ProcessStringForDateTime(MenuOption, OptionString, FALSE); - } - Width = (UINT16) gOptionBlockWidth; - - OriginalRow = MenuOption->Row; - GlyphWidth = 1; - - for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { - if ((Temp2 == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow) ) { - PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&OptionString[Index]) != 0) { - if (Temp2 == 0) { - MenuOption->Row++; - } - } - - FreePool (OutputString); - if (Temp2 != 0) { - Temp2--; - } - } - - MenuOption->Row = OriginalRow; - - FreePool (OptionString); - } else { - if (NewLine) { - OriginalRow = MenuOption->Row; - - Width = GetWidth (Statement, MenuOption->Handle); - GlyphWidth = 1; - - for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { - if ((Temp2 == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow) ) { - PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&MenuOption->Description[Index]) != 0) { - if (Temp2 == 0) { - MenuOption->Row++; - } - } - - FreePool (OutputString); - if (Temp2 != 0) { - Temp2--; - } - } - - MenuOption->Row = OriginalRow; - - } - } - - UpdateKeyHelp (Selection, MenuOption, FALSE); - - // - // Clear reverse attribute - // - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND); - } - // - // Repaint flag will be used when process CfUpdateHelpString, so restore its value - // if we didn't break halfway when process CfRefreshHighLight. - // - Repaint = SavedValue; - break; - - case CfUpdateHelpString: - ControlFlag = CfPrepareToReadKey; - if (Selection->Form->ModalForm) { - break; - } - - if (Repaint || NewLine) { - // - // Don't print anything if it is a NULL help token - // - ASSERT(MenuOption != NULL); - if (MenuOption->ThisTag->Help == 0 || !IsSelectable (MenuOption)) { - StringPtr = L"\0"; - } else { - StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle); - } - - RowCount = BottomRow - TopRow; - HelpPageIndex = 0; - // - // 1.Calculate how many line the help string need to print. - // - if (HelpString != NULL) { - FreePool (HelpString); - } - HelpLine = ProcessHelpString (StringPtr, &HelpString, &EachLineWidth, RowCount); - if (HelpLine > RowCount) { - MultiHelpPage = TRUE; - StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP), gHiiHandle); - if (HelpHeaderString != NULL) { - FreePool (HelpHeaderString); - } - HelpHeaderLine = ProcessHelpString (StringPtr, &HelpHeaderString, &HeaderLineWidth, RowCount); - StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN), gHiiHandle); - if (HelpBottomString != NULL) { - FreePool (HelpBottomString); - } - HelpBottomLine = ProcessHelpString (StringPtr, &HelpBottomString, &BottomLineWidth, RowCount); - // - // Calculate the help page count. - // - if (HelpLine > 2 * RowCount - 2) { - HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1; - if ((HelpLine - RowCount + 1) % (RowCount - 2) > 1) { - HelpPageCount += 1; - } - } else { - HelpPageCount = 2; - } - } else { - MultiHelpPage = FALSE; - } - } - - // - // Clean the help field first. - // - ClearLines ( - LocalScreen.RightColumn - gHelpBlockWidth, - LocalScreen.RightColumn, - TopRow, - BottomRow, - PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND - ); - - // - // Check whether need to show the 'More(U/u)' at the begin. - // Base on current direct info, here shows aligned to the right side of the column. - // If the direction is multi line and aligned to right side may have problem, so - // add ASSERT code here. - // - if (HelpPageIndex > 0) { - gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND); - for (Index = 0; Index < HelpHeaderLine; Index++) { - ASSERT (HelpHeaderLine == 1); - ASSERT (GetStringWidth (HelpHeaderString) / 2 < (UINTN) (gHelpBlockWidth - 1)); - PrintStringAt ( - LocalScreen.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1, - Index + TopRow, - &HelpHeaderString[Index * HeaderLineWidth] - ); - } - } - - gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND); - // - // Print the help string info. - // - if (!MultiHelpPage) { - for (Index = 0; Index < HelpLine; Index++) { - PrintStringAt ( - LocalScreen.RightColumn - gHelpBlockWidth, - Index + TopRow, - &HelpString[Index * EachLineWidth] - ); - } - gST->ConOut->SetCursorPosition(gST->ConOut, LocalScreen.RightColumn-1, BottomRow); - } else { - if (HelpPageIndex == 0) { - for (Index = 0; Index < RowCount - HelpBottomLine; Index++) { - PrintStringAt ( - LocalScreen.RightColumn - gHelpBlockWidth, - Index + TopRow, - &HelpString[Index * EachLineWidth] - ); - } - } else { - for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) && - (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++) { - PrintStringAt ( - LocalScreen.RightColumn - gHelpBlockWidth, - Index + TopRow + HelpHeaderLine, - &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* EachLineWidth] - ); - } - if (HelpPageIndex == HelpPageCount - 1) { - gST->ConOut->SetCursorPosition(gST->ConOut, LocalScreen.RightColumn-1, BottomRow); - } - } - } - - // - // Check whether need to print the 'More(D/d)' at the bottom. - // Base on current direct info, here shows aligned to the right side of the column. - // If the direction is multi line and aligned to right side may have problem, so - // add ASSERT code here. - // - if (HelpPageIndex < HelpPageCount - 1 && MultiHelpPage) { - gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND); - for (Index = 0; Index < HelpBottomLine; Index++) { - ASSERT (HelpBottomLine == 1); - ASSERT (GetStringWidth (HelpBottomString) / 2 < (UINTN) (gHelpBlockWidth - 1)); - PrintStringAt ( - LocalScreen.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1, - Index + BottomRow - HelpBottomLine, - &HelpBottomString[Index * BottomLineWidth] - ); - } - } - // - // Reset this flag every time we finish using it. - // - Repaint = FALSE; - NewLine = FALSE; - break; - - case CfPrepareToReadKey: - ControlFlag = CfReadKey; - ScreenOperation = UiNoOperation; - break; - - case CfReadKey: - ControlFlag = CfScreenOperation; - - // - // Wait for user's selection - // - while (TRUE) { - Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); - if (!EFI_ERROR (Status)) { - break; - } - - // - // If we encounter error, continue to read another key in. - // - if (Status != EFI_NOT_READY) { - continue; - } - - Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval); - ASSERT_EFI_ERROR (Status); - - if (Selection->Action == UI_ACTION_REFRESH_FORMSET) { - // - // IFR is updated in Callback of refresh opcode, re-parse it - // - ControlFlag = CfCheckSelection; - Selection->Statement = NULL; - break; - } - } - - if (ControlFlag == CfCheckSelection) { - break; - } - - switch (Key.UnicodeChar) { - case CHAR_CARRIAGE_RETURN: - if(MenuOption->GrayOut || MenuOption->ReadOnly) { - ControlFlag = CfReadKey; - break; - } - - ScreenOperation = UiSelect; - gDirection = 0; - break; - - // - // We will push the adjustment of these numeric values directly to the input handler - // NOTE: we won't handle manual input numeric - // - case '+': - case '-': - // - // If the screen has no menu items, and the user didn't select UiReset - // ignore the selection and go back to reading keys. - // - if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) { - ControlFlag = CfReadKey; - break; - } - - ASSERT(MenuOption != NULL); - Statement = MenuOption->ThisTag; - if ((Statement->Operand == EFI_IFR_DATE_OP) - || (Statement->Operand == EFI_IFR_TIME_OP) - || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0)) - ){ - if (Key.UnicodeChar == '+') { - gDirection = SCAN_RIGHT; - } else { - gDirection = SCAN_LEFT; - } - Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString); - if (EFI_ERROR (Status)) { - // - // Repaint to clear possible error prompt pop-up - // - Repaint = TRUE; - NewLine = TRUE; - } else { - Selection->Action = UI_ACTION_REFRESH_FORM; - } - if (OptionString != NULL) { - FreePool (OptionString); - } - } - break; - - case '^': - ScreenOperation = UiUp; - break; - - case 'V': - case 'v': - ScreenOperation = UiDown; - break; - - case ' ': - if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) { - // - // If the screen has no menu items, and the user didn't select UiReset - // ignore the selection and go back to reading keys. - // - if(IsListEmpty (&gMenuOption)) { - ControlFlag = CfReadKey; - break; - } - - ASSERT(MenuOption != NULL); - if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) { - ScreenOperation = UiSelect; - } - } - break; - - case 'D': - case 'd': - if (!MultiHelpPage) { - ControlFlag = CfReadKey; - break; - } - ControlFlag = CfUpdateHelpString; - HelpPageIndex = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1; - break; - - case 'U': - case 'u': - if (!MultiHelpPage) { - ControlFlag = CfReadKey; - break; - } - ControlFlag = CfUpdateHelpString; - HelpPageIndex = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0; - break; - - case CHAR_NULL: - for (Index = 0; Index < mScanCodeNumber; Index++) { - if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) { - ScreenOperation = gScanCodeToOperation[Index].ScreenOperation; - break; - } - } - - if (Selection->Form->ModalForm && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) { - // - // ModalForm has no ESC key and Hot Key. - // - ControlFlag = CfReadKey; - } else if (Index == mScanCodeNumber) { - // - // Check whether Key matches the registered hot key. - // - HotKey = NULL; - if ((gBrowserSettingScope == SystemLevel) || - (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) { - HotKey = GetHotKeyFromRegisterList (&Key); - } - if (HotKey != NULL) { - ScreenOperation = UiHotKey; - } - } - break; - } - break; - - case CfScreenOperation: - if (ScreenOperation != UiReset) { - // - // If the screen has no menu items, and the user didn't select UiReset - // ignore the selection and go back to reading keys. - // - if (IsListEmpty (&gMenuOption)) { - ControlFlag = CfReadKey; - break; - } - } - - for (Index = 0; - Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]); - Index++ - ) { - if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) { - ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag; - break; - } - } - break; - - case CfUiSelect: - ControlFlag = CfCheckSelection; - - ASSERT(MenuOption != NULL); - Statement = MenuOption->ThisTag; - if (Statement->Operand == EFI_IFR_TEXT_OP) { - break; - } - - // - // Keep highlight on current MenuOption - // - Selection->QuestionId = Statement->QuestionId; - - switch (Statement->Operand) { - case EFI_IFR_REF_OP: - ProcessGotoOpCode(Statement, Selection, &Repaint, &NewLine); - break; - - case EFI_IFR_ACTION_OP: - // - // Process the Config string - // - Status = ProcessQuestionConfig (Selection, Statement); - - if (EFI_ERROR (Status)) { - break; - } - - // - // The action button may change some Question value, so refresh the form - // - Selection->Action = UI_ACTION_REFRESH_FORM; - break; - - case EFI_IFR_RESET_BUTTON_OP: - // - // Reset Question to default value specified by DefaultId - // - ControlFlag = CfUiDefault; - DefaultId = Statement->DefaultId; - break; - - default: - // - // Editable Questions: oneof, ordered list, checkbox, numeric, string, password - // - UpdateKeyHelp (Selection, MenuOption, TRUE); - Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString); - - if (EFI_ERROR (Status)) { - Repaint = TRUE; - NewLine = TRUE; - UpdateKeyHelp (Selection, MenuOption, FALSE); - } else { - Selection->Action = UI_ACTION_REFRESH_FORM; - } - - if (OptionString != NULL) { - FreePool (OptionString); - } - break; - } - break; - - case CfUiReset: - // - // We come here when someone press ESC - // - ControlFlag = CfCheckSelection; - FindNextMenu (Selection, &Repaint, &NewLine); - break; - - case CfUiLeft: - ControlFlag = CfCheckSelection; - ASSERT(MenuOption != NULL); - if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { - if (MenuOption->Sequence != 0) { - // - // In the middle or tail of the Date/Time op-code set, go left. - // - ASSERT(NewPos != NULL); - NewPos = NewPos->BackLink; - } - } - break; - - case CfUiRight: - ControlFlag = CfCheckSelection; - ASSERT(MenuOption != NULL); - if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { - if (MenuOption->Sequence != 2) { - // - // In the middle or tail of the Date/Time op-code set, go left. - // - ASSERT(NewPos != NULL); - NewPos = NewPos->ForwardLink; - } - } - break; - - case CfUiUp: - ControlFlag = CfCheckSelection; - - SavedListEntry = NewPos; - - ASSERT(NewPos != NULL); - // - // Adjust Date/Time position before we advance forward. - // - AdjustDateAndTimePosition (TRUE, &NewPos); - if (NewPos->BackLink != &gMenuOption) { - MenuOption = MENU_OPTION_FROM_LINK (NewPos); - ASSERT (MenuOption != NULL); - NewLine = TRUE; - NewPos = NewPos->BackLink; - - PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos); - if (PreviousMenuOption->Row == 0) { - UpdateOptionSkipLines (Selection, PreviousMenuOption); - } - DistanceValue = PreviousMenuOption->Skip; - Difference = 0; - if (MenuOption->Row >= DistanceValue + TopRow) { - Difference = MoveToNextStatement (Selection, TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue); - } - NextMenuOption = MENU_OPTION_FROM_LINK (NewPos); - - if (Difference < 0) { - // - // We hit the begining MenuOption that can be focused - // so we simply scroll to the top. - // - if (TopOfScreen != gMenuOption.ForwardLink) { - TopOfScreen = gMenuOption.ForwardLink; - Repaint = TRUE; - } else { - // - // Scroll up to the last page when we have arrived at top page. - // - NewPos = &gMenuOption; - TopOfScreen = &gMenuOption; - MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); - ScreenOperation = UiPageUp; - ControlFlag = CfScreenOperation; - break; - } - } else if (MenuOption->Row < TopRow + DistanceValue + Difference) { - // - // Previous focus MenuOption is above the TopOfScreen, so we need to scroll - // - TopOfScreen = NewPos; - Repaint = TRUE; - SkipValue = 0; - } else if (!IsSelectable (NextMenuOption)) { - // - // Continue to go up until scroll to next page or the selectable option is found. - // - ScreenOperation = UiUp; - ControlFlag = CfScreenOperation; - } - - // - // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. - // - AdjustDateAndTimePosition (TRUE, &TopOfScreen); - AdjustDateAndTimePosition (TRUE, &NewPos); - MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); - UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); - } else { - // - // Scroll up to the last page. - // - NewPos = &gMenuOption; - TopOfScreen = &gMenuOption; - MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); - ScreenOperation = UiPageUp; - ControlFlag = CfScreenOperation; - } - break; - - case CfUiPageUp: - // - // SkipValue means lines is skipped when show the top menu option. - // - ControlFlag = CfCheckSelection; - - ASSERT(NewPos != NULL); - // - // Already at the first menu option, so do nothing. - // - if (NewPos->BackLink == &gMenuOption) { - NewLine = FALSE; - Repaint = FALSE; - break; - } - - NewLine = TRUE; - Repaint = TRUE; - - // - // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one - // form of options to be show, so just update the SkipValue to show the next - // parts of options. - // - if (SkipValue > (INTN) (BottomRow - TopRow + 1)) { - SkipValue -= BottomRow - TopRow + 1; - break; - } - - Link = TopOfScreen; - // - // First minus the menu of the top screen, it's value is SkipValue. - // - Index = (BottomRow + 1) - SkipValue; - while ((Index >= TopRow) && (Link->BackLink != &gMenuOption)) { - Link = Link->BackLink; - PreviousMenuOption = MENU_OPTION_FROM_LINK (Link); - if (PreviousMenuOption->Row == 0) { - UpdateOptionSkipLines (Selection, PreviousMenuOption); - } - if (Index < PreviousMenuOption->Skip) { - break; - } - Index = Index - PreviousMenuOption->Skip; - } - - if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) { - SkipValue = 0; - if (TopOfScreen == &gMenuOption) { - TopOfScreen = gMenuOption.ForwardLink; - NewPos = gMenuOption.BackLink; - MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow); - Repaint = FALSE; - } else if (TopOfScreen != Link) { - TopOfScreen = Link; - NewPos = Link; - MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow); - } else { - // - // Finally we know that NewPos is the last MenuOption can be focused. - // - Repaint = FALSE; - NewPos = Link; - MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow); - } - } else { - if (Index >= TopRow) { - // - // At here, only case "Index < PreviousMenuOption->Skip" can reach here. - // - SkipValue = PreviousMenuOption->Skip - (Index - TopRow); - } else { - SkipValue = PreviousMenuOption->Skip - (TopRow - Index); - Link = Link->ForwardLink; - } - - // - // Move to the option in Next page. - // - if (TopOfScreen == &gMenuOption) { - NewPos = gMenuOption.BackLink; - MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow); - } else { - NewPos = Link; - MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow); - } - - // - // There are more MenuOption needing scrolling up. - // - TopOfScreen = Link; - MenuOption = NULL; - } - - // - // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. - // Don't do this when we are already in the first page. - // - AdjustDateAndTimePosition (TRUE, &TopOfScreen); - AdjustDateAndTimePosition (TRUE, &NewPos); - break; - - case CfUiPageDown: - // - // SkipValue means lines is skipped when show the top menu option. - // - ControlFlag = CfCheckSelection; - - ASSERT (NewPos != NULL); - if (NewPos->ForwardLink == &gMenuOption) { - NewLine = FALSE; - Repaint = FALSE; - break; - } - - NewLine = TRUE; - Repaint = TRUE; - Link = TopOfScreen; - NextMenuOption = MENU_OPTION_FROM_LINK (Link); - Index = TopRow + NextMenuOption->Skip - SkipValue; - // - // Count to the menu option which will show at the top of the next form. - // - while ((Index <= BottomRow + 1) && (Link->ForwardLink != &gMenuOption)) { - Link = Link->ForwardLink; - NextMenuOption = MENU_OPTION_FROM_LINK (Link); - Index = Index + NextMenuOption->Skip; - } - - if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) { - // - // Finally we know that NewPos is the last MenuOption can be focused. - // - Repaint = FALSE; - MoveToNextStatement (Selection, TRUE, &Link, Index - TopRow); - SkipValue = 0; - } else { - // - // Calculate the skip line for top of screen menu. - // - if (Link == TopOfScreen) { - // - // The top of screen menu option occupies the entire form. - // - SkipValue += BottomRow - TopRow + 1; - } else { - SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1)); - } - - TopOfScreen = Link; - MenuOption = NULL; - // - // Move to the Next selectable menu. - // - MoveToNextStatement (Selection, FALSE, &Link, BottomRow - TopRow); - } - - // - // Save the menu as the next highlight menu. - // - NewPos = Link; - - // - // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. - // Don't do this when we are already in the last page. - // - AdjustDateAndTimePosition (TRUE, &TopOfScreen); - AdjustDateAndTimePosition (TRUE, &NewPos); - break; - - case CfUiDown: - // - // SkipValue means lines is skipped when show the top menu option. - // NewPos points to the menu which is highlighted now. - // - ControlFlag = CfCheckSelection; - // - // Since the behavior of hitting the down arrow on a Date/Time op-code is intended - // to be one that progresses to the next set of op-codes, we need to advance to the last - // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate - // checking can be done. The only other logic we need to introduce is that if a Date/Time - // op-code is the last entry in the menu, we need to rewind back to the first op-code of - // the Date/Time op-code. - // - SavedListEntry = NewPos; - AdjustDateAndTimePosition (FALSE, &NewPos); - - if (NewPos->ForwardLink != &gMenuOption) { - MenuOption = MENU_OPTION_FROM_LINK (NewPos); - NewLine = TRUE; - NewPos = NewPos->ForwardLink; - - Difference = 0; - // - // Current menu not at the bottom of the form. - // - if (BottomRow >= MenuOption->Row + MenuOption->Skip) { - // - // Find the next selectable menu. - // - Difference = MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip); - // - // We hit the end of MenuOption that can be focused - // so we simply scroll to the first page. - // - if (Difference < 0) { - // - // Scroll to the first page. - // - if (TopOfScreen != gMenuOption.ForwardLink) { - TopOfScreen = gMenuOption.ForwardLink; - Repaint = TRUE; - MenuOption = NULL; - } else { - MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); - } - NewPos = gMenuOption.ForwardLink; - MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow); - - SkipValue = 0; - // - // If we are at the end of the list and sitting on a Date/Time op, rewind to the head. - // - AdjustDateAndTimePosition (TRUE, &TopOfScreen); - AdjustDateAndTimePosition (TRUE, &NewPos); - break; - } - } - NextMenuOption = MENU_OPTION_FROM_LINK (NewPos); - if (NextMenuOption->Row == 0) { - UpdateOptionSkipLines (Selection, NextMenuOption); - } - DistanceValue = Difference + NextMenuOption->Skip; - - Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1; - if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) && - (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP || - NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) - ) { - Temp ++; - } - - // - // If we are going to scroll, update TopOfScreen - // - if (Temp > BottomRow) { - do { - // - // Is the current top of screen a zero-advance op-code? - // If so, keep moving forward till we hit a >0 advance op-code - // - SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); - - // - // If bottom op-code is more than one line or top op-code is more than one line - // - if ((DistanceValue > 1) || (SavedMenuOption->Skip > 1)) { - // - // Is the bottom op-code greater than or equal in size to the top op-code? - // - if ((Temp - BottomRow) >= (SavedMenuOption->Skip - SkipValue)) { - // - // Skip the top op-code - // - TopOfScreen = TopOfScreen->ForwardLink; - Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue); - - SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); - - // - // If we have a remainder, skip that many more op-codes until we drain the remainder - // - while (Difference >= (INTN) SavedMenuOption->Skip) { - // - // Since the Difference is greater than or equal to this op-code's skip value, skip it - // - Difference = Difference - (INTN) SavedMenuOption->Skip; - TopOfScreen = TopOfScreen->ForwardLink; - SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); - } - // - // Since we will act on this op-code in the next routine, and increment the - // SkipValue, set the skips to one less than what is required. - // - SkipValue = Difference - 1; - } else { - // - // Since we will act on this op-code in the next routine, and increment the - // SkipValue, set the skips to one less than what is required. - // - SkipValue += (Temp - BottomRow) - 1; - } - } else { - if ((SkipValue + 1) == (INTN) SavedMenuOption->Skip) { - TopOfScreen = TopOfScreen->ForwardLink; - break; - } - } - // - // If the op-code at the top of the screen is more than one line, let's not skip it yet - // Let's set a skip flag to smoothly scroll the top of the screen. - // - if (SavedMenuOption->Skip > 1) { - if (SavedMenuOption == NextMenuOption) { - SkipValue = 0; - } else { - SkipValue++; - } - } else if (SavedMenuOption->Skip == 1) { - SkipValue = 0; - } else { - SkipValue = 0; - TopOfScreen = TopOfScreen->ForwardLink; - } - } while (SavedMenuOption->Skip == 0); - - Repaint = TRUE; - } else if (!IsSelectable (NextMenuOption)) { - // - // Continue to go down until scroll to next page or the selectable option is found. - // - ScreenOperation = UiDown; - ControlFlag = CfScreenOperation; - } - - MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); - - UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); - - } else { - // - // Scroll to the first page. - // - if (TopOfScreen != gMenuOption.ForwardLink) { - TopOfScreen = gMenuOption.ForwardLink; - Repaint = TRUE; - MenuOption = NULL; - } else { - // - // Need to remove the current highlight menu. - // MenuOption saved the last highlight menu info. - // - MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); - } - - SkipValue = 0; - NewLine = TRUE; - // - // Get the next highlight menu. - // - NewPos = gMenuOption.ForwardLink; - MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow); - } - - // - // If we are at the end of the list and sitting on a Date/Time op, rewind to the head. - // - AdjustDateAndTimePosition (TRUE, &TopOfScreen); - AdjustDateAndTimePosition (TRUE, &NewPos); - break; - - case CfUiHotKey: - ControlFlag = CfCheckSelection; - - Status = EFI_SUCCESS; - // - // Discard changes. After it, no NV flag is showed. - // - if ((HotKey->Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) { - Status = DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope); - if (!EFI_ERROR (Status)) { - Selection->Action = UI_ACTION_REFRESH_FORM; - Selection->Statement = NULL; - gResetRequired = FALSE; - } else { - do { - CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDiscardFailed, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - // - // Still show current page. - // - Selection->Action = UI_ACTION_NONE; - Repaint = TRUE; - NewLine = TRUE; - break; - } - } - - // - // Reterieve default setting. After it. NV flag will be showed. - // - if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) { - Status = ExtractDefault (Selection->FormSet, Selection->Form, HotKey->DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE); - if (!EFI_ERROR (Status)) { - Selection->Action = UI_ACTION_REFRESH_FORM; - Selection->Statement = NULL; - gResetRequired = TRUE; - } else { - do { - CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDefaultFailed, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - // - // Still show current page. - // - Selection->Action = UI_ACTION_NONE; - Repaint = TRUE; - NewLine = TRUE; - break; - } - } - - // - // Save changes. After it, no NV flag is showed. - // - if ((HotKey->Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) { - Status = SubmitForm (Selection->FormSet, Selection->Form, gBrowserSettingScope); - if (!EFI_ERROR (Status)) { - ASSERT(MenuOption != NULL); - UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); - UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE); - } else { - do { - CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gSaveFailed, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - // - // Still show current page. - // - Selection->Action = UI_ACTION_NONE; - Repaint = TRUE; - NewLine = TRUE; - break; - } - } - - // - // Set Reset required Flag - // - if ((HotKey->Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) { - gResetRequired = TRUE; - } - - // - // Exit Action - // - if ((HotKey->Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) { - // - // Form Exit without saving, Similar to ESC Key. - // FormSet Exit without saving, Exit SendForm. - // System Exit without saving, CallExitHandler and Exit SendForm. - // - DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope); - if (gBrowserSettingScope == FormLevel) { - ControlFlag = CfUiReset; - } else if (gBrowserSettingScope == FormSetLevel) { - Selection->Action = UI_ACTION_EXIT; - } else if (gBrowserSettingScope == SystemLevel) { - if (ExitHandlerFunction != NULL) { - ExitHandlerFunction (); - } - Selection->Action = UI_ACTION_EXIT; - } - Selection->Statement = NULL; - } - break; - - case CfUiDefault: - ControlFlag = CfCheckSelection; - // - // Reset to default value for all forms in the whole system. - // - Status = ExtractDefault (Selection->FormSet, NULL, DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE); - - if (!EFI_ERROR (Status)) { - Selection->Action = UI_ACTION_REFRESH_FORM; - Selection->Statement = NULL; - gResetRequired = TRUE; - } - break; - - case CfUiNoOperation: - ControlFlag = CfCheckSelection; - break; - - case CfExit: - UiFreeRefreshList (); - - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); - gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4); - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - gST->ConOut->OutputString (gST->ConOut, L"\n"); - if (HelpString != NULL) { - FreePool (HelpString); - } - if (HelpHeaderString != NULL) { - FreePool (HelpHeaderString); - } - if (HelpBottomString != NULL) { - FreePool (HelpBottomString); - } - - return EFI_SUCCESS; - - default: - break; - } - } -} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h deleted file mode 100644 index 03cb0cd753..0000000000 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h +++ /dev/null @@ -1,1067 +0,0 @@ -/** @file -Private structure, MACRO and function definitions for User Interface related functionalities. - -Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef _UI_H_ -#define _UI_H_ - -// -// Globals -// -#define REGULAR_NUMERIC 0 -#define TIME_NUMERIC 1 -#define DATE_NUMERIC 2 - -#define SUBTITLE_INDENT 2 - - -// -// It take 23 characters including the NULL to print a 64 bits number with "[" and "]". -// pow(2, 64) = [18446744073709551616] -// -#define MAX_NUMERIC_INPUT_WIDTH 23 - -typedef enum { - UiNoOperation, - UiSelect, - UiUp, - UiDown, - UiLeft, - UiRight, - UiReset, - UiPrevious, - UiPageUp, - UiPageDown, - UiHotKey, - UiMaxOperation -} UI_SCREEN_OPERATION; - -typedef enum { - CfInitialization, - CfCheckSelection, - CfRepaint, - CfRefreshHighLight, - CfUpdateHelpString, - CfPrepareToReadKey, - CfReadKey, - CfScreenOperation, - CfUiSelect, - CfUiReset, - CfUiLeft, - CfUiRight, - CfUiUp, - CfUiPageUp, - CfUiPageDown, - CfUiDown, - CfUiDefault, - CfUiNoOperation, - CfExit, - CfUiHotKey, - CfMaxControlFlag -} UI_CONTROL_FLAG; - -#define UI_ACTION_NONE 0 -#define UI_ACTION_REFRESH_FORM 1 -#define UI_ACTION_REFRESH_FORMSET 2 -#define UI_ACTION_EXIT 3 - -typedef struct _UI_MENU_LIST UI_MENU_LIST; - -typedef struct { - EFI_HII_HANDLE Handle; - - // - // Target formset/form/Question information - // - EFI_GUID FormSetGuid; - UINT16 FormId; - UINT16 QuestionId; - UINTN Sequence; // used for time/date only. - - UINTN TopRow; - UINTN BottomRow; - UINTN PromptCol; - UINTN OptionCol; - UINTN CurrentRow; - - // - // Ation for Browser to taken: - // UI_ACTION_NONE - navigation inside a form - // UI_ACTION_REFRESH_FORM - re-evaluate expressions and repaint form - // UI_ACTION_REFRESH_FORMSET - re-parse formset IFR binary - // - UINTN Action; - - // - // Current selected fomset/form/Question - // - FORM_BROWSER_FORMSET *FormSet; - FORM_BROWSER_FORM *Form; - FORM_BROWSER_STATEMENT *Statement; - - // - // Whether the Form is editable - // - BOOLEAN FormEditable; - - UI_MENU_LIST *CurrentMenu; -} UI_MENU_SELECTION; - -#define UI_MENU_OPTION_SIGNATURE SIGNATURE_32 ('u', 'i', 'm', 'm') -#define UI_MENU_LIST_SIGNATURE SIGNATURE_32 ('u', 'i', 'm', 'l') - -typedef struct { - UINTN Signature; - LIST_ENTRY Link; - - EFI_HII_HANDLE Handle; - FORM_BROWSER_STATEMENT *ThisTag; - UINT16 EntryNumber; - - UINTN Row; - UINTN Col; - UINTN OptCol; - CHAR16 *Description; - UINTN Skip; // Number of lines - - // - // Display item sequence for date/time - // Date: Month/Day/Year - // Sequence: 0 1 2 - // - // Time: Hour : Minute : Second - // Sequence: 0 1 2 - // - // - UINTN Sequence; - - BOOLEAN GrayOut; - BOOLEAN ReadOnly; - - // - // Whether user could change value of this item - // - BOOLEAN IsQuestion; -} UI_MENU_OPTION; - -#define MENU_OPTION_FROM_LINK(a) CR (a, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE) - -struct _UI_MENU_LIST { - UINTN Signature; - LIST_ENTRY Link; - - EFI_HII_HANDLE HiiHandle; - EFI_GUID FormSetGuid; - UINT16 FormId; - UINT16 QuestionId; - UINTN Sequence; // used for time/date only. - - UI_MENU_LIST *Parent; - LIST_ENTRY ChildListHead; -}; - -#define UI_MENU_LIST_FROM_LINK(a) CR (a, UI_MENU_LIST, Link, UI_MENU_LIST_SIGNATURE) - -typedef struct _MENU_REFRESH_ENTRY MENU_REFRESH_ENTRY; -struct _MENU_REFRESH_ENTRY { - MENU_REFRESH_ENTRY *Next; - UI_MENU_OPTION *MenuOption; // Describes the entry needing an update - UI_MENU_SELECTION *Selection; - UINTN CurrentColumn; - UINTN CurrentRow; - UINTN CurrentAttribute; - EFI_EVENT Event; -}; - -typedef struct { - UINT16 ScanCode; - UI_SCREEN_OPERATION ScreenOperation; -} SCAN_CODE_TO_SCREEN_OPERATION; - -typedef struct { - UI_SCREEN_OPERATION ScreenOperation; - UI_CONTROL_FLAG ControlFlag; -} SCREEN_OPERATION_T0_CONTROL_FLAG; - - -extern LIST_ENTRY gMenuOption; -extern LIST_ENTRY gMenuList; -extern MENU_REFRESH_ENTRY *gMenuRefreshHead; -extern UI_MENU_SELECTION *gCurrentSelection; -extern BOOLEAN mHiiPackageListUpdated; - -// -// Global Functions -// -/** - Initialize Menu option list. - -**/ -VOID -UiInitMenu ( - VOID - ); - -/** - Initialize Menu option list. - -**/ -VOID -UiInitMenuList ( - VOID - ); - -/** - Free Menu option linked list. - -**/ -VOID -UiFreeMenu ( - VOID - ); - -/** - Create a menu with specified formset GUID and form ID, and add it as a child - of the given parent menu. - - @param Parent The parent of menu to be added. - @param HiiHandle Hii handle related to this formset. - @param FormSetGuid The Formset Guid of menu to be added. - @param FormId The Form ID of menu to be added. - - @return A pointer to the newly added menu or NULL if memory is insufficient. - -**/ -UI_MENU_LIST * -UiAddMenuList ( - IN OUT UI_MENU_LIST *Parent, - IN EFI_HII_HANDLE HiiHandle, - IN EFI_GUID *FormSetGuid, - IN UINT16 FormId - ); - -/** - Search Menu with given FormId, FormSetGuid and Handle in all cached menu list. - - @param Parent The parent of menu to search. - @param Handle Hii handle related to this formset. - @param FormSetGuid The Formset GUID of the menu to search. - @param FormId The Form ID of menu to search. - - @return A pointer to menu found or NULL if not found. - -**/ -UI_MENU_LIST * -UiFindChildMenuList ( - IN UI_MENU_LIST *Parent, - IN EFI_HII_HANDLE Handle, - IN EFI_GUID *FormSetGuid, - IN UINT16 FormId - ); - -/** - Search Menu with given Handle, FormSetGuid and FormId in all cached menu list. - - @param Handle Hii handle related to this formset. - @param FormSetGuid The Formset GUID of the menu to search. - @param FormId The Form ID of menu to search. - - @return A pointer to menu found or NULL if not found. - -**/ -UI_MENU_LIST * -UiFindMenuList ( - IN EFI_HII_HANDLE Handle, - IN EFI_GUID *FormSetGuid, - IN UINT16 FormId - ); - -/** - Free Menu list linked list. - - @param MenuListHead One Menu list point in the menu list. - -**/ -VOID -UiFreeMenuList ( - LIST_ENTRY *MenuListHead - ); - -/** - Free Menu option linked list. - -**/ -VOID -UiFreeRefreshList ( - VOID - ); - -/** - Add one menu option by specified description and context. - - @param String String description for this option. - @param Handle Hii handle for the package list. - @param Form The form this statement belong to. - @param Statement Statement of this Menu Option. - @param NumberOfLines Display lines for this Menu Option. - @param MenuItemCount The index for this Option in the Menu. - - @retval Pointer Pointer to the added Menu Option. - -**/ -UI_MENU_OPTION * -UiAddMenuOption ( - IN CHAR16 *String, - IN EFI_HII_HANDLE Handle, - IN FORM_BROWSER_FORM *Form, - IN FORM_BROWSER_STATEMENT *Statement, - IN UINT16 NumberOfLines, - IN UINT16 MenuItemCount - ); - -/** - Display menu and wait for user to select one menu option, then return it. - If AutoBoot is enabled, then if user doesn't select any option, - after period of time, it will automatically return the first menu option. - - @param Selection Menu selection. - - @return Return the pointer of the menu which selected, - @return otherwise return NULL. - -**/ -EFI_STATUS -UiDisplayMenu ( - IN OUT UI_MENU_SELECTION *Selection - ); - -/** - Free up the resource allocated for all strings required - by Setup Browser. - -**/ -VOID -FreeBrowserStrings ( - VOID - ); - -/** - Process the goto op code, update the info in the selection structure. - - @param Statement The statement belong to goto op code. - @param Selection The selection info. - @param Repaint Whether need to repaint the menu. - @param NewLine Whether need to create new line. - - @retval EFI_SUCCESS The menu process successfully. - @return Other value if the process failed. -**/ -EFI_STATUS -ProcessGotoOpCode ( - IN OUT FORM_BROWSER_STATEMENT *Statement, - IN OUT UI_MENU_SELECTION *Selection, - OUT BOOLEAN *Repaint, - OUT BOOLEAN *NewLine - ); - - -/** - The worker function that send the displays to the screen. On output, - the selection made by user is returned. - - @param Selection On input, Selection tell setup browser the information - about the Selection, form and formset to be displayed. - On output, Selection return the screen item that is selected - by user. - - @retval EFI_SUCCESS The page is displayed successfully. - @return Other value if the page failed to be diplayed. - -**/ -EFI_STATUS -SetupBrowser ( - IN OUT UI_MENU_SELECTION *Selection - ); - -/** - Set Buffer to Value for Size bytes. - - @param Buffer Memory to set. - @param Size Number of bytes to set - @param Value Value of the set operation. - -**/ -VOID -SetUnicodeMem ( - IN VOID *Buffer, - IN UINTN Size, - IN CHAR16 Value - ); - -/** - Wait for a given event to fire, or for an optional timeout to expire. - - @param Event The event to wait for - @param Timeout An optional timeout value in 100 ns units. - @param RefreshInterval Menu refresh interval (in seconds). - - @retval EFI_SUCCESS Event fired before Timeout expired. - @retval EFI_TIME_OUT Timout expired before Event fired. - -**/ -EFI_STATUS -UiWaitForSingleEvent ( - IN EFI_EVENT Event, - IN UINT64 Timeout, OPTIONAL - IN UINT8 RefreshInterval OPTIONAL - ); - -/** - Draw a pop up windows based on the dimension, number of lines and - strings specified. - - @param ScreenWidth The width of the pop-up. - @param NumberOfLines The number of lines. - @param ... A series of text strings that displayed in the pop-up. - -**/ -VOID -EFIAPI -CreateMultiStringPopUp ( - IN UINTN ScreenWidth, - IN UINTN NumberOfLines, - ... - ); - -/** - Get string or password input from user. - - @param MenuOption Pointer to the current input menu. - @param Prompt The prompt string shown on popup window. - @param StringPtr Old user input and destination for use input string. - - @retval EFI_SUCCESS If string input is read successfully - @retval EFI_DEVICE_ERROR If operation fails - -**/ -EFI_STATUS -ReadString ( - IN UI_MENU_OPTION *MenuOption, - IN CHAR16 *Prompt, - IN OUT CHAR16 *StringPtr - ); - -/** - Get selection for OneOf and OrderedList (Left/Right will be ignored). - - @param Selection Pointer to current selection. - @param MenuOption Pointer to the current input menu. - - @retval EFI_SUCCESS If Option input is processed successfully - @retval EFI_DEVICE_ERROR If operation fails - -**/ -EFI_STATUS -GetSelectionInputPopUp ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption - ); - -/** - This routine reads a numeric value from the user input. - - @param Selection Pointer to current selection. - @param MenuOption Pointer to the current input menu. - - @retval EFI_SUCCESS If numerical input is read successfully - @retval EFI_DEVICE_ERROR If operation fails - -**/ -EFI_STATUS -GetNumericInput ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption - ); - -/** - Update status bar on the bottom of menu. - - @param Selection Current selection info. - @param MessageType The type of message to be shown. - @param Flags The flags in Question header. - @param State Set or clear. - -**/ -VOID -UpdateStatusBar ( - IN UI_MENU_SELECTION *Selection, - IN UINTN MessageType, - IN UINT8 Flags, - IN BOOLEAN State - ); - -/** - Process Question Config. - - @param Selection The UI menu selection. - @param Question The Question to be peocessed. - - @retval EFI_SUCCESS Question Config process success. - @retval Other Question Config process fail. - -**/ -EFI_STATUS -ProcessQuestionConfig ( - IN UI_MENU_SELECTION *Selection, - IN FORM_BROWSER_STATEMENT *Question - ); - -/** - Print Question Value according to it's storage width and display attributes. - - @param Question The Question to be printed. - @param FormattedNumber Buffer for output string. - @param BufferSize The FormattedNumber buffer size in bytes. - - @retval EFI_SUCCESS Print success. - @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number. - -**/ -EFI_STATUS -PrintFormattedNumber ( - IN FORM_BROWSER_STATEMENT *Question, - IN OUT CHAR16 *FormattedNumber, - IN UINTN BufferSize - ); - -/** - Search an Option of a Question by its value. - - @param Question The Question - @param OptionValue Value for Option to be searched. - - @retval Pointer Pointer to the found Option. - @retval NULL Option not found. - -**/ -QUESTION_OPTION * -ValueToOption ( - IN FORM_BROWSER_STATEMENT *Question, - IN EFI_HII_VALUE *OptionValue - ); - -/** - Return data element in an Array by its Index. - - @param Array The data array. - @param Type Type of the data in this array. - @param Index Zero based index for data in this array. - - @retval Value The data to be returned - -**/ -UINT64 -GetArrayData ( - IN VOID *Array, - IN UINT8 Type, - IN UINTN Index - ); - -/** - Set value of a data element in an Array by its Index. - - @param Array The data array. - @param Type Type of the data in this array. - @param Index Zero based index for data in this array. - @param Value The value to be set. - -**/ -VOID -SetArrayData ( - IN VOID *Array, - IN UINT8 Type, - IN UINTN Index, - IN UINT64 Value - ); - -/** - Check whether this value already in the array, if yes, return the index. - - @param Array The data array. - @param Type Type of the data in this array. - @param Value The value to be find. - @param Index The index in the array which has same value with Value. - - @retval TRUE Found the value in the array. - @retval FALSE Not found the value. - -**/ -BOOLEAN -FindArrayData ( - IN VOID *Array, - IN UINT8 Type, - IN UINT64 Value, - OUT UINTN *Index OPTIONAL - ); - -/** - Process a Question's Option (whether selected or un-selected). - - @param Selection Pointer to UI_MENU_SELECTION. - @param MenuOption The MenuOption for this Question. - @param Selected TRUE: if Question is selected. - @param OptionString Pointer of the Option String to be displayed. - - @retval EFI_SUCCESS Question Option process success. - @retval Other Question Option process fail. - -**/ -EFI_STATUS -ProcessOptions ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption, - IN BOOLEAN Selected, - OUT CHAR16 **OptionString - ); - -/** - Process the help string: Split StringPtr to several lines of strings stored in - FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth. - - @param StringPtr The entire help string. - @param FormattedString The oupput formatted string. - @param EachLineWidth The string length of each line in the formatted string. - @param RowCount TRUE: if Question is selected. - -**/ -UINTN -ProcessHelpString ( - IN CHAR16 *StringPtr, - OUT CHAR16 **FormattedString, - OUT UINT16 *EachLineWidth, - IN UINTN RowCount - ); - -/** - Update key's help imformation. - - @param Selection Tell setup browser the information about the Selection - @param MenuOption The Menu option - @param Selected Whether or not a tag be selected - -**/ -VOID -UpdateKeyHelp ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption, - IN BOOLEAN Selected - ); - -/** - Clear retangle with specified text attribute. - - @param LeftColumn Left column of retangle. - @param RightColumn Right column of retangle. - @param TopRow Start row of retangle. - @param BottomRow End row of retangle. - @param TextAttribute The character foreground and background. - -**/ -VOID -ClearLines ( - IN UINTN LeftColumn, - IN UINTN RightColumn, - IN UINTN TopRow, - IN UINTN BottomRow, - IN UINTN TextAttribute - ); - -/** - Count the storage space of a Unicode string. - - This function handles the Unicode string with NARROW_CHAR - and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR - does not count in the resultant output. If a WIDE_CHAR is - hit, then 2 Unicode character will consume an output storage - space with size of CHAR16 till a NARROW_CHAR is hit. - - If String is NULL, then ASSERT (). - - @param String The input string to be counted. - - @return Storage space for the input string. - -**/ -UINTN -GetStringWidth ( - IN CHAR16 *String - ); - -/** - Will copy LineWidth amount of a string in the OutputString buffer and return the - number of CHAR16 characters that were copied into the OutputString buffer. - In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g. - - @param InputString String description for this option. - @param LineWidth Width of the desired string to extract in CHAR16 - characters - @param GlyphWidth The glyph width of the beging char in the string. - @param Index Where in InputString to start the copy process - @param OutputString Buffer to copy the string into - - @return Returns the number of CHAR16 characters that were copied into the OutputString buffer. - -**/ -UINT16 -GetLineByWidth ( - IN CHAR16 *InputString, - IN UINT16 LineWidth, - IN OUT UINT16 *GlyphWidth, - IN OUT UINTN *Index, - OUT CHAR16 **OutputString - ); - -/** - Get the supported width for a particular op-code - - @param Statement The FORM_BROWSER_STATEMENT structure passed in. - @param Handle The handle in the HII database being used - - @return Returns the number of CHAR16 characters that is support. - -**/ -UINT16 -GetWidth ( - IN FORM_BROWSER_STATEMENT *Statement, - IN EFI_HII_HANDLE Handle - ); - -/** - Concatenate a narrow string to another string. - - @param Destination The destination string. - @param Source The source string. The string to be concatenated. - to the end of Destination. - -**/ -VOID -NewStrCat ( - IN OUT CHAR16 *Destination, - IN CHAR16 *Source - ); - -/** - Wait for a key to be pressed by user. - - @param Key The key which is pressed by user. - - @retval EFI_SUCCESS The function always completed successfully. - -**/ -EFI_STATUS -WaitForKeyStroke ( - OUT EFI_INPUT_KEY *Key - ); - -/** - Reset stack pointer to begin of the stack. - -**/ -VOID -ResetScopeStack ( - VOID - ); - -/** - Push the expression options onto the Stack. - - @param Pointer Pointer to the current expression. - @param Level Which type this expression belong to. Form, - statement or option? - - @retval EFI_SUCCESS The value was pushed onto the stack. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. - -**/ -EFI_STATUS -PushConditionalExpression ( - IN FORM_EXPRESSION *Pointer, - IN EXPRESS_LEVEL Level - ); - -/** - Pop the expression options from the Stack - - @param Level Which type this expression belong to. Form, - statement or option? - - @retval EFI_SUCCESS The value was pushed onto the stack. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. - -**/ -EFI_STATUS -PopConditionalExpression ( - IN EXPRESS_LEVEL Level - ); - -/** - Get the expression Buffer pointer. - - @param Level Which type this expression belong to. Form, - statement or option? - - @retval The start pointer of the expression buffer or NULL. - -**/ -FORM_EXPRESSION ** -GetConditionalExpressionList ( - IN EXPRESS_LEVEL Level - ); - -/** - Get the expression list count. - - @param Level Which type this expression belong to. Form, - statement or option? - - @retval >=0 The expression count - @retval -1 Input parameter error. - -**/ -INTN -GetConditionalExpressionCount ( - IN EXPRESS_LEVEL Level - ); - -/** - Push an Operand onto the Stack - - @param Operand Operand to push. - - @retval EFI_SUCCESS The value was pushed onto the stack. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the - stack. - -**/ -EFI_STATUS -PushScope ( - IN UINT8 Operand - ); - -/** - Pop an Operand from the Stack - - @param Operand Operand to pop. - - @retval EFI_SUCCESS The value was pushed onto the stack. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the - stack. - -**/ -EFI_STATUS -PopScope ( - OUT UINT8 *Operand - ); - -/** - Reset stack pointer to begin of the stack. - -**/ -VOID -ResetCurrentExpressionStack ( - VOID - ); - -/** - Push current expression onto the Stack - - @param Pointer Pointer to current expression. - - @retval EFI_SUCCESS The value was pushed onto the stack. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. - -**/ -EFI_STATUS -PushCurrentExpression ( - IN VOID *Pointer - ); - -/** - Pop current expression from the Stack - - @param Pointer Pointer to current expression to be pop. - - @retval EFI_SUCCESS The value was pushed onto the stack. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. - -**/ -EFI_STATUS -PopCurrentExpression ( - OUT VOID **Pointer - ); - -/** - Reset stack pointer to begin of the stack. - -**/ -VOID -ResetMapExpressionListStack ( - VOID - ); - -/** - Push the list of map expression onto the Stack - - @param Pointer Pointer to the list of map expression to be pushed. - - @retval EFI_SUCCESS The value was pushed onto the stack. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. - -**/ -EFI_STATUS -PushMapExpressionList ( - IN VOID *Pointer - ); - -/** - Pop the list of map expression from the Stack - - @param Pointer Pointer to the list of map expression to be pop. - - @retval EFI_SUCCESS The value was pushed onto the stack. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. - -**/ -EFI_STATUS -PopMapExpressionList ( - OUT VOID **Pointer - ); - -/** - Get Form given its FormId. - - @param FormSet The formset which contains this form. - @param FormId Id of this form. - - @retval Pointer The form. - @retval NULL Specified Form is not found in the formset. - -**/ -FORM_BROWSER_FORM * -IdToForm ( - IN FORM_BROWSER_FORMSET *FormSet, - IN UINT16 FormId - ); - -/** - Search a Question in Formset scope using its QuestionId. - - @param FormSet The formset which contains this form. - @param Form The form which contains this Question. - @param QuestionId Id of this Question. - - @retval Pointer The Question. - @retval NULL Specified Question not found in the form. - -**/ -FORM_BROWSER_STATEMENT * -IdToQuestion ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN UINT16 QuestionId - ); - -/** - Zero extend integer/boolean/date/time to UINT64 for comparing. - - @param Value HII Value to be converted. - -**/ -VOID -ExtendValueToU64 ( - IN EFI_HII_VALUE *Value - ); - -/** - Compare two Hii value. - - @param Value1 Expression value to compare on left-hand. - @param Value2 Expression value to compare on right-hand. - @param Result Return value after compare. - retval 0 Two operators equal. - return Positive value if Value1 is greater than Value2. - retval Negative value if Value1 is less than Value2. - @param HiiHandle Only required for string compare. - - @retval other Could not perform compare on two values. - @retval EFI_SUCCESS Compare the value success. - -**/ -EFI_STATUS -CompareHiiValue ( - IN EFI_HII_VALUE *Value1, - IN EFI_HII_VALUE *Value2, - OUT INTN *Result, - IN EFI_HII_HANDLE HiiHandle OPTIONAL - ); - -/** - Evaluate the result of a HII expression - - If Expression is NULL, then ASSERT. - - @param FormSet FormSet associated with this expression. - @param Form Form associated with this expression. - @param Expression Expression to be evaluated. - - @retval EFI_SUCCESS The expression evaluated successfuly - @retval EFI_NOT_FOUND The Question which referenced by a QuestionId - could not be found. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the - stack. - @retval EFI_ACCESS_DENIED The pop operation underflowed the stack - @retval EFI_INVALID_PARAMETER Syntax error with the Expression - -**/ -EFI_STATUS -EvaluateExpression ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN OUT FORM_EXPRESSION *Expression - ); - -/** - Return the result of the expression list. Check the expression list and - return the highest priority express result. - Priority: DisableIf > SuppressIf > GrayOutIf > FALSE - - @param ExpList The input expression list. - @param Evaluate Whether need to evaluate the expression first. - @param FormSet FormSet associated with this expression. Only - needed when Evaluate is TRUE - @param Form Form associated with this expression. Only - needed when Evaluate is TRUE - - @retval EXPRESS_RESULT Return the higher priority express result. - DisableIf > SuppressIf > GrayOutIf > FALSE - -**/ -EXPRESS_RESULT -EvaluateExpressionList ( - IN FORM_EXPRESSION_LIST *ExpList, - IN BOOLEAN Evaluate, - IN FORM_BROWSER_FORMSET *FormSet, OPTIONAL - IN FORM_BROWSER_FORM *Form OPTIONAL - ); - -#endif // _UI_H diff --git a/Nt32Pkg/Nt32Pkg.dsc b/Nt32Pkg/Nt32Pkg.dsc index cfcfc4234d..507e7ed0e1 100644 --- a/Nt32Pkg/Nt32Pkg.dsc +++ b/Nt32Pkg/Nt32Pkg.dsc @@ -102,6 +102,7 @@ DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf GenericBdsLib|IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf + CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf @@ -406,6 +407,7 @@ IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf + MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf MdeModulePkg/Universal/PrintDxe/PrintDxe.inf MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf { diff --git a/Nt32Pkg/Nt32Pkg.fdf b/Nt32Pkg/Nt32Pkg.fdf index 2b8a8e76d3..7315d432fa 100644 --- a/Nt32Pkg/Nt32Pkg.fdf +++ b/Nt32Pkg/Nt32Pkg.fdf @@ -233,6 +233,7 @@ INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf INF MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf INF MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf +INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf INF MdeModulePkg/Universal/PrintDxe/PrintDxe.inf INF RuleOverride = TIANOCOMPRESSED MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index f732703fdb..28b1815c70 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -100,6 +100,7 @@ VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf + CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf !ifdef $(SOURCE_DEBUG_ENABLE) PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf @@ -435,6 +436,7 @@ PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf { diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf index be6ca885b9..7acd16717e 100644 --- a/OvmfPkg/OvmfPkgIa32.fdf +++ b/OvmfPkg/OvmfPkgIa32.fdf @@ -211,6 +211,7 @@ INF IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf INF PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerDxe.inf INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf +INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf INF MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf INF PcAtChipsetPkg/IsaAcpiDxe/IsaAcpi.inf diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index dcfb95aa32..2b35027b6a 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -105,6 +105,7 @@ VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf + CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf !ifdef $(SOURCE_DEBUG_ENABLE) PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf @@ -447,6 +448,7 @@ PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf { diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf index fe77a3a3de..2bd31f6b82 100644 --- a/OvmfPkg/OvmfPkgIa32X64.fdf +++ b/OvmfPkg/OvmfPkgIa32X64.fdf @@ -212,6 +212,7 @@ INF IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf INF PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerDxe.inf INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf +INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf INF MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf INF PcAtChipsetPkg/IsaAcpiDxe/IsaAcpi.inf diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index 89ce44e6d2..cd09beb3b4 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -105,6 +105,7 @@ VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf + CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf !ifdef $(SOURCE_DEBUG_ENABLE) PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf @@ -440,6 +441,7 @@ PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf { diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf index abeedefd85..7db09cad55 100644 --- a/OvmfPkg/OvmfPkgX64.fdf +++ b/OvmfPkg/OvmfPkgX64.fdf @@ -211,6 +211,7 @@ INF IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf INF PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerDxe.inf INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf +INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf INF MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf INF PcAtChipsetPkg/IsaAcpiDxe/IsaAcpi.inf -- 2.39.2