]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
MdeModulePkg/Universal/CapsuleRuntimeDxe: Use safe string functions to refine code.
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / FormDisplay.c
CommitLineData
7c6c064c
ED
1/** @file\r
2Entry and initialization module for the browser.\r
3\r
23c7d425 4Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>\r
c4866c77 5Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>\r
7c6c064c
ED
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "FormDisplay.h"\r
17\r
18//\r
19// Search table for UiDisplayMenu()\r
20//\r
21SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {\r
22 {\r
23 SCAN_UP,\r
24 UiUp,\r
25 },\r
26 {\r
27 SCAN_DOWN,\r
28 UiDown,\r
29 },\r
30 {\r
31 SCAN_PAGE_UP,\r
32 UiPageUp,\r
33 },\r
34 {\r
35 SCAN_PAGE_DOWN,\r
36 UiPageDown,\r
37 },\r
38 {\r
39 SCAN_ESC,\r
40 UiReset,\r
41 },\r
42 {\r
43 SCAN_LEFT,\r
44 UiLeft,\r
45 },\r
46 {\r
47 SCAN_RIGHT,\r
48 UiRight,\r
49 }\r
50};\r
51\r
52UINTN mScanCodeNumber = sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]);\r
53\r
54SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {\r
55 {\r
56 UiNoOperation,\r
57 CfUiNoOperation,\r
58 },\r
59 {\r
60 UiSelect,\r
61 CfUiSelect,\r
62 },\r
63 {\r
64 UiUp,\r
65 CfUiUp,\r
66 },\r
67 {\r
68 UiDown,\r
69 CfUiDown,\r
70 },\r
71 {\r
72 UiLeft,\r
73 CfUiLeft,\r
74 },\r
75 {\r
76 UiRight,\r
77 CfUiRight,\r
78 },\r
79 {\r
80 UiReset,\r
81 CfUiReset,\r
82 },\r
83 {\r
84 UiPageUp,\r
85 CfUiPageUp,\r
86 },\r
87 {\r
88 UiPageDown,\r
89 CfUiPageDown\r
90 }, \r
91 {\r
92 UiHotKey,\r
93 CfUiHotKey\r
94 }\r
95};\r
96\r
97EFI_GUID gDisplayEngineGuid = {\r
98 0xE38C1029, 0xE38F, 0x45b9, {0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62}\r
99};\r
100\r
42645c3d 101BOOLEAN gMisMatch;\r
7c6c064c 102EFI_SCREEN_DESCRIPTOR gStatementDimensions;\r
7c6c064c
ED
103BOOLEAN mStatementLayoutIsChanged = TRUE;\r
104USER_INPUT *gUserInput;\r
105FORM_DISPLAY_ENGINE_FORM *gFormData;\r
106EFI_HII_HANDLE gHiiHandle;\r
107UINT16 gDirection;\r
108LIST_ENTRY gMenuOption;\r
109DISPLAY_HIGHLIGHT_MENU_INFO gHighligthMenuInfo = {0};\r
5a9f73bf
ED
110BOOLEAN mIsFirstForm = TRUE;\r
111FORM_ENTRY_INFO gOldFormEntry = {0};\r
7c6c064c
ED
112\r
113//\r
114// Browser Global Strings\r
115//\r
f2e7732e
ED
116CHAR16 *gReconnectConfirmChanges;\r
117CHAR16 *gReconnectFail;\r
118CHAR16 *gReconnectRequired;\r
119CHAR16 *gChangesOpt;\r
7c6c064c
ED
120CHAR16 *gFormNotFound;\r
121CHAR16 *gNoSubmitIf;\r
f2e7732e 122CHAR16 *gBrowserError;\r
7c6c064c 123CHAR16 *gSaveFailed;\r
4d4deaac
ED
124CHAR16 *gNoSubmitIfFailed;\r
125CHAR16 *gSaveProcess;\r
126CHAR16 *gSaveNoSubmitProcess;\r
127CHAR16 *gDiscardChange;\r
128CHAR16 *gJumpToFormSet;\r
129CHAR16 *gCheckError;\r
7c6c064c
ED
130CHAR16 *gPromptForData;\r
131CHAR16 *gPromptForPassword;\r
132CHAR16 *gPromptForNewPassword;\r
133CHAR16 *gConfirmPassword;\r
134CHAR16 *gConfirmError;\r
135CHAR16 *gPassowordInvalid;\r
136CHAR16 *gPressEnter;\r
137CHAR16 *gEmptyString;\r
138CHAR16 *gMiniString;\r
139CHAR16 *gOptionMismatch;\r
140CHAR16 *gFormSuppress;\r
141CHAR16 *gProtocolNotFound;\r
23c7d425
ED
142CHAR16 *gConfirmDefaultMsg;\r
143CHAR16 *gConfirmSubmitMsg;\r
144CHAR16 *gConfirmDiscardMsg;\r
145CHAR16 *gConfirmResetMsg;\r
146CHAR16 *gConfirmExitMsg;\r
147CHAR16 *gConfirmSubmitMsg2nd;\r
148CHAR16 *gConfirmDefaultMsg2nd;\r
149CHAR16 *gConfirmResetMsg2nd;\r
150CHAR16 *gConfirmExitMsg2nd;\r
151CHAR16 *gConfirmOpt;\r
152CHAR16 *gConfirmOptYes;\r
153CHAR16 *gConfirmOptNo;\r
154CHAR16 *gConfirmMsgConnect;\r
155CHAR16 *gConfirmMsgEnd;\r
af047db7 156CHAR16 gModalSkipColumn;\r
7c6c064c
ED
157CHAR16 gPromptBlockWidth;\r
158CHAR16 gOptionBlockWidth;\r
159CHAR16 gHelpBlockWidth;\r
160CHAR16 *mUnknownString;\r
161\r
162FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData = {\r
163 FORM_DISPLAY_DRIVER_SIGNATURE,\r
164 NULL,\r
165 {\r
166 FormDisplay,\r
5a9f73bf 167 DriverClearDisplayPage,\r
7c6c064c
ED
168 ConfirmDataChange\r
169 }\r
170};\r
171\r
172\r
173/**\r
174 Get the string based on the StringId and HII Package List Handle.\r
175\r
176 @param Token The String's ID.\r
177 @param HiiHandle The package list in the HII database to search for\r
178 the specified string.\r
179\r
180 @return The output string.\r
181\r
182**/\r
183CHAR16 *\r
184GetToken (\r
185 IN EFI_STRING_ID Token,\r
186 IN EFI_HII_HANDLE HiiHandle\r
187 )\r
188{\r
189 EFI_STRING String;\r
190\r
191 String = HiiGetString (HiiHandle, Token, NULL);\r
192 if (String == NULL) {\r
193 String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);\r
194 ASSERT (String != NULL);\r
195 }\r
196\r
197 return (CHAR16 *) String;\r
198}\r
199\r
200\r
201/**\r
202 Initialize the HII String Token to the correct values.\r
203\r
204**/\r
205VOID\r
206InitializeDisplayStrings (\r
207 VOID\r
208 )\r
209{\r
f2e7732e 210 gReconnectConfirmChanges = GetToken (STRING_TOKEN (RECONNECT_CONFIRM_CHANGES), gHiiHandle);\r
7c6c064c
ED
211 mUnknownString = GetToken (STRING_TOKEN (UNKNOWN_STRING), gHiiHandle);\r
212 gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle);\r
4d4deaac 213 gNoSubmitIfFailed = GetToken (STRING_TOKEN (NO_SUBMIT_IF_CHECK_FAILED), gHiiHandle);\r
f2e7732e
ED
214 gReconnectFail = GetToken (STRING_TOKEN (RECONNECT_FAILED), gHiiHandle);\r
215 gReconnectRequired = GetToken (STRING_TOKEN (RECONNECT_REQUIRED), gHiiHandle);\r
216 gChangesOpt = GetToken (STRING_TOKEN (RECONNECT_CHANGES_OPTIONS), gHiiHandle);\r
4d4deaac
ED
217 gSaveProcess = GetToken (STRING_TOKEN (DISCARD_OR_JUMP), gHiiHandle);\r
218 gSaveNoSubmitProcess = GetToken (STRING_TOKEN (DISCARD_OR_CHECK), gHiiHandle);\r
219 gDiscardChange = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_DISCARD), gHiiHandle);\r
220 gJumpToFormSet = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_JUMP), gHiiHandle);\r
221 gCheckError = GetToken (STRING_TOKEN (DISCARD_OR_CHECK_CHECK), gHiiHandle);\r
7c6c064c
ED
222 gPromptForData = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle);\r
223 gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle);\r
224 gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle);\r
225 gConfirmPassword = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle);\r
226 gConfirmError = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle);\r
227 gPassowordInvalid = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle);\r
228 gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle);\r
229 gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
230 gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle);\r
231 gOptionMismatch = GetToken (STRING_TOKEN (OPTION_MISMATCH), gHiiHandle);\r
232 gFormSuppress = GetToken (STRING_TOKEN (FORM_SUPPRESSED), gHiiHandle);\r
233 gProtocolNotFound = GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND), gHiiHandle);\r
234 gFormNotFound = GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND), gHiiHandle);\r
235 gNoSubmitIf = GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF), gHiiHandle);\r
f2e7732e 236 gBrowserError = GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR), gHiiHandle);\r
23c7d425
ED
237 gConfirmDefaultMsg = GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE), gHiiHandle);\r
238 gConfirmDiscardMsg = GetToken (STRING_TOKEN (CONFIRM_DISCARD_MESSAGE), gHiiHandle);\r
239 gConfirmSubmitMsg = GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE), gHiiHandle);\r
240 gConfirmResetMsg = GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE), gHiiHandle);\r
241 gConfirmExitMsg = GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE), gHiiHandle);\r
242 gConfirmDefaultMsg2nd = GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE_2ND), gHiiHandle);\r
243 gConfirmSubmitMsg2nd = GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE_2ND), gHiiHandle);\r
244 gConfirmResetMsg2nd = GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE_2ND), gHiiHandle);\r
245 gConfirmExitMsg2nd = GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE_2ND), gHiiHandle);\r
246 gConfirmOpt = GetToken (STRING_TOKEN (CONFIRM_OPTION), gHiiHandle);\r
247 gConfirmOptYes = GetToken (STRING_TOKEN (CONFIRM_OPTION_YES), gHiiHandle);\r
248 gConfirmOptNo = GetToken (STRING_TOKEN (CONFIRM_OPTION_NO), gHiiHandle);\r
249 gConfirmMsgConnect = GetToken (STRING_TOKEN (CONFIRM_OPTION_CONNECT), gHiiHandle);\r
250 gConfirmMsgEnd = GetToken (STRING_TOKEN (CONFIRM_OPTION_END), gHiiHandle);\r
7c6c064c
ED
251}\r
252\r
253/**\r
254 Free up the resource allocated for all strings required\r
255 by Setup Browser.\r
256\r
257**/\r
258VOID\r
259FreeDisplayStrings (\r
260 VOID\r
261 )\r
262{\r
263 FreePool (mUnknownString);\r
264 FreePool (gEmptyString);\r
265 FreePool (gSaveFailed);\r
4d4deaac 266 FreePool (gNoSubmitIfFailed);\r
f2e7732e
ED
267 FreePool (gReconnectFail);\r
268 FreePool (gReconnectRequired);\r
269 FreePool (gChangesOpt);\r
270 FreePool (gReconnectConfirmChanges);\r
4d4deaac
ED
271 FreePool (gSaveProcess);\r
272 FreePool (gSaveNoSubmitProcess);\r
273 FreePool (gDiscardChange);\r
274 FreePool (gJumpToFormSet);\r
275 FreePool (gCheckError);\r
7c6c064c
ED
276 FreePool (gPromptForData);\r
277 FreePool (gPromptForPassword);\r
278 FreePool (gPromptForNewPassword);\r
279 FreePool (gConfirmPassword);\r
280 FreePool (gConfirmError);\r
281 FreePool (gPassowordInvalid);\r
282 FreePool (gPressEnter);\r
283 FreePool (gMiniString);\r
284 FreePool (gOptionMismatch);\r
285 FreePool (gFormSuppress);\r
286 FreePool (gProtocolNotFound);\r
f2e7732e 287 FreePool (gBrowserError);\r
7c6c064c
ED
288 FreePool (gNoSubmitIf);\r
289 FreePool (gFormNotFound);\r
23c7d425
ED
290 FreePool (gConfirmDefaultMsg);\r
291 FreePool (gConfirmSubmitMsg);\r
292 FreePool (gConfirmDiscardMsg);\r
293 FreePool (gConfirmResetMsg);\r
294 FreePool (gConfirmExitMsg);\r
295 FreePool (gConfirmDefaultMsg2nd);\r
296 FreePool (gConfirmSubmitMsg2nd);\r
297 FreePool (gConfirmResetMsg2nd);\r
298 FreePool (gConfirmExitMsg2nd);\r
299 FreePool (gConfirmOpt);\r
300 FreePool (gConfirmOptYes);\r
301 FreePool (gConfirmOptNo);\r
302 FreePool (gConfirmMsgConnect);\r
303 FreePool (gConfirmMsgEnd);\r
7c6c064c
ED
304}\r
305\r
306/**\r
307 Get prompt string id from the opcode data buffer.\r
308\r
309 @param OpCode The input opcode buffer.\r
310\r
311 @return The prompt string id.\r
312\r
313**/\r
314EFI_STRING_ID\r
315GetPrompt (\r
316 IN EFI_IFR_OP_HEADER *OpCode\r
317 )\r
318{\r
319 EFI_IFR_STATEMENT_HEADER *Header;\r
320\r
321 if (OpCode->Length <= sizeof (EFI_IFR_OP_HEADER)) {\r
322 return 0;\r
323 }\r
324\r
325 Header = (EFI_IFR_STATEMENT_HEADER *) (OpCode + 1);\r
326\r
327 return Header->Prompt;\r
328}\r
329\r
330/**\r
331 Get the supported width for a particular op-code\r
332\r
6f05c023 333 @param MenuOption The menu option.\r
af047db7 334 @param AdjustWidth The width which is saved for the space.\r
7c6c064c
ED
335\r
336 @return Returns the number of CHAR16 characters that is support.\r
337\r
338**/\r
339UINT16\r
340GetWidth (\r
6f05c023
ED
341 IN UI_MENU_OPTION *MenuOption,\r
342 OUT UINT16 *AdjustWidth\r
7c6c064c
ED
343 )\r
344{\r
6f05c023
ED
345 CHAR16 *String;\r
346 UINTN Size;\r
347 EFI_IFR_TEXT *TestOp;\r
348 UINT16 ReturnWidth;\r
349 FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
350\r
351 Statement = MenuOption->ThisTag;\r
7c6c064c 352\r
af047db7
ED
353 //\r
354 // For modal form, clean the entire row.\r
355 //\r
356 if ((gFormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
ae4f5746
ED
357 if (AdjustWidth != NULL) {\r
358 *AdjustWidth = LEFT_SKIPPED_COLUMNS;\r
359 }\r
360 return (UINT16)(gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * (gModalSkipColumn + LEFT_SKIPPED_COLUMNS));\r
af047db7
ED
361 }\r
362\r
7c6c064c
ED
363 Size = 0;\r
364\r
365 //\r
366 // See if the second text parameter is really NULL\r
367 //\r
368 if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {\r
369 TestOp = (EFI_IFR_TEXT *) Statement->OpCode;\r
370 if (TestOp->TextTwo != 0) {\r
371 String = GetToken (TestOp->TextTwo, gFormData->HiiHandle);\r
372 Size = StrLen (String);\r
373 FreePool (String);\r
374 }\r
375 }\r
376\r
377 if ((Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||\r
378 (Statement->OpCode->OpCode == EFI_IFR_REF_OP) ||\r
379 (Statement->OpCode->OpCode == EFI_IFR_PASSWORD_OP) ||\r
380 (Statement->OpCode->OpCode == EFI_IFR_ACTION_OP) ||\r
381 (Statement->OpCode->OpCode == EFI_IFR_RESET_BUTTON_OP) ||\r
382 //\r
383 // Allow a wide display if text op-code and no secondary text op-code\r
384 //\r
385 ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))\r
386 ) {\r
af047db7
ED
387 \r
388 //\r
389 // Return the space width.\r
390 // \r
391 if (AdjustWidth != NULL) {\r
392 *AdjustWidth = 2;\r
393 }\r
394 //\r
395 // Keep consistent with current behavior.\r
396 //\r
6f05c023
ED
397 ReturnWidth = (UINT16) (gPromptBlockWidth + gOptionBlockWidth - 2);\r
398 } else {\r
399 if (AdjustWidth != NULL) {\r
400 *AdjustWidth = 1;\r
401 }\r
402\r
403 ReturnWidth = (UINT16) (gPromptBlockWidth - 1);\r
7c6c064c
ED
404 }\r
405\r
6f05c023
ED
406 //\r
407 // For nest in statement, should the subtitle indent.\r
408 //\r
409 if (MenuOption->NestInStatement) {\r
410 ReturnWidth -= SUBTITLE_INDENT;\r
af047db7 411 }\r
6f05c023
ED
412\r
413 return ReturnWidth;\r
7c6c064c
ED
414}\r
415\r
416/**\r
417 Will copy LineWidth amount of a string in the OutputString buffer and return the\r
418 number of CHAR16 characters that were copied into the OutputString buffer.\r
419 The output string format is:\r
420 Glyph Info + String info + '\0'.\r
421\r
422 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.\r
423\r
424 @param InputString String description for this option.\r
425 @param LineWidth Width of the desired string to extract in CHAR16\r
426 characters\r
427 @param GlyphWidth The glyph width of the begin of the char in the string.\r
428 @param Index Where in InputString to start the copy process\r
429 @param OutputString Buffer to copy the string into\r
430\r
431 @return Returns the number of CHAR16 characters that were copied into the OutputString \r
432 buffer, include extra glyph info and '\0' info.\r
433\r
434**/\r
435UINT16\r
436GetLineByWidth (\r
437 IN CHAR16 *InputString,\r
438 IN UINT16 LineWidth,\r
439 IN OUT UINT16 *GlyphWidth,\r
440 IN OUT UINTN *Index,\r
441 OUT CHAR16 **OutputString\r
442 )\r
443{\r
444 UINT16 StrOffset;\r
445 UINT16 GlyphOffset;\r
446 UINT16 OriginalGlyphWidth;\r
447 BOOLEAN ReturnFlag;\r
448 UINT16 LastSpaceOffset;\r
449 UINT16 LastGlyphWidth;\r
450\r
451 if (InputString == NULL || Index == NULL || OutputString == NULL) {\r
452 return 0;\r
453 }\r
454\r
455 if (LineWidth == 0 || *GlyphWidth == 0) {\r
456 return 0;\r
457 }\r
458\r
459 //\r
460 // Save original glyph width.\r
461 //\r
462 OriginalGlyphWidth = *GlyphWidth;\r
463 LastGlyphWidth = OriginalGlyphWidth;\r
464 ReturnFlag = FALSE;\r
465 LastSpaceOffset = 0;\r
466\r
467 //\r
468 // 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.\r
469 // To avoid displaying this empty line in screen, just skip the two CHARs here.\r
470 //\r
471 if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
472 *Index = *Index + 2;\r
473 }\r
474\r
475 //\r
476 // Fast-forward the string and see if there is a carriage-return in the string\r
477 //\r
478 for (StrOffset = 0, GlyphOffset = 0; GlyphOffset <= LineWidth; StrOffset++) {\r
479 switch (InputString[*Index + StrOffset]) {\r
480 case NARROW_CHAR:\r
481 *GlyphWidth = 1;\r
482 break;\r
483\r
484 case WIDE_CHAR:\r
485 *GlyphWidth = 2;\r
486 break;\r
487\r
488 case CHAR_CARRIAGE_RETURN:\r
489 case CHAR_LINEFEED:\r
490 case CHAR_NULL:\r
491 ReturnFlag = TRUE;\r
492 break;\r
493\r
494 default:\r
495 GlyphOffset = GlyphOffset + *GlyphWidth;\r
496\r
497 //\r
498 // Record the last space info in this line. Will be used in rewind.\r
499 //\r
500 if ((InputString[*Index + StrOffset] == CHAR_SPACE) && (GlyphOffset <= LineWidth)) {\r
501 LastSpaceOffset = StrOffset;\r
502 LastGlyphWidth = *GlyphWidth;\r
503 }\r
504 break;\r
505 }\r
506\r
507 if (ReturnFlag) {\r
508 break;\r
509 }\r
510 } \r
511\r
512 //\r
513 // Rewind the string from the maximum size until we see a space to break the line\r
514 //\r
515 if (GlyphOffset > LineWidth) {\r
516 //\r
517 // Rewind the string to last space char in this line.\r
518 //\r
519 if (LastSpaceOffset != 0) {\r
520 StrOffset = LastSpaceOffset;\r
521 *GlyphWidth = LastGlyphWidth;\r
522 } else {\r
523 //\r
524 // Roll back to last char in the line width.\r
525 //\r
526 StrOffset--;\r
527 }\r
528 }\r
529\r
530 //\r
531 // The CHAR_NULL has process last time, this time just return 0 to stand for the end.\r
532 //\r
533 if (StrOffset == 0 && (InputString[*Index + StrOffset] == CHAR_NULL)) {\r
534 return 0;\r
535 }\r
536\r
537 //\r
538 // Need extra glyph info and '\0' info, so +2.\r
539 //\r
540 *OutputString = AllocateZeroPool (((UINTN) (StrOffset + 2) * sizeof(CHAR16)));\r
541 if (*OutputString == NULL) {\r
542 return 0;\r
543 }\r
544\r
545 //\r
546 // Save the glyph info at the begin of the string, will used by Print function.\r
547 //\r
548 if (OriginalGlyphWidth == 1) {\r
549 *(*OutputString) = NARROW_CHAR;\r
550 } else {\r
551 *(*OutputString) = WIDE_CHAR;\r
552 }\r
553\r
554 CopyMem ((*OutputString) + 1, &InputString[*Index], StrOffset * sizeof(CHAR16));\r
555\r
556 if (InputString[*Index + StrOffset] == CHAR_SPACE) {\r
557 //\r
558 // Skip the space info at the begin of next line.\r
559 // \r
560 *Index = (UINT16) (*Index + StrOffset + 1);\r
561 } else if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {\r
562 //\r
563 // Skip the /n or /n/r info.\r
564 //\r
565 if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {\r
566 *Index = (UINT16) (*Index + StrOffset + 2);\r
567 } else {\r
568 *Index = (UINT16) (*Index + StrOffset + 1);\r
569 }\r
570 } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) {\r
571 //\r
572 // Skip the /r or /r/n info.\r
573 // \r
574 if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) {\r
575 *Index = (UINT16) (*Index + StrOffset + 2);\r
576 } else {\r
577 *Index = (UINT16) (*Index + StrOffset + 1);\r
578 }\r
579 } else {\r
580 *Index = (UINT16) (*Index + StrOffset);\r
581 }\r
582\r
583 //\r
584 // Include extra glyph info and '\0' info, so +2.\r
585 //\r
586 return StrOffset + 2;\r
587}\r
588\r
589/**\r
590 Add one menu option by specified description and context.\r
591\r
592 @param Statement Statement of this Menu Option.\r
593 @param MenuItemCount The index for this Option in the Menu.\r
594 @param NestIn Whether this statement is nest in another statement.\r
595\r
596**/\r
597VOID\r
598UiAddMenuOption (\r
599 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,\r
600 IN UINT16 *MenuItemCount,\r
601 IN BOOLEAN NestIn\r
602 )\r
603{\r
604 UI_MENU_OPTION *MenuOption;\r
605 UINTN Index;\r
606 UINTN Count;\r
607 CHAR16 *String;\r
608 UINT16 NumberOfLines;\r
609 UINT16 GlyphWidth;\r
610 UINT16 Width;\r
611 UINTN ArrayEntry;\r
612 CHAR16 *OutputString;\r
613 EFI_STRING_ID PromptId;\r
614\r
615 NumberOfLines = 1;\r
616 ArrayEntry = 0;\r
617 GlyphWidth = 1;\r
618 Count = 1;\r
619 MenuOption = NULL;\r
620\r
621 PromptId = GetPrompt (Statement->OpCode);\r
622 ASSERT (PromptId != 0);\r
623\r
624 String = GetToken (PromptId, gFormData->HiiHandle);\r
625 ASSERT (String != NULL);\r
626\r
7c6c064c 627 if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
7c6c064c
ED
628 Count = 3;\r
629 }\r
630\r
631 for (Index = 0; Index < Count; Index++) {\r
632 MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
633 ASSERT (MenuOption);\r
634\r
635 MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;\r
636 MenuOption->Description = String;\r
637 MenuOption->Handle = gFormData->HiiHandle;\r
638 MenuOption->ThisTag = Statement;\r
639 MenuOption->NestInStatement = NestIn;\r
640 MenuOption->EntryNumber = *MenuItemCount;\r
641\r
7c6c064c
ED
642 MenuOption->Sequence = Index;\r
643\r
644 if ((Statement->Attribute & HII_DISPLAY_GRAYOUT) != 0) {\r
645 MenuOption->GrayOut = TRUE;\r
646 } else {\r
647 MenuOption->GrayOut = FALSE;\r
648 }\r
649\r
650 if ((Statement->Attribute & HII_DISPLAY_LOCK) != 0 || (gFormData->Attribute & HII_DISPLAY_LOCK) != 0) {\r
651 MenuOption->GrayOut = TRUE;\r
652 }\r
653\r
654 //\r
655 // If the form or the question has the lock attribute, deal same as grayout.\r
656 //\r
657 if ((gFormData->Attribute & HII_DISPLAY_LOCK) != 0 || (Statement->Attribute & HII_DISPLAY_LOCK) != 0) {\r
658 MenuOption->GrayOut = TRUE;\r
659 }\r
660\r
661 switch (Statement->OpCode->OpCode) {\r
662 case EFI_IFR_ORDERED_LIST_OP:\r
663 case EFI_IFR_ONE_OF_OP:\r
664 case EFI_IFR_NUMERIC_OP:\r
665 case EFI_IFR_TIME_OP:\r
666 case EFI_IFR_DATE_OP:\r
667 case EFI_IFR_CHECKBOX_OP:\r
668 case EFI_IFR_PASSWORD_OP:\r
669 case EFI_IFR_STRING_OP:\r
670 //\r
671 // User could change the value of these items\r
672 //\r
673 MenuOption->IsQuestion = TRUE;\r
674 break;\r
675 case EFI_IFR_TEXT_OP:\r
676 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement)) {\r
677 //\r
678 // Initializing GrayOut option as TRUE for Text setup options \r
679 // so that those options will be Gray in colour and un selectable.\r
680 //\r
681 MenuOption->GrayOut = TRUE;\r
682 }\r
683 break;\r
684 default:\r
685 MenuOption->IsQuestion = FALSE;\r
686 break;\r
687 }\r
688\r
689 if ((Statement->Attribute & HII_DISPLAY_READONLY) != 0) {\r
690 MenuOption->ReadOnly = TRUE;\r
691 if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu)) {\r
692 MenuOption->GrayOut = TRUE;\r
693 }\r
694 }\r
695\r
6f05c023
ED
696 if (Index == 0 && \r
697 (Statement->OpCode->OpCode != EFI_IFR_DATE_OP) && \r
698 (Statement->OpCode->OpCode != EFI_IFR_TIME_OP)) {\r
699 Width = GetWidth (MenuOption, NULL);\r
700 for (; GetLineByWidth (String, Width, &GlyphWidth,&ArrayEntry, &OutputString) != 0x0000;) {\r
701 //\r
702 // If there is more string to process print on the next row and increment the Skip value\r
703 //\r
704 if (StrLen (&String[ArrayEntry]) != 0) {\r
705 NumberOfLines++;\r
706 }\r
707 FreePool (OutputString);\r
708 }\r
709 } else {\r
710 //\r
711 // Add three MenuOptions for Date/Time\r
712 // Data format : [01/02/2004] [11:22:33]\r
713 // Line number : 0 0 1 0 0 1\r
714 // \r
715 NumberOfLines = 0;\r
716 }\r
717\r
718 if (Index == 2) {\r
719 //\r
720 // Override LineNumber for the MenuOption in Date/Time sequence\r
721 //\r
722 MenuOption->Skip = 1;\r
723 } else {\r
724 MenuOption->Skip = NumberOfLines;\r
725 }\r
726\r
7c6c064c
ED
727 InsertTailList (&gMenuOption, &MenuOption->Link);\r
728 }\r
729\r
730 (*MenuItemCount)++;\r
731}\r
732\r
733/**\r
734 Create the menu list base on the form data info.\r
735\r
736**/\r
737VOID\r
738ConvertStatementToMenu (\r
739 VOID\r
740 )\r
741{\r
742 UINT16 MenuItemCount;\r
743 LIST_ENTRY *Link;\r
744 LIST_ENTRY *NestLink;\r
745 FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
746 FORM_DISPLAY_ENGINE_STATEMENT *NestStatement;\r
747\r
748 MenuItemCount = 0;\r
749 InitializeListHead (&gMenuOption);\r
750\r
751 Link = GetFirstNode (&gFormData->StatementListHead);\r
752 while (!IsNull (&gFormData->StatementListHead, Link)) {\r
753 Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);\r
754 Link = GetNextNode (&gFormData->StatementListHead, Link);\r
755\r
756 //\r
757 // Skip the opcode not recognized by Display core.\r
758 //\r
759 if (Statement->OpCode->OpCode == EFI_IFR_GUID_OP) {\r
760 continue;\r
761 }\r
762\r
763 UiAddMenuOption (Statement, &MenuItemCount, FALSE);\r
764\r
765 //\r
766 // Check the statement nest in this host statement.\r
767 //\r
768 NestLink = GetFirstNode (&Statement->NestStatementList);\r
769 while (!IsNull (&Statement->NestStatementList, NestLink)) {\r
770 NestStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink);\r
771 NestLink = GetNextNode (&Statement->NestStatementList, NestLink);\r
772\r
077c7aee
ED
773 //\r
774 // Skip the opcode not recognized by Display core.\r
775 //\r
776 if (NestStatement->OpCode->OpCode == EFI_IFR_GUID_OP) {\r
777 continue;\r
778 }\r
779\r
7c6c064c
ED
780 UiAddMenuOption (NestStatement, &MenuItemCount, TRUE);\r
781 }\r
782 }\r
783}\r
784\r
785/**\r
786 Count the storage space of a Unicode string.\r
787\r
788 This function handles the Unicode string with NARROW_CHAR\r
789 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR\r
790 does not count in the resultant output. If a WIDE_CHAR is\r
791 hit, then 2 Unicode character will consume an output storage\r
792 space with size of CHAR16 till a NARROW_CHAR is hit.\r
793\r
794 If String is NULL, then ASSERT ().\r
795\r
796 @param String The input string to be counted.\r
797\r
798 @return Storage space for the input string.\r
799\r
800**/\r
801UINTN\r
802GetStringWidth (\r
803 IN CHAR16 *String\r
804 )\r
805{\r
806 UINTN Index;\r
807 UINTN Count;\r
808 UINTN IncrementValue;\r
809\r
810 ASSERT (String != NULL);\r
811 if (String == NULL) {\r
812 return 0;\r
813 }\r
814\r
815 Index = 0;\r
816 Count = 0;\r
817 IncrementValue = 1;\r
818\r
819 do {\r
820 //\r
821 // Advance to the null-terminator or to the first width directive\r
822 //\r
823 for (;\r
824 (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);\r
825 Index++, Count = Count + IncrementValue\r
826 )\r
827 ;\r
828\r
829 //\r
830 // We hit the null-terminator, we now have a count\r
831 //\r
832 if (String[Index] == 0) {\r
833 break;\r
834 }\r
835 //\r
836 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed\r
837 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)\r
838 //\r
839 if (String[Index] == NARROW_CHAR) {\r
840 //\r
841 // Skip to the next character\r
842 //\r
843 Index++;\r
844 IncrementValue = 1;\r
845 } else {\r
846 //\r
847 // Skip to the next character\r
848 //\r
849 Index++;\r
850 IncrementValue = 2;\r
851 }\r
852 } while (String[Index] != 0);\r
853\r
854 //\r
855 // Increment by one to include the null-terminator in the size\r
856 //\r
857 Count++;\r
858\r
859 return Count * sizeof (CHAR16);\r
860}\r
861\r
862/**\r
863 Base on the input option string to update the skip value for a menu option.\r
864\r
865 @param MenuOption The MenuOption to be checked.\r
866 @param OptionString The input option string.\r
867\r
868**/\r
869VOID\r
870UpdateSkipInfoForMenu (\r
871 IN UI_MENU_OPTION *MenuOption,\r
872 IN CHAR16 *OptionString\r
873 )\r
874{\r
875 UINTN Index;\r
876 UINT16 Width;\r
877 UINTN Row;\r
878 CHAR16 *OutputString;\r
879 UINT16 GlyphWidth;\r
880\r
881 Width = (UINT16) gOptionBlockWidth;\r
882 GlyphWidth = 1;\r
883 Row = 1;\r
884\r
885 for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
886 if (StrLen (&OptionString[Index]) != 0) {\r
887 Row++;\r
888 }\r
889\r
890 FreePool (OutputString);\r
891 }\r
892\r
893 if ((Row > MenuOption->Skip) && \r
894 (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_DATE_OP) && \r
895 (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_TIME_OP)) {\r
896 MenuOption->Skip = Row;\r
897 }\r
898}\r
899\r
900/**\r
901 Update display lines for a Menu Option.\r
902\r
903 @param MenuOption The MenuOption to be checked.\r
904\r
905**/\r
906VOID\r
907UpdateOptionSkipLines (\r
908 IN UI_MENU_OPTION *MenuOption\r
909 )\r
910{\r
911 CHAR16 *OptionString;\r
912\r
913 OptionString = NULL;\r
914\r
915 ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);\r
916 if (OptionString != NULL) {\r
917 UpdateSkipInfoForMenu (MenuOption, OptionString);\r
918\r
919 FreePool (OptionString);\r
920 }\r
921\r
922 if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo != 0)) {\r
923 OptionString = GetToken (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo, gFormData->HiiHandle);\r
924\r
925 if (OptionString != NULL) {\r
926 UpdateSkipInfoForMenu (MenuOption, OptionString);\r
927\r
928 FreePool (OptionString);\r
929 }\r
930 }\r
931}\r
932\r
ab369468
ED
933/**\r
934 Check whether this Menu Option could be print.\r
935\r
936 Check Prompt string, option string or text two string not NULL.\r
937\r
938 This is an internal function.\r
939\r
940 @param MenuOption The MenuOption to be checked.\r
941\r
942 @retval TRUE This Menu Option is printable.\r
943 @retval FALSE This Menu Option could not be printable.\r
944\r
945**/\r
946BOOLEAN\r
947PrintableMenu (\r
948 UI_MENU_OPTION *MenuOption\r
949 )\r
950{\r
951 EFI_STATUS Status;\r
952 EFI_STRING OptionString;\r
953\r
954 OptionString = NULL;\r
955\r
956 if (MenuOption->Description[0] != '\0') {\r
957 return TRUE;\r
958 }\r
959\r
960 Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);\r
961 if (EFI_ERROR (Status)) {\r
962 return FALSE;\r
963 }\r
964 if (OptionString != NULL && OptionString[0] != '\0') {\r
965 FreePool (OptionString);\r
966 return TRUE;\r
967 }\r
968\r
969 if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo != 0)) {\r
970 OptionString = GetToken (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo, gFormData->HiiHandle);\r
971 ASSERT (OptionString != NULL);\r
972 if (OptionString[0] != '\0'){\r
973 FreePool (OptionString);\r
974 return TRUE;\r
975 }\r
976 }\r
977\r
978 return FALSE;\r
979}\r
980\r
7c6c064c
ED
981/**\r
982 Check whether this Menu Option could be highlighted.\r
983\r
984 This is an internal function.\r
985\r
986 @param MenuOption The MenuOption to be checked.\r
987\r
988 @retval TRUE This Menu Option is selectable.\r
989 @retval FALSE This Menu Option could not be selected.\r
990\r
991**/\r
992BOOLEAN\r
993IsSelectable (\r
994 UI_MENU_OPTION *MenuOption\r
995 )\r
996{\r
997 if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||\r
ab369468 998 MenuOption->GrayOut || MenuOption->ReadOnly || !PrintableMenu (MenuOption)) {\r
7c6c064c
ED
999 return FALSE;\r
1000 } else {\r
1001 return TRUE;\r
1002 }\r
1003}\r
1004\r
1005/**\r
1006 Move to next selectable statement.\r
1007\r
1008 This is an internal function.\r
1009\r
1010 @param GoUp The navigation direction. TRUE: up, FALSE: down.\r
1011 @param CurrentPosition Current position.\r
1012 @param GapToTop Gap position to top or bottom.\r
ab369468 1013 @param FindInForm Whether find menu in current form or beyond.\r
7c6c064c
ED
1014\r
1015 @return The row distance from current MenuOption to next selectable MenuOption.\r
1016\r
1017 @retval -1 Reach the begin of the menu, still can't find the selectable menu.\r
ab369468
ED
1018 @retval Value Find the selectable menu, maybe the truly selectable, maybe the \r
1019 first menu showing beyond current form or last menu showing in \r
1020 current form.\r
1021 The value is the line number between the new selected menu and the\r
1022 current select menu, not include the new selected menu.\r
7c6c064c
ED
1023\r
1024**/\r
1025INTN\r
1026MoveToNextStatement (\r
1027 IN BOOLEAN GoUp,\r
1028 IN OUT LIST_ENTRY **CurrentPosition,\r
ab369468
ED
1029 IN UINTN GapToTop,\r
1030 IN BOOLEAN FindInForm\r
7c6c064c
ED
1031 )\r
1032{\r
1033 INTN Distance;\r
1034 LIST_ENTRY *Pos;\r
1035 UI_MENU_OPTION *NextMenuOption;\r
1036 UI_MENU_OPTION *PreMenuOption;\r
1037\r
1038 Distance = 0;\r
1039 Pos = *CurrentPosition;\r
ab369468
ED
1040\r
1041 if (Pos == &gMenuOption) {\r
1042 return -1;\r
1043 }\r
1044\r
7c6c064c
ED
1045 PreMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
1046\r
1047 while (TRUE) {\r
1048 NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
1049 //\r
1050 // NextMenuOption->Row == 0 means this menu has not calculate\r
1051 // the NextMenuOption->Skip value yet, just calculate here.\r
1052 //\r
1053 if (NextMenuOption->Row == 0) {\r
1054 UpdateOptionSkipLines (NextMenuOption);\r
1055 }\r
7c6c064c 1056\r
ab369468
ED
1057 if (IsSelectable (NextMenuOption)) {\r
1058 break;\r
7c6c064c
ED
1059 }\r
1060\r
ab369468
ED
1061 //\r
1062 // In this case, still can't find the selectable menu,\r
1063 // return the first one beyond the showing form.\r
1064 //\r
1065 if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
1066 if (FindInForm) {\r
1067 NextMenuOption = PreMenuOption;\r
1068 }\r
7c6c064c
ED
1069 break;\r
1070 }\r
1071\r
ab369468
ED
1072 Distance += NextMenuOption->Skip;\r
1073\r
7c6c064c
ED
1074 //\r
1075 // Arrive at begin of the menu list.\r
1076 //\r
1077 if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
1078 Distance = -1;\r
1079 break;\r
1080 }\r
1081\r
7c6c064c 1082 Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
ab369468 1083 PreMenuOption = NextMenuOption;\r
7c6c064c
ED
1084 }\r
1085\r
1086 *CurrentPosition = &NextMenuOption->Link;\r
1087 return Distance;\r
1088}\r
1089\r
1090\r
1091/**\r
1092 Process option string for date/time opcode.\r
1093\r
1094 @param MenuOption Menu option point to date/time.\r
1095 @param OptionString Option string input for process.\r
1096 @param AddOptCol Whether need to update MenuOption->OptCol. \r
1097\r
1098**/\r
1099VOID \r
1100ProcessStringForDateTime (\r
1101 UI_MENU_OPTION *MenuOption,\r
1102 CHAR16 *OptionString,\r
1103 BOOLEAN AddOptCol\r
1104 )\r
1105{\r
1106 UINTN Index;\r
1107 UINTN Count;\r
1108 FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
1109 EFI_IFR_DATE *Date;\r
1110 EFI_IFR_TIME *Time;\r
1111\r
1112 ASSERT (MenuOption != NULL && OptionString != NULL);\r
1113 \r
1114 Statement = MenuOption->ThisTag;\r
1115 Date = NULL;\r
1116 Time = NULL;\r
1117 if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
1118 Date = (EFI_IFR_DATE *) Statement->OpCode;\r
1119 } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
1120 Time = (EFI_IFR_TIME *) Statement->OpCode;\r
1121 }\r
1122 \r
1123 //\r
1124 // If leading spaces on OptionString - remove the spaces\r
1125 //\r
1126 for (Index = 0; OptionString[Index] == L' '; Index++) {\r
1127 //\r
1128 // Base on the blockspace to get the option column info.\r
1129 //\r
1130 if (AddOptCol) {\r
1131 MenuOption->OptCol++;\r
1132 }\r
1133 }\r
1134 \r
1135 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1136 OptionString[Count] = OptionString[Index];\r
1137 Count++;\r
1138 }\r
1139 OptionString[Count] = CHAR_NULL;\r
1140 \r
1141 //\r
1142 // Enable to suppress field in the opcode base on the flag.\r
1143 //\r
1144 if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
1145 //\r
1146 // OptionString format is: <**: **: ****>\r
1147 // |month|day|year|\r
1148 // 4 3 5\r
1149 //\r
1150 if ((Date->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
1151 //\r
1152 // At this point, only "<**:" in the optionstring. \r
1153 // Clean the day's ** field, after clean, the format is "< :"\r
1154 //\r
1155 SetUnicodeMem (&OptionString[1], 2, L' ');\r
1156 } else if ((Date->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
1157 //\r
1158 // At this point, only "**:" in the optionstring. \r
1159 // Clean the month's "**" field, after clean, the format is " :"\r
1160 // \r
1161 SetUnicodeMem (&OptionString[0], 2, L' ');\r
1162 } else if ((Date->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
1163 //\r
1164 // At this point, only "****>" in the optionstring. \r
1165 // Clean the year's "****" field, after clean, the format is " >"\r
1166 // \r
1167 SetUnicodeMem (&OptionString[0], 4, L' ');\r
1168 }\r
1169 } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
1170 //\r
1171 // OptionString format is: <**: **: **>\r
1172 // |hour|minute|second|\r
1173 // 4 3 3\r
1174 //\r
1175 if ((Time->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
1176 //\r
1177 // At this point, only "<**:" in the optionstring. \r
1178 // Clean the hour's ** field, after clean, the format is "< :"\r
1179 //\r
1180 SetUnicodeMem (&OptionString[1], 2, L' ');\r
1181 } else if ((Time->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
1182 //\r
1183 // At this point, only "**:" in the optionstring. \r
1184 // Clean the minute's "**" field, after clean, the format is " :"\r
1185 // \r
1186 SetUnicodeMem (&OptionString[0], 2, L' ');\r
1187 } else if ((Time->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
1188 //\r
1189 // At this point, only "**>" in the optionstring. \r
1190 // Clean the second's "**" field, after clean, the format is " >"\r
1191 // \r
1192 SetUnicodeMem (&OptionString[0], 2, L' ');\r
1193 }\r
1194 }\r
1195}\r
1196\r
1197\r
1198/**\r
1199 Adjust Data and Time position accordingly.\r
1200 Data format : [01/02/2004] [11:22:33]\r
1201 Line number : 0 0 1 0 0 1\r
1202\r
1203 This is an internal function.\r
1204\r
1205 @param DirectionUp the up or down direction. False is down. True is\r
1206 up.\r
1207 @param CurrentPosition Current position. On return: Point to the last\r
1208 Option (Year or Second) if up; Point to the first\r
1209 Option (Month or Hour) if down.\r
1210\r
1211 @return Return line number to pad. It is possible that we stand on a zero-advance\r
1212 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
1213\r
1214**/\r
1215UINTN\r
1216AdjustDateAndTimePosition (\r
1217 IN BOOLEAN DirectionUp,\r
1218 IN OUT LIST_ENTRY **CurrentPosition\r
1219 )\r
1220{\r
1221 UINTN Count;\r
1222 LIST_ENTRY *NewPosition;\r
1223 UI_MENU_OPTION *MenuOption;\r
1224 UINTN PadLineNumber;\r
1225\r
1226 PadLineNumber = 0;\r
1227 NewPosition = *CurrentPosition;\r
1228 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
1229\r
1230 if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) ||\r
1231 (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {\r
1232 //\r
1233 // Calculate the distance from current position to the last Date/Time MenuOption\r
1234 //\r
1235 Count = 0;\r
1236 while (MenuOption->Skip == 0) {\r
1237 Count++;\r
1238 NewPosition = NewPosition->ForwardLink;\r
1239 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
1240 PadLineNumber = 1;\r
1241 }\r
1242\r
1243 NewPosition = *CurrentPosition;\r
1244 if (DirectionUp) {\r
1245 //\r
1246 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended\r
1247 // to be one that back to the previous set of MenuOptions, we need to advance to the first\r
1248 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate\r
1249 // checking can be done.\r
1250 //\r
1251 while (Count++ < 2) {\r
1252 NewPosition = NewPosition->BackLink;\r
1253 }\r
1254 } else {\r
1255 //\r
1256 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended\r
1257 // to be one that progresses to the next set of MenuOptions, we need to advance to the last\r
1258 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate\r
1259 // checking can be done.\r
1260 //\r
1261 while (Count-- > 0) {\r
1262 NewPosition = NewPosition->ForwardLink;\r
1263 }\r
1264 }\r
1265\r
1266 *CurrentPosition = NewPosition;\r
1267 }\r
1268\r
1269 return PadLineNumber;\r
1270}\r
1271\r
1272/**\r
1273 Get step info from numeric opcode.\r
1274 \r
1275 @param[in] OpCode The input numeric op code.\r
1276\r
1277 @return step info for this opcode.\r
1278**/\r
1279UINT64\r
1280GetFieldFromNum (\r
1281 IN EFI_IFR_OP_HEADER *OpCode\r
1282 )\r
1283{\r
1284 EFI_IFR_NUMERIC *NumericOp;\r
1285 UINT64 Step;\r
1286\r
1287 NumericOp = (EFI_IFR_NUMERIC *) OpCode;\r
1288 \r
1289 switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {\r
1290 case EFI_IFR_NUMERIC_SIZE_1:\r
1291 Step = NumericOp->data.u8.Step;\r
1292 break;\r
1293 \r
1294 case EFI_IFR_NUMERIC_SIZE_2:\r
1295 Step = NumericOp->data.u16.Step;\r
1296 break;\r
1297 \r
1298 case EFI_IFR_NUMERIC_SIZE_4:\r
1299 Step = NumericOp->data.u32.Step;\r
1300 break;\r
1301 \r
1302 case EFI_IFR_NUMERIC_SIZE_8:\r
1303 Step = NumericOp->data.u64.Step;\r
1304 break;\r
1305 \r
1306 default:\r
1307 Step = 0;\r
1308 break;\r
1309 }\r
1310\r
1311 return Step;\r
1312}\r
1313\r
1314/**\r
1315 Find the registered HotKey based on KeyData.\r
1316 \r
1317 @param[in] KeyData A pointer to a buffer that describes the keystroke\r
1318 information for the hot key.\r
1319\r
1320 @return The registered HotKey context. If no found, NULL will return.\r
1321**/\r
1322BROWSER_HOT_KEY *\r
1323GetHotKeyFromRegisterList (\r
1324 IN EFI_INPUT_KEY *KeyData\r
1325 )\r
1326{\r
1327 LIST_ENTRY *Link;\r
1328 BROWSER_HOT_KEY *HotKey;\r
1329\r
1330 Link = GetFirstNode (&gFormData->HotKeyListHead);\r
1331 while (!IsNull (&gFormData->HotKeyListHead, Link)) {\r
1332 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
1333 \r
1334 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {\r
1335 return HotKey;\r
1336 }\r
1337\r
1338 Link = GetNextNode (&gFormData->HotKeyListHead, Link);\r
1339 }\r
1340 \r
1341 return NULL;\r
1342}\r
1343\r
1344\r
1345/**\r
1346 Determine if the menu is the last menu that can be selected.\r
1347\r
1348 This is an internal function.\r
1349\r
1350 @param Direction The scroll direction. False is down. True is up.\r
1351 @param CurrentPos The current focus.\r
1352\r
1353 @return FALSE -- the menu isn't the last menu that can be selected.\r
1354 @return TRUE -- the menu is the last menu that can be selected.\r
1355\r
1356**/\r
1357BOOLEAN\r
1358ValueIsScroll (\r
1359 IN BOOLEAN Direction,\r
1360 IN LIST_ENTRY *CurrentPos\r
1361 )\r
1362{\r
1363 LIST_ENTRY *Temp;\r
1364\r
1365 Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
1366\r
1367 if (Temp == &gMenuOption) {\r
1368 return TRUE;\r
1369 }\r
1370\r
1371 return FALSE;\r
1372}\r
1373\r
1374/**\r
1375 Wait for a given event to fire, or for an optional timeout to expire.\r
1376\r
1377 @param Event The event to wait for\r
1378\r
1379 @retval UI_EVENT_TYPE The type of the event which is trigged.\r
1380\r
1381**/\r
1382UI_EVENT_TYPE\r
1383UiWaitForEvent (\r
1384 IN EFI_EVENT Event\r
1385 )\r
1386{\r
1387 EFI_STATUS Status;\r
1388 UINTN Index;\r
1389 UINTN EventNum;\r
1390 UINT64 Timeout;\r
1391 EFI_EVENT TimerEvent;\r
1392 EFI_EVENT WaitList[3];\r
1393 UI_EVENT_TYPE EventType;\r
1394\r
1395 TimerEvent = NULL;\r
1396 Timeout = FormExitTimeout(gFormData);\r
1397\r
1398 if (Timeout != 0) {\r
1399 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
1400\r
1401 //\r
1402 // Set the timer event\r
1403 //\r
1404 gBS->SetTimer (\r
1405 TimerEvent,\r
1406 TimerRelative,\r
1407 Timeout\r
1408 );\r
1409 }\r
1410 \r
1411 WaitList[0] = Event;\r
1412 EventNum = 1;\r
1413 if (gFormData->FormRefreshEvent != NULL) {\r
1414 WaitList[EventNum] = gFormData->FormRefreshEvent;\r
1415 EventNum ++;\r
1416 } \r
1417\r
1418 if (Timeout != 0) {\r
1419 WaitList[EventNum] = TimerEvent;\r
1420 EventNum ++;\r
1421 }\r
1422\r
1423 Status = gBS->WaitForEvent (EventNum, WaitList, &Index);\r
1424 ASSERT_EFI_ERROR (Status);\r
1425\r
1426 switch (Index) {\r
1427 case 0:\r
1428 EventType = UIEventKey;\r
1429 break;\r
1430\r
1431 case 1:\r
1432 if (gFormData->FormRefreshEvent != NULL) {\r
1433 EventType = UIEventDriver;\r
1434 } else {\r
1435 ASSERT (Timeout != 0 && EventNum == 2);\r
1436 EventType = UIEventTimeOut;\r
1437 }\r
1438 break;\r
1439\r
1440 default:\r
1441 ASSERT (Index == 2 && EventNum == 3);\r
1442 EventType = UIEventTimeOut;\r
1443 break;\r
1444 }\r
1445\r
1446 if (Timeout != 0) {\r
1447 gBS->CloseEvent (TimerEvent);\r
1448 }\r
1449 \r
1450 return EventType;\r
1451}\r
1452\r
1453/**\r
1454 Get question id info from the input opcode header.\r
1455\r
1456 @param OpCode The input opcode header pointer.\r
1457\r
1458 @retval The question id for this opcode.\r
1459\r
1460**/\r
1461EFI_QUESTION_ID\r
1462GetQuestionIdInfo (\r
1463 IN EFI_IFR_OP_HEADER *OpCode\r
1464 )\r
1465{\r
1466 EFI_IFR_QUESTION_HEADER *QuestionHeader;\r
1467\r
1468 if (OpCode->Length < sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER)) {\r
1469 return 0;\r
1470 }\r
1471\r
1472 QuestionHeader = (EFI_IFR_QUESTION_HEADER *)((UINT8 *) OpCode + sizeof(EFI_IFR_OP_HEADER));\r
1473\r
1474 return QuestionHeader->QuestionId;\r
1475}\r
1476\r
ab369468
ED
1477\r
1478/**\r
1479 Find the top of screen menu base on the current menu.\r
1480\r
1481 @param CurPos Current input menu.\r
1482 @param Rows Totol screen rows.\r
1483 @param SkipValue SkipValue for this new form.\r
1484\r
1485 @retval TopOfScreen Top of screen menu for the new form.\r
1486\r
1487**/\r
1488LIST_ENTRY *\r
1489FindTopOfScreenMenu (\r
1490 IN LIST_ENTRY *CurPos,\r
1491 IN UINTN Rows,\r
1492 OUT UINTN *SkipValue\r
1493 )\r
1494{\r
1495 LIST_ENTRY *Link;\r
1496 LIST_ENTRY *TopOfScreen;\r
1497 UI_MENU_OPTION *PreviousMenuOption;\r
1498\r
1499 Link = CurPos;\r
1500 PreviousMenuOption = NULL;\r
1501\r
1502 while (Link->BackLink != &gMenuOption) {\r
1503 Link = Link->BackLink;\r
1504 PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
1505 if (PreviousMenuOption->Row == 0) {\r
1506 UpdateOptionSkipLines (PreviousMenuOption);\r
1507 }\r
1508 if (Rows <= PreviousMenuOption->Skip) {\r
1509 break;\r
1510 }\r
1511 Rows = Rows - PreviousMenuOption->Skip;\r
1512 }\r
1513\r
1514 if (Link->BackLink == &gMenuOption) {\r
1515 TopOfScreen = gMenuOption.ForwardLink;\r
1516 if (PreviousMenuOption != NULL && Rows < PreviousMenuOption->Skip) {\r
1517 *SkipValue = PreviousMenuOption->Skip - Rows;\r
1518 } else {\r
1519 *SkipValue = 0;\r
1520 }\r
1521 } else {\r
1522 TopOfScreen = Link;\r
1523 *SkipValue = PreviousMenuOption->Skip - Rows;\r
1524 }\r
1525\r
1526 return TopOfScreen;\r
1527}\r
1528\r
42645c3d
ED
1529/**\r
1530 Get the index info for this opcode.\r
1531\r
1532 @param OpCode The input opcode for the statement.\r
1533\r
1534 @retval The index of this statement.\r
1535\r
1536**/\r
1537UINTN\r
1538GetIndexInfoForOpcode (\r
1539 IN EFI_IFR_OP_HEADER *OpCode\r
1540 )\r
1541{\r
1542 LIST_ENTRY *NewPos;\r
1543 UI_MENU_OPTION *MenuOption;\r
1544 UINTN Index;\r
1545\r
1546 NewPos = gMenuOption.ForwardLink;\r
1547 Index = 0;\r
1548\r
1549 for (NewPos = gMenuOption.ForwardLink; NewPos != &gMenuOption; NewPos = NewPos->ForwardLink){\r
1550 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
1551\r
1552 if (CompareMem (MenuOption->ThisTag->OpCode, OpCode, OpCode->Length) == 0) {\r
1553 if (MenuOption->ThisTag->OpCode == OpCode) {\r
1554 return Index;\r
1555 }\r
1556\r
1557 Index ++;\r
1558 }\r
1559 }\r
1560\r
1561 return Index;\r
1562}\r
1563\r
1564/**\r
1565 Is this the saved highlight statement.\r
1566\r
1567 @param HighLightedStatement The input highlight statement.\r
1568\r
1569 @retval TRUE This is the highlight statement.\r
1570 @retval FALSE This is not the highlight statement.\r
1571\r
1572**/\r
1573BOOLEAN \r
1574IsSavedHighlightStatement (\r
1575 IN FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement\r
1576 )\r
1577{\r
1578 if ((gFormData->HiiHandle == gHighligthMenuInfo.HiiHandle) &&\r
1579 (gFormData->FormId == gHighligthMenuInfo.FormId)) {\r
1580 if (gHighligthMenuInfo.HLTQuestionId != 0) {\r
2e097165 1581 return (BOOLEAN) (gHighligthMenuInfo.HLTQuestionId == GetQuestionIdInfo (HighLightedStatement->OpCode));\r
42645c3d
ED
1582 } else {\r
1583 if (CompareMem (gHighligthMenuInfo.HLTOpCode, HighLightedStatement->OpCode, gHighligthMenuInfo.HLTOpCode->Length) == 0) {\r
1584 if (gHighligthMenuInfo.HLTIndex == 0 || gHighligthMenuInfo.HLTIndex == GetIndexInfoForOpcode(HighLightedStatement->OpCode)) {\r
1585 return TRUE;\r
1586 } else {\r
1587 return FALSE;\r
1588 }\r
1589 }\r
1590 }\r
1591 }\r
1592\r
1593 return FALSE;\r
1594}\r
1595\r
1596/**\r
1597 Is this the highlight menu.\r
1598\r
1599 @param MenuOption The input Menu option.\r
1600\r
1601 @retval TRUE This is the highlight menu option.\r
1602 @retval FALSE This is not the highlight menu option.\r
1603\r
1604**/\r
1605BOOLEAN\r
1606IsHighLightMenuOption (\r
1607 IN UI_MENU_OPTION *MenuOption\r
1608 )\r
1609{\r
1610 if (gHighligthMenuInfo.HLTQuestionId != 0) {\r
1611 if (GetQuestionIdInfo(MenuOption->ThisTag->OpCode) == gHighligthMenuInfo.HLTQuestionId) {\r
2e097165 1612 return (BOOLEAN) (MenuOption->Sequence == gHighligthMenuInfo.HLTSequence);\r
42645c3d
ED
1613 }\r
1614 } else {\r
1615 if(CompareMem (gHighligthMenuInfo.HLTOpCode, MenuOption->ThisTag->OpCode, gHighligthMenuInfo.HLTOpCode->Length) == 0) {\r
1616 if (gHighligthMenuInfo.HLTIndex == 0 || gHighligthMenuInfo.HLTIndex == GetIndexInfoForOpcode(MenuOption->ThisTag->OpCode)) {\r
2e097165 1617 return (BOOLEAN) (MenuOption->Sequence == gHighligthMenuInfo.HLTSequence);\r
42645c3d
ED
1618 } else {\r
1619 return FALSE;\r
1620 }\r
1621 }\r
1622 }\r
1623\r
1624 return FALSE;\r
1625}\r
1626\r
1627/**\r
1628 Find the highlight menu.\r
1629\r
1630 If the input is NULL, base on the record highlight info in\r
1631 gHighligthMenuInfo to find the last highlight menu.\r
1632\r
1633 @param HighLightedStatement The input highlight statement.\r
1634\r
1635 @retval The highlight menu index.\r
1636\r
1637**/\r
1638LIST_ENTRY *\r
1639FindHighLightMenuOption (\r
1640 IN FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement\r
1641 )\r
1642{\r
1643 LIST_ENTRY *NewPos;\r
1644 UI_MENU_OPTION *MenuOption;\r
1645\r
1646 NewPos = gMenuOption.ForwardLink;\r
1647 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
1648\r
1649 if (HighLightedStatement != NULL) {\r
1650 while (MenuOption->ThisTag != HighLightedStatement) {\r
1651 NewPos = NewPos->ForwardLink;\r
1652 if (NewPos == &gMenuOption) {\r
1653 //\r
1654 // Not Found it, break\r
1655 //\r
1656 break;\r
1657 }\r
1658 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
1659 }\r
1660\r
1661 //\r
1662 // Must find the highlight statement.\r
1663 //\r
1664 ASSERT (NewPos != &gMenuOption);\r
1665\r
1666 } else {\r
1667 while (!IsHighLightMenuOption (MenuOption)) {\r
1668 NewPos = NewPos->ForwardLink;\r
1669 if (NewPos == &gMenuOption) {\r
1670 //\r
1671 // Not Found it, break\r
1672 //\r
1673 break;\r
1674 }\r
1675 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
1676 }\r
1677\r
1678 //\r
1679 // Highlight statement has disappear (suppressed/disableed)\r
1680 //\r
1681 if (NewPos == &gMenuOption) {\r
1682 NewPos = NULL;\r
1683 }\r
1684 }\r
1685\r
1686 return NewPos;\r
1687}\r
1688\r
1689/**\r
1690 Is this the Top of screen menu.\r
1691\r
1692 @param MenuOption The input Menu option.\r
1693\r
1694 @retval TRUE This is the Top of screen menu option.\r
1695 @retval FALSE This is not the Top of screen menu option.\r
1696\r
1697**/\r
1698BOOLEAN\r
1699IsTopOfScreeMenuOption (\r
1700 IN UI_MENU_OPTION *MenuOption\r
1701 )\r
1702{\r
1703 if (gHighligthMenuInfo.TOSQuestionId != 0) {\r
2e097165 1704 return (BOOLEAN) (GetQuestionIdInfo(MenuOption->ThisTag->OpCode) == gHighligthMenuInfo.TOSQuestionId);\r
42645c3d
ED
1705 } \r
1706\r
1707 if(CompareMem (gHighligthMenuInfo.TOSOpCode, MenuOption->ThisTag->OpCode, gHighligthMenuInfo.TOSOpCode->Length) == 0) {\r
1708 if (gHighligthMenuInfo.TOSIndex == 0 || gHighligthMenuInfo.TOSIndex == GetIndexInfoForOpcode(MenuOption->ThisTag->OpCode)) {\r
1709 return TRUE;\r
1710 } else {\r
1711 return FALSE;\r
1712 }\r
1713 }\r
1714\r
1715 return FALSE;\r
1716}\r
1717\r
1718/**\r
1719 Find the Top of screen menu.\r
1720\r
1721 If the input is NULL, base on the record highlight info in\r
1722 gHighligthMenuInfo to find the last highlight menu.\r
1723\r
1724 @param HighLightedStatement The input highlight statement.\r
1725\r
1726 @retval The highlight menu index.\r
1727\r
1728**/\r
1729LIST_ENTRY *\r
1730FindTopOfScreenMenuOption (\r
1731 VOID\r
1732 )\r
1733{\r
1734 LIST_ENTRY *NewPos;\r
1735 UI_MENU_OPTION *MenuOption;\r
1736\r
1737 NewPos = gMenuOption.ForwardLink;\r
1738 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
1739\r
1740 while (!IsTopOfScreeMenuOption(MenuOption)) {\r
1741 NewPos = NewPos->ForwardLink;\r
1742 if (NewPos == &gMenuOption) {\r
1743 //\r
1744 // Not Found it, break\r
1745 //\r
1746 break;\r
1747 }\r
1748 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
1749 }\r
1750\r
1751 //\r
1752 // Last time top of screen menu has disappeared.\r
1753 //\r
1754 if (NewPos == &gMenuOption) {\r
1755 NewPos = NULL;\r
1756 }\r
1757\r
1758 return NewPos;\r
1759}\r
1760\r
7c6c064c
ED
1761/**\r
1762 Find the first menu which will be show at the top.\r
1763\r
1764 @param FormData The data info for this form.\r
1765 @param TopOfScreen The link_entry pointer to top menu.\r
1766 @param HighlightMenu The menu which will be highlight.\r
1767 @param SkipValue The skip value for the top menu.\r
1768\r
1769**/\r
1770VOID\r
1771FindTopMenu (\r
1772 IN FORM_DISPLAY_ENGINE_FORM *FormData,\r
1773 OUT LIST_ENTRY **TopOfScreen,\r
1774 OUT LIST_ENTRY **HighlightMenu,\r
ab369468 1775 OUT UINTN *SkipValue\r
7c6c064c
ED
1776 )\r
1777{\r
7c6c064c
ED
1778 UINTN TopRow;\r
1779 UINTN BottomRow;\r
42645c3d 1780 UI_MENU_OPTION *MenuOption;\r
ab369468 1781 UINTN TmpValue;\r
7c6c064c
ED
1782\r
1783 TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;\r
1784 BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;\r
1785\r
42645c3d
ED
1786 if (gMisMatch) {\r
1787 //\r
1788 // Reenter caused by option mismatch or auto exit caused by refresh form(refresh interval/guid), \r
1789 // base on the record highlight info to find the highlight menu.\r
1790 //\r
1791 ASSERT (gFormData->HiiHandle == gHighligthMenuInfo.HiiHandle &&\r
1792 gFormData->FormId == gHighligthMenuInfo.FormId);\r
7c6c064c 1793\r
42645c3d
ED
1794 *HighlightMenu = FindHighLightMenuOption(NULL);\r
1795 if (*HighlightMenu != NULL) {\r
7c6c064c 1796 //\r
42645c3d 1797 // Update skip info for this highlight menu.\r
7c6c064c 1798 //\r
42645c3d
ED
1799 MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);\r
1800 UpdateOptionSkipLines (MenuOption);\r
7c6c064c 1801\r
42645c3d
ED
1802 //\r
1803 // Found the last time highlight menu.\r
1804 //\r
1805 *TopOfScreen = FindTopOfScreenMenuOption();\r
1806 if (*TopOfScreen != NULL) {\r
1807 //\r
1808 // Found the last time selectable top of screen menu.\r
1809 //\r
1810 AdjustDateAndTimePosition(TRUE, TopOfScreen);\r
1811 MenuOption = MENU_OPTION_FROM_LINK (*TopOfScreen);\r
1812 UpdateOptionSkipLines (MenuOption);\r
7c6c064c 1813\r
42645c3d
ED
1814 *SkipValue = gHighligthMenuInfo.SkipValue;\r
1815 } else {\r
336c8e11 1816 //\r
42645c3d
ED
1817 // Not found last time top of screen menu, so base on current highlight menu\r
1818 // to find the new top of screen menu.\r
1819 // Make the current highlight menu at the bottom of the form to calculate the\r
1820 // top of screen menu.\r
336c8e11 1821 //\r
42645c3d
ED
1822 if (MenuOption->Skip >= BottomRow - TopRow) {\r
1823 *TopOfScreen = *HighlightMenu;\r
1824 TmpValue = 0;\r
1825 } else {\r
1826 *TopOfScreen = FindTopOfScreenMenu(*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);\r
1827 }\r
1828\r
1829 *SkipValue = TmpValue;\r
336c8e11 1830 }\r
42645c3d
ED
1831 } else {\r
1832 //\r
1833 // Last time highlight menu has disappear, find the first highlightable menu as the defalut one.\r
1834 //\r
1835 *HighlightMenu = gMenuOption.ForwardLink;\r
1836 if (!IsListEmpty (&gMenuOption)) {\r
1837 MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow, TRUE);\r
1838 }\r
1839 *TopOfScreen = gMenuOption.ForwardLink;\r
1840 *SkipValue = 0;\r
1841 }\r
1842\r
1843 gMisMatch = FALSE;\r
1844 } else if (FormData->HighLightedStatement != NULL) {\r
1845 if (IsSavedHighlightStatement (FormData->HighLightedStatement)) {\r
1846 //\r
1847 // Input highlight menu is same as last time highlight menu.\r
1848 // Base on last time highlight menu to set the top of screen menu and highlight menu.\r
1849 //\r
1850 *HighlightMenu = FindHighLightMenuOption(NULL);\r
1851 ASSERT (*HighlightMenu != NULL);\r
1852\r
1853 //\r
1854 // Update skip info for this highlight menu.\r
1855 //\r
1856 MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);\r
1857 UpdateOptionSkipLines (MenuOption);\r
1858 \r
1859 *TopOfScreen = FindTopOfScreenMenuOption();\r
1860 if (*TopOfScreen == NULL) {\r
336c8e11 1861 //\r
42645c3d
ED
1862 // Not found last time top of screen menu, so base on current highlight menu\r
1863 // to find the new top of screen menu.\r
1864 // Make the current highlight menu at the bottom of the form to calculate the\r
1865 // top of screen menu.\r
336c8e11 1866 //\r
42645c3d
ED
1867 if (MenuOption->Skip >= BottomRow - TopRow) {\r
1868 *TopOfScreen = *HighlightMenu;\r
1869 TmpValue = 0;\r
1870 } else {\r
1871 *TopOfScreen = FindTopOfScreenMenu(*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);\r
1872 }\r
1873\r
1874 *SkipValue = TmpValue;\r
1875 } else {\r
1876 AdjustDateAndTimePosition(TRUE, TopOfScreen);\r
1877 MenuOption = MENU_OPTION_FROM_LINK (*TopOfScreen);\r
1878 UpdateOptionSkipLines (MenuOption);\r
1879\r
1880 *SkipValue = gHighligthMenuInfo.SkipValue;\r
336c8e11 1881 }\r
42645c3d
ED
1882 AdjustDateAndTimePosition(TRUE, TopOfScreen);\r
1883 } else {\r
1884 //\r
1885 // Input highlight menu is not save as last time highlight menu.\r
1886 //\r
1887 *HighlightMenu = FindHighLightMenuOption(FormData->HighLightedStatement);\r
1888 MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);\r
1889 UpdateOptionSkipLines (MenuOption);\r
7c6c064c 1890\r
42645c3d
ED
1891 //\r
1892 // Make the current highlight menu at the bottom of the form to calculate the\r
1893 // top of screen menu.\r
1894 //\r
1895 if (MenuOption->Skip >= BottomRow - TopRow) {\r
1896 *TopOfScreen = *HighlightMenu;\r
1897 TmpValue = 0;\r
1898 } else {\r
1899 *TopOfScreen = FindTopOfScreenMenu(*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);\r
1900 }\r
1901\r
1902 *SkipValue = TmpValue;\r
1903 }\r
1904 AdjustDateAndTimePosition(TRUE, TopOfScreen);\r
7c6c064c 1905 } else {\r
42645c3d
ED
1906 //\r
1907 // If not has input highlight statement, just return the first one in this form.\r
1908 //\r
1909 *TopOfScreen = gMenuOption.ForwardLink;\r
1910 *HighlightMenu = gMenuOption.ForwardLink;\r
1911 if (!IsListEmpty (&gMenuOption)) {\r
1912 MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow, TRUE);\r
1913 }\r
1914 *SkipValue = 0;\r
7c6c064c 1915 }\r
ab2cf8ea
ED
1916\r
1917 //\r
1918 // First enter to show the menu, update highlight info.\r
1919 //\r
1920 UpdateHighlightMenuInfo (*HighlightMenu, *TopOfScreen, *SkipValue);\r
7c6c064c
ED
1921}\r
1922\r
af047db7 1923/**\r
42645c3d 1924 Record the highlight menu and top of screen menu info.\r
af047db7 1925\r
42645c3d
ED
1926 @param Highlight The menu opton which is highlight.\r
1927 @param TopOfScreen The menu opton which is at the top of the form.\r
1928 @param SkipValue The skip line info for the top of screen menu.\r
af047db7
ED
1929\r
1930**/\r
1931VOID\r
1932UpdateHighlightMenuInfo (\r
42645c3d
ED
1933 IN LIST_ENTRY *Highlight,\r
1934 IN LIST_ENTRY *TopOfScreen,\r
1935 IN UINTN SkipValue\r
af047db7
ED
1936 )\r
1937{\r
42645c3d 1938 UI_MENU_OPTION *MenuOption;\r
af047db7
ED
1939 FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
1940\r
42645c3d
ED
1941 gHighligthMenuInfo.HiiHandle = gFormData->HiiHandle;\r
1942 gHighligthMenuInfo.FormId = gFormData->FormId;\r
1943 gHighligthMenuInfo.SkipValue = (UINT16)SkipValue;\r
af047db7 1944\r
42645c3d
ED
1945 if (!IsListEmpty (&gMenuOption)) {\r
1946 MenuOption = MENU_OPTION_FROM_LINK (Highlight);\r
1947 Statement = MenuOption->ThisTag;\r
af047db7 1948\r
42645c3d 1949 gUserInput->SelectedStatement = Statement;\r
336c8e11 1950\r
42645c3d
ED
1951 gHighligthMenuInfo.HLTSequence = MenuOption->Sequence;\r
1952 gHighligthMenuInfo.HLTQuestionId = GetQuestionIdInfo(Statement->OpCode);\r
1953 if (gHighligthMenuInfo.HLTQuestionId == 0) {\r
1954 //\r
1955 // if question id == 0, save the opcode buffer..\r
1956 //\r
1957 if (gHighligthMenuInfo.HLTOpCode != NULL) {\r
1958 FreePool (gHighligthMenuInfo.HLTOpCode);\r
336c8e11 1959 }\r
42645c3d
ED
1960 gHighligthMenuInfo.HLTOpCode = AllocateCopyPool (Statement->OpCode->Length, Statement->OpCode);\r
1961 ASSERT (gHighligthMenuInfo.HLTOpCode != NULL);\r
1962\r
1963 gHighligthMenuInfo.HLTIndex = GetIndexInfoForOpcode(Statement->OpCode);\r
1964 }\r
1965\r
1966 MenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
1967 Statement = MenuOption->ThisTag;\r
1968\r
1969 gHighligthMenuInfo.TOSQuestionId = GetQuestionIdInfo(Statement->OpCode);\r
1970 if (gHighligthMenuInfo.TOSQuestionId == 0) {\r
1971 //\r
1972 // if question id == 0, save the opcode buffer..\r
1973 //\r
1974 if (gHighligthMenuInfo.TOSOpCode != NULL) {\r
1975 FreePool (gHighligthMenuInfo.TOSOpCode);\r
1976 }\r
1977 gHighligthMenuInfo.TOSOpCode = AllocateCopyPool (Statement->OpCode->Length, Statement->OpCode);\r
1978 ASSERT (gHighligthMenuInfo.TOSOpCode != NULL);\r
1979\r
1980 gHighligthMenuInfo.TOSIndex = GetIndexInfoForOpcode(Statement->OpCode);\r
336c8e11 1981 }\r
af047db7 1982 } else {\r
42645c3d
ED
1983 gUserInput->SelectedStatement = NULL;\r
1984\r
1985 gHighligthMenuInfo.HLTSequence = 0;\r
1986 gHighligthMenuInfo.HLTQuestionId = 0;\r
1987 if (gHighligthMenuInfo.HLTOpCode != NULL) {\r
1988 FreePool (gHighligthMenuInfo.HLTOpCode);\r
336c8e11 1989 }\r
42645c3d
ED
1990 gHighligthMenuInfo.HLTOpCode = NULL;\r
1991 gHighligthMenuInfo.HLTIndex = 0;\r
af047db7 1992\r
42645c3d
ED
1993 gHighligthMenuInfo.TOSQuestionId = 0;\r
1994 if (gHighligthMenuInfo.TOSOpCode != NULL) {\r
1995 FreePool (gHighligthMenuInfo.TOSOpCode);\r
1996 }\r
1997 gHighligthMenuInfo.TOSOpCode = NULL;\r
1998 gHighligthMenuInfo.TOSIndex = 0;\r
1999 }\r
af047db7
ED
2000}\r
2001\r
2002/**\r
2003 Update attribut for this menu.\r
2004\r
2005 @param MenuOption The menu opton which this attribut used to.\r
2006 @param Highlight Whether this menu will be highlight.\r
2007\r
2008**/\r
2009VOID\r
2010SetDisplayAttribute (\r
2011 IN UI_MENU_OPTION *MenuOption,\r
2012 IN BOOLEAN Highlight\r
2013 )\r
2014{\r
2015 FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
2016 \r
2017 Statement = MenuOption->ThisTag;\r
2018\r
2019 if (Highlight) {\r
2020 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
2021 return;\r
2022 }\r
2023\r
2024 if (MenuOption->GrayOut) {\r
2025 gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());\r
2026 } else {\r
2027 if (Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {\r
2028 gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());\r
2029 } else {\r
2030 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
2031 }\r
2032 }\r
2033}\r
2034\r
2035/**\r
2036 Print string for this menu option.\r
2037\r
2038 @param MenuOption The menu opton which this attribut used to.\r
2039 @param Col The column that this string will be print at.\r
2040 @param Row The row that this string will be print at.\r
2041 @param String The string which need to print.\r
2042 @param Width The width need to print, if string is less than the\r
2043 width, the block space will be used.\r
2044 @param Highlight Whether this menu will be highlight.\r
2045\r
2046**/\r
2047VOID\r
2048DisplayMenuString (\r
2049 IN UI_MENU_OPTION *MenuOption,\r
2050 IN UINTN Col,\r
2051 IN UINTN Row,\r
2052 IN CHAR16 *String,\r
2053 IN UINTN Width,\r
2054 IN BOOLEAN Highlight\r
2055 )\r
2056{\r
2057 UINTN Length;\r
2058\r
2059 //\r
2060 // Print string with normal color.\r
2061 //\r
2062 if (!Highlight) {\r
2063 PrintStringAtWithWidth (Col, Row, String, Width);\r
2064 return;\r
2065 }\r
2066 \r
2067 //\r
2068 // Print the highlight menu string.\r
2069 // First print the highlight string.\r
2070 // \r
2071 SetDisplayAttribute(MenuOption, TRUE);\r
2072 Length = PrintStringAt (Col, Row, String);\r
2073\r
2074 //\r
2075 // Second, clean the empty after the string.\r
2076 //\r
2077 SetDisplayAttribute(MenuOption, FALSE);\r
2078 PrintStringAtWithWidth (Col + Length, Row, L"", Width - Length);\r
2079}\r
2080\r
28401a65
ED
2081/**\r
2082 Check whether this menu can has option string.\r
2083\r
2084 @param MenuOption The menu opton which this attribut used to.\r
2085\r
2086 @retval TRUE This menu option can have option string.\r
2087 @retval FALSE This menu option can't have option string.\r
2088\r
2089**/\r
2090BOOLEAN \r
2091HasOptionString (\r
2092 IN UI_MENU_OPTION *MenuOption\r
2093 )\r
2094{\r
2095 FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
2096 CHAR16 *String;\r
2097 UINTN Size;\r
2098 EFI_IFR_TEXT *TestOp;\r
2099\r
2100 Size = 0;\r
2101 Statement = MenuOption->ThisTag;\r
2102\r
2103 //\r
2104 // See if the second text parameter is really NULL\r
2105 //\r
2106 if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {\r
2107 TestOp = (EFI_IFR_TEXT *) Statement->OpCode;\r
2108 if (TestOp->TextTwo != 0) {\r
2109 String = GetToken (TestOp->TextTwo, gFormData->HiiHandle);\r
2110 Size = StrLen (String);\r
2111 FreePool (String);\r
2112 }\r
2113 }\r
2114\r
2115 if ((Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||\r
2116 (Statement->OpCode->OpCode == EFI_IFR_REF_OP) ||\r
2117 (Statement->OpCode->OpCode == EFI_IFR_PASSWORD_OP) ||\r
2118 (Statement->OpCode->OpCode == EFI_IFR_ACTION_OP) ||\r
2119 (Statement->OpCode->OpCode == EFI_IFR_RESET_BUTTON_OP) ||\r
2120 //\r
2121 // Allow a wide display if text op-code and no secondary text op-code\r
2122 //\r
2123 ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))\r
2124 ) {\r
2125\r
2126 return FALSE;\r
2127 }\r
2128\r
2129 return TRUE;\r
2130}\r
2131\r
23c7d425
ED
2132/**\r
2133 Double confirm with user about the action.\r
2134\r
2135 @param Action The user input action.\r
2136\r
2137 @retval TRUE User confirm with the input or not need user confirm.\r
2138 @retval FALSE User want ignore this input.\r
2139\r
2140**/\r
2141BOOLEAN\r
2142FxConfirmPopup (\r
2143 IN UINT32 Action\r
2144 )\r
2145{\r
2146 EFI_INPUT_KEY Key;\r
2147 CHAR16 *CfmStr;\r
2148 UINTN CfmStrLen;\r
2149 UINT32 CheckFlags;\r
2150 BOOLEAN RetVal;\r
2151 UINTN CatLen;\r
5ad66ec6 2152 UINTN MaxLen;\r
23c7d425
ED
2153\r
2154 CfmStrLen = 0;\r
2155 CatLen = StrLen (gConfirmMsgConnect);\r
2156\r
2157 //\r
2158 // Below action need extra popup dialog to confirm.\r
2159 // \r
2160 CheckFlags = BROWSER_ACTION_DISCARD | \r
2161 BROWSER_ACTION_DEFAULT |\r
2162 BROWSER_ACTION_SUBMIT |\r
2163 BROWSER_ACTION_RESET |\r
2164 BROWSER_ACTION_EXIT;\r
2165\r
2166 //\r
2167 // Not need to confirm with user, just return TRUE.\r
2168 //\r
2169 if ((Action & CheckFlags) == 0) {\r
2170 return TRUE;\r
2171 }\r
2172\r
2173 if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {\r
2174 CfmStrLen += StrLen (gConfirmDiscardMsg);\r
2175 } \r
2176\r
2177 if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
2178 if (CfmStrLen != 0) {\r
2179 CfmStrLen += CatLen;\r
2180 } \r
2181\r
2182 CfmStrLen += StrLen (gConfirmDefaultMsg);\r
2183 }\r
2184\r
2185 if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {\r
2186 if (CfmStrLen != 0) {\r
2187 CfmStrLen += CatLen;\r
2188 } \r
2189\r
2190 CfmStrLen += StrLen (gConfirmSubmitMsg);\r
2191 }\r
2192\r
2193 if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {\r
2194 if (CfmStrLen != 0) {\r
2195 CfmStrLen += CatLen;\r
2196 } \r
2197\r
2198 CfmStrLen += StrLen (gConfirmResetMsg);\r
2199 }\r
2200\r
2201 if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {\r
2202 if (CfmStrLen != 0) {\r
2203 CfmStrLen += CatLen;\r
2204 } \r
2205\r
2206 CfmStrLen += StrLen (gConfirmExitMsg);\r
2207 }\r
2208\r
2209 //\r
2210 // Allocate buffer to save the string.\r
2211 // String + "?" + "\0"\r
2212 //\r
5ad66ec6
DB
2213 MaxLen = CfmStrLen + 1 + 1;\r
2214 CfmStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));\r
23c7d425
ED
2215 ASSERT (CfmStr != NULL);\r
2216\r
2217 if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {\r
5ad66ec6 2218 StrCpyS (CfmStr, MaxLen, gConfirmDiscardMsg);\r
23c7d425
ED
2219 }\r
2220\r
2221 if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
2222 if (CfmStr[0] != 0) {\r
5ad66ec6
DB
2223 StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);\r
2224 StrCatS (CfmStr, MaxLen, gConfirmDefaultMsg2nd);\r
23c7d425 2225 } else {\r
5ad66ec6 2226 StrCpyS (CfmStr, MaxLen, gConfirmDefaultMsg);\r
23c7d425
ED
2227 }\r
2228 }\r
2229\r
2230 if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {\r
2231 if (CfmStr[0] != 0) {\r
5ad66ec6
DB
2232 StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);\r
2233 StrCatS (CfmStr, MaxLen, gConfirmSubmitMsg2nd);\r
23c7d425 2234 } else {\r
5ad66ec6 2235 StrCpyS (CfmStr, MaxLen, gConfirmSubmitMsg);\r
23c7d425
ED
2236 }\r
2237 }\r
2238\r
2239 if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {\r
2240 if (CfmStr[0] != 0) {\r
5ad66ec6
DB
2241 StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);\r
2242 StrCatS (CfmStr, MaxLen, gConfirmResetMsg2nd);\r
23c7d425 2243 } else {\r
5ad66ec6 2244 StrCpyS (CfmStr, MaxLen, gConfirmResetMsg);\r
23c7d425
ED
2245 }\r
2246 }\r
2247\r
2248 if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {\r
2249 if (CfmStr[0] != 0) {\r
5ad66ec6
DB
2250 StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);\r
2251 StrCatS (CfmStr, MaxLen, gConfirmExitMsg2nd);\r
23c7d425 2252 } else {\r
5ad66ec6 2253 StrCpyS (CfmStr, MaxLen, gConfirmExitMsg);\r
23c7d425
ED
2254 }\r
2255 }\r
2256\r
5ad66ec6 2257 StrCatS (CfmStr, MaxLen, gConfirmMsgEnd);\r
23c7d425
ED
2258\r
2259 do {\r
2260 CreateDialog (&Key, gEmptyString, CfmStr, gConfirmOpt, gEmptyString, NULL);\r
2261 } while (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (gConfirmOptYes[0] | UPPER_LOWER_CASE_OFFSET)) &&\r
2262 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (gConfirmOptNo[0] | UPPER_LOWER_CASE_OFFSET)));\r
2263\r
2264 if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (gConfirmOptYes[0] | UPPER_LOWER_CASE_OFFSET)) {\r
2265 RetVal = TRUE;\r
2266 } else {\r
2267 RetVal = FALSE;\r
2268 }\r
2269\r
2270 FreePool (CfmStr);\r
2271\r
2272 return RetVal;\r
2273}\r
28401a65 2274\r
af047db7
ED
2275/**\r
2276 Print string for this menu option.\r
2277\r
2278 @param MenuOption The menu opton which this attribut used to.\r
2279 @param SkipWidth The skip width between the left to the start of the prompt.\r
2280 @param BeginCol The begin column for one menu.\r
2281 @param SkipLine The skip line for this menu. \r
2282 @param BottomRow The bottom row for this form.\r
2283 @param Highlight Whether this menu will be highlight.\r
f0c5095b 2284 @param UpdateCol Whether need to update the column info for Date/Time.\r
af047db7
ED
2285\r
2286 @retval EFI_SUCESSS Process the user selection success.\r
2287\r
2288**/\r
2289EFI_STATUS\r
2290DisplayOneMenu (\r
2291 IN UI_MENU_OPTION *MenuOption,\r
2292 IN UINTN SkipWidth,\r
2293 IN UINTN BeginCol,\r
2294 IN UINTN SkipLine,\r
2295 IN UINTN BottomRow,\r
f0c5095b
ED
2296 IN BOOLEAN Highlight,\r
2297 IN BOOLEAN UpdateCol\r
af047db7
ED
2298 )\r
2299{\r
2300 FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
2301 UINTN Index;\r
2302 UINT16 Width;\r
2303 UINT16 PromptWidth;\r
2304 CHAR16 *StringPtr;\r
2305 CHAR16 *OptionString;\r
2306 CHAR16 *OutputString;\r
af047db7
ED
2307 UINT16 GlyphWidth;\r
2308 UINTN Temp;\r
2309 UINTN Temp2;\r
2310 UINTN Temp3;\r
2311 EFI_STATUS Status;\r
2312 UINTN Row;\r
8c9c60b6 2313 BOOLEAN IsProcessingFirstRow;\r
af047db7
ED
2314 UINTN Col;\r
2315 UINTN PromptLineNum;\r
28401a65 2316 UINTN OptionLineNum;\r
af047db7 2317 CHAR16 AdjustValue;\r
28401a65 2318 UINTN MaxRow;\r
af047db7
ED
2319\r
2320 Statement = MenuOption->ThisTag;\r
af047db7
ED
2321 Temp = SkipLine;\r
2322 Temp2 = SkipLine;\r
2323 Temp3 = SkipLine;\r
28401a65
ED
2324 AdjustValue = 0;\r
2325 PromptLineNum = 0;\r
2326 OptionLineNum = 0;\r
2327 MaxRow = 0;\r
8c9c60b6 2328 IsProcessingFirstRow = TRUE;\r
af047db7
ED
2329\r
2330 //\r
2331 // Set default color.\r
2332 //\r
2333 SetDisplayAttribute (MenuOption, FALSE);\r
2334\r
2335 //\r
2336 // 1. Paint the option string.\r
2337 //\r
2338 Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);\r
2339 if (EFI_ERROR (Status)) {\r
2340 return Status;\r
2341 }\r
2342\r
2343 if (OptionString != NULL) {\r
2344 if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
2345 //\r
2346 // Adjust option string for date/time opcode.\r
2347 //\r
f0c5095b 2348 ProcessStringForDateTime(MenuOption, OptionString, UpdateCol);\r
af047db7
ED
2349 }\r
2350 \r
2351 Width = (UINT16) gOptionBlockWidth - 1;\r
28401a65 2352 Row = MenuOption->Row;\r
af047db7 2353 GlyphWidth = 1;\r
28401a65 2354 OptionLineNum = 0;\r
af047db7
ED
2355 \r
2356 for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
2357 if (((Temp2 == 0)) && (Row <= BottomRow)) {\r
2358 if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
2359 //\r
2360 // For date/time question, it has three menu options for this qustion.\r
2361 // The first/second menu options with the skip value is 0. the last one\r
2362 // with skip value is 1.\r
2363 //\r
2364 if (MenuOption->Skip != 0) {\r
2365 //\r
2366 // For date/ time, print the last past (year for date and second for time)\r
2367 // - 7 means skip [##/##/ for date and [##:##: for time.\r
2368 //\r
2369 DisplayMenuString (MenuOption,MenuOption->OptCol, Row, OutputString, Width + 1 - 7, Highlight);\r
2370 } else {\r
2371 //\r
2372 // For date/ time, print the first and second past (year for date and second for time)\r
f0c5095b
ED
2373 // The OutputString has a NARROW_CHAR or WIDE_CHAR at the begin of the string, \r
2374 // so need to - 1 to remove it, otherwise, it will clean 1 extr char follow it.\r
2375 DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, StrLen (OutputString) - 1, Highlight);\r
af047db7
ED
2376 }\r
2377 } else {\r
2378 DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);\r
2379 }\r
28401a65 2380 OptionLineNum++;\r
af047db7
ED
2381 }\r
2382 \r
2383 //\r
2384 // If there is more string to process print on the next row and increment the Skip value\r
2385 //\r
2386 if (StrLen (&OptionString[Index]) != 0) {\r
2387 if (Temp2 == 0) {\r
2388 Row++;\r
2389 //\r
2390 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
2391 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
2392 // some testing to ensure we are keeping this in-sync.\r
2393 //\r
2394 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
2395 //\r
28401a65 2396 if ((Row - MenuOption->Row) >= MenuOption->Skip) {\r
af047db7
ED
2397 MenuOption->Skip++;\r
2398 }\r
2399 }\r
2400 }\r
2401 \r
2402 FreePool (OutputString);\r
2403 if (Temp2 != 0) {\r
2404 Temp2--;\r
2405 }\r
2406 }\r
2407 \r
af047db7
ED
2408 Highlight = FALSE;\r
2409\r
2410 FreePool (OptionString);\r
2411 }\r
af047db7
ED
2412\r
2413 //\r
28401a65 2414 // 2. Paint the description.\r
af047db7 2415 //\r
6f05c023 2416 PromptWidth = GetWidth (MenuOption, &AdjustValue);\r
28401a65 2417 Row = MenuOption->Row;\r
af047db7
ED
2418 GlyphWidth = 1;\r
2419 PromptLineNum = 0;\r
2420\r
2421 if (MenuOption->Description == NULL || MenuOption->Description[0] == '\0') {\r
28401a65
ED
2422 PrintStringAtWithWidth (BeginCol, Row, L"", PromptWidth + AdjustValue + SkipWidth);\r
2423 PromptLineNum++;\r
af047db7
ED
2424 } else {\r
2425 for (Index = 0; GetLineByWidth (MenuOption->Description, PromptWidth, &GlyphWidth, &Index, &OutputString) != 0x0000;) { \r
2426 if ((Temp == 0) && (Row <= BottomRow)) { \r
2427 //\r
2428 // 1.Clean the start LEFT_SKIPPED_COLUMNS \r
2429 //\r
2430 PrintStringAtWithWidth (BeginCol, Row, L"", SkipWidth);\r
2431 \r
8c9c60b6 2432 if (Statement->OpCode->OpCode == EFI_IFR_REF_OP && MenuOption->Col >= 2 && IsProcessingFirstRow) {\r
af047db7
ED
2433 //\r
2434 // Print Arrow for Goto button.\r
2435 //\r
2436 PrintCharAt (\r
2437 MenuOption->Col - 2,\r
2438 Row,\r
2439 GEOMETRICSHAPE_RIGHT_TRIANGLE\r
2440 );\r
8c9c60b6 2441 IsProcessingFirstRow = FALSE;\r
af047db7
ED
2442 }\r
2443 DisplayMenuString (MenuOption, MenuOption->Col, Row, OutputString, PromptWidth + AdjustValue, Highlight);\r
2444 PromptLineNum ++;\r
2445 }\r
2446 //\r
2447 // If there is more string to process print on the next row and increment the Skip value\r
2448 //\r
2449 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
2450 if (Temp == 0) {\r
2451 Row++;\r
2452 }\r
2453 }\r
2454\r
2455 FreePool (OutputString);\r
2456 if (Temp != 0) {\r
2457 Temp--;\r
2458 }\r
2459 }\r
2460\r
2461 Highlight = FALSE;\r
af047db7 2462 }\r
af047db7
ED
2463\r
2464\r
2465 //\r
28401a65 2466 // 3. If this is a text op with secondary text information\r
af047db7
ED
2467 //\r
2468 if ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo != 0)) {\r
2469 StringPtr = GetToken (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo, gFormData->HiiHandle);\r
2470 \r
2471 Width = (UINT16) gOptionBlockWidth - 1;\r
28401a65 2472 Row = MenuOption->Row;\r
af047db7 2473 GlyphWidth = 1;\r
28401a65 2474 OptionLineNum = 0;\r
af047db7
ED
2475\r
2476 for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { \r
2477 if ((Temp3 == 0) && (Row <= BottomRow)) {\r
2478 DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);\r
28401a65 2479 OptionLineNum++;\r
af047db7
ED
2480 }\r
2481 //\r
2482 // If there is more string to process print on the next row and increment the Skip value\r
2483 //\r
2484 if (StrLen (&StringPtr[Index]) != 0) {\r
2485 if (Temp3 == 0) {\r
2486 Row++;\r
a6a2a956
ED
2487 //\r
2488 // If the rows for text two is greater than or equal to the skip value, increase the skip value\r
2489 //\r
2490 if ((Row - MenuOption->Row) >= MenuOption->Skip) {\r
2491 MenuOption->Skip++;\r
2492 }\r
af047db7
ED
2493 }\r
2494 }\r
2495 \r
2496 FreePool (OutputString);\r
2497 if (Temp3 != 0) {\r
2498 Temp3--;\r
2499 }\r
2500 }\r
28401a65 2501\r
af047db7
ED
2502 FreePool (StringPtr);\r
2503 }\r
2504\r
28401a65
ED
2505 //\r
2506 // 4.Line number for Option string and prompt string are not equal.\r
2507 // Clean the column whose line number is less.\r
2508 //\r
2509 if (HasOptionString(MenuOption) && (OptionLineNum != PromptLineNum)) {\r
2510 Col = OptionLineNum < PromptLineNum ? MenuOption->OptCol : BeginCol;\r
2511 Row = (OptionLineNum < PromptLineNum ? OptionLineNum : PromptLineNum) + MenuOption->Row;\r
2512 Width = (UINT16) (OptionLineNum < PromptLineNum ? gOptionBlockWidth : PromptWidth + AdjustValue + SkipWidth);\r
2513 MaxRow = (OptionLineNum < PromptLineNum ? PromptLineNum : OptionLineNum) + MenuOption->Row - 1;\r
2514 \r
2515 while (Row <= MaxRow) {\r
2516 DisplayMenuString (MenuOption, Col, Row++, L"", Width, FALSE);\r
2517 }\r
2518 }\r
2519\r
af047db7
ED
2520 return EFI_SUCCESS;\r
2521}\r
2522\r
7c6c064c
ED
2523/**\r
2524 Display menu and wait for user to select one menu option, then return it.\r
2525 If AutoBoot is enabled, then if user doesn't select any option,\r
2526 after period of time, it will automatically return the first menu option.\r
2527\r
2528 @param FormData The current form data info.\r
2529\r
2530 @retval EFI_SUCESSS Process the user selection success.\r
2531 @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.\r
2532\r
2533**/\r
2534EFI_STATUS\r
2535UiDisplayMenu (\r
2536 IN FORM_DISPLAY_ENGINE_FORM *FormData\r
2537 )\r
2538{\r
ab369468 2539 UINTN SkipValue;\r
7c6c064c
ED
2540 INTN Difference;\r
2541 UINTN DistanceValue;\r
2542 UINTN Row;\r
2543 UINTN Col;\r
7c6c064c
ED
2544 UINTN Temp;\r
2545 UINTN Temp2;\r
7c6c064c
ED
2546 UINTN TopRow;\r
2547 UINTN BottomRow;\r
7c6c064c 2548 UINTN Index;\r
7c6c064c 2549 CHAR16 *StringPtr;\r
cc63add8
DB
2550 CHAR16 *StringRightPtr;\r
2551 CHAR16 *StringErrorPtr;\r
7c6c064c 2552 CHAR16 *OptionString;\r
7c6c064c
ED
2553 CHAR16 *HelpString;\r
2554 CHAR16 *HelpHeaderString;\r
2555 CHAR16 *HelpBottomString;\r
2556 BOOLEAN NewLine;\r
2557 BOOLEAN Repaint;\r
2558 BOOLEAN UpArrow;\r
2559 BOOLEAN DownArrow;\r
2560 EFI_STATUS Status;\r
2561 EFI_INPUT_KEY Key;\r
2562 LIST_ENTRY *Link;\r
2563 LIST_ENTRY *NewPos;\r
2564 LIST_ENTRY *TopOfScreen;\r
2565 LIST_ENTRY *SavedListEntry;\r
2566 UI_MENU_OPTION *MenuOption;\r
2567 UI_MENU_OPTION *NextMenuOption;\r
2568 UI_MENU_OPTION *SavedMenuOption;\r
7c6c064c
ED
2569 UI_CONTROL_FLAG ControlFlag;\r
2570 UI_SCREEN_OPERATION ScreenOperation;\r
7c6c064c 2571 FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
7c6c064c
ED
2572 BROWSER_HOT_KEY *HotKey;\r
2573 UINTN HelpPageIndex;\r
2574 UINTN HelpPageCount;\r
2575 UINTN RowCount;\r
2576 UINTN HelpLine;\r
2577 UINTN HelpHeaderLine;\r
2578 UINTN HelpBottomLine;\r
2579 BOOLEAN MultiHelpPage;\r
7c6c064c
ED
2580 UINT16 EachLineWidth;\r
2581 UINT16 HeaderLineWidth;\r
2582 UINT16 BottomLineWidth;\r
2583 EFI_STRING_ID HelpInfo;\r
2584 UI_EVENT_TYPE EventType;\r
af047db7 2585 BOOLEAN SkipHighLight;\r
cc63add8 2586 EFI_HII_VALUE *StatementValue;\r
7c6c064c
ED
2587\r
2588 EventType = UIEventNone;\r
2589 Status = EFI_SUCCESS;\r
2590 HelpString = NULL;\r
2591 HelpHeaderString = NULL;\r
2592 HelpBottomString = NULL;\r
2593 OptionString = NULL;\r
2594 ScreenOperation = UiNoOperation;\r
2595 NewLine = TRUE;\r
7c6c064c
ED
2596 HelpPageCount = 0;\r
2597 HelpLine = 0;\r
2598 RowCount = 0;\r
2599 HelpBottomLine = 0;\r
2600 HelpHeaderLine = 0;\r
2601 HelpPageIndex = 0;\r
2602 MultiHelpPage = FALSE;\r
2603 EachLineWidth = 0;\r
2604 HeaderLineWidth = 0;\r
2605 BottomLineWidth = 0;\r
7c6c064c
ED
2606 UpArrow = FALSE;\r
2607 DownArrow = FALSE;\r
2608 SkipValue = 0;\r
af047db7 2609 SkipHighLight = FALSE;\r
7c6c064c
ED
2610\r
2611 NextMenuOption = NULL;\r
7c6c064c
ED
2612 SavedMenuOption = NULL;\r
2613 HotKey = NULL;\r
2614 Repaint = TRUE;\r
2615 MenuOption = NULL;\r
af047db7 2616 gModalSkipColumn = (CHAR16) (gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 6;\r
7c6c064c
ED
2617\r
2618 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
2619\r
7c6c064c
ED
2620 TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;\r
2621 BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT - 1;\r
2622\r
2623 Row = TopRow;\r
2624 if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
af047db7 2625 Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gModalSkipColumn;\r
7c6c064c
ED
2626 } else {\r
2627 Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
2628 }\r
2629\r
2630 FindTopMenu(FormData, &TopOfScreen, &NewPos, &SkipValue);\r
42645c3d
ED
2631 if (!IsListEmpty (&gMenuOption)) {\r
2632 NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2633 gUserInput->SelectedStatement = NextMenuOption->ThisTag;\r
2634 }\r
7c6c064c
ED
2635\r
2636 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
2637\r
2638 ControlFlag = CfInitialization;\r
2639 while (TRUE) {\r
2640 switch (ControlFlag) {\r
2641 case CfInitialization:\r
af047db7
ED
2642 if ((gOldFormEntry.HiiHandle != FormData->HiiHandle) || \r
2643 (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid))) {\r
2644 //\r
2645 // Clear Statement range if different formset is painted.\r
2646 //\r
2647 ClearLines (\r
2648 gStatementDimensions.LeftColumn,\r
2649 gStatementDimensions.RightColumn,\r
2650 TopRow - SCROLL_ARROW_HEIGHT,\r
2651 BottomRow + SCROLL_ARROW_HEIGHT,\r
2652 GetFieldTextColor ()\r
2653 );\r
7c6c064c 2654\r
7c6c064c 2655 }\r
af047db7 2656 ControlFlag = CfRepaint;\r
7c6c064c
ED
2657 break;\r
2658\r
2659 case CfRepaint:\r
2660 ControlFlag = CfRefreshHighLight;\r
2661\r
2662 if (Repaint) {\r
2663 //\r
2664 // Display menu\r
2665 //\r
2666 DownArrow = FALSE;\r
2667 UpArrow = FALSE;\r
2668 Row = TopRow;\r
2669\r
af047db7
ED
2670 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
2671 \r
7c6c064c 2672 //\r
af047db7 2673 // 1. Check whether need to print the arrow up.\r
7c6c064c 2674 //\r
af047db7
ED
2675 if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
2676 UpArrow = TRUE;\r
2677 }\r
af047db7 2678\r
ae4f5746
ED
2679 if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
2680 PrintStringAtWithWidth(gStatementDimensions.LeftColumn + gModalSkipColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn);\r
2681 } else {\r
2682 PrintStringAtWithWidth(gStatementDimensions.LeftColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);\r
2683 }\r
af047db7
ED
2684 if (UpArrow) {\r
2685 gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());\r
2686 PrintCharAt (\r
2687 gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
7c6c064c 2688 TopRow - SCROLL_ARROW_HEIGHT,\r
af047db7 2689 ARROW_UP\r
7c6c064c 2690 );\r
af047db7 2691 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
7c6c064c
ED
2692 }\r
2693\r
2694 //\r
2695 // 2.Paint the menu.\r
2696 //\r
2697 for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) {\r
2698 MenuOption = MENU_OPTION_FROM_LINK (Link);\r
2699 MenuOption->Row = Row;\r
2700 MenuOption->Col = Col;\r
2701 if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
af047db7 2702 MenuOption->OptCol = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gPromptBlockWidth + gModalSkipColumn;\r
7c6c064c 2703 } else {\r
af047db7 2704 MenuOption->OptCol = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gPromptBlockWidth;\r
7c6c064c
ED
2705 }\r
2706\r
7c6c064c
ED
2707 if (MenuOption->NestInStatement) {\r
2708 MenuOption->Col += SUBTITLE_INDENT;\r
2709 }\r
2710\r
7c6c064c 2711 //\r
af047db7 2712 // Save the highlight menu, will be used in CfRefreshHighLight case.\r
7c6c064c 2713 //\r
af047db7
ED
2714 if (Link == NewPos) {\r
2715 SavedMenuOption = MenuOption;\r
2716 SkipHighLight = TRUE;\r
7c6c064c 2717 }\r
ae4f5746
ED
2718\r
2719 if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
72f2eca2 2720 Status = DisplayOneMenu (MenuOption, \r
6f05c023 2721 MenuOption->Col - gStatementDimensions.LeftColumn,\r
ae4f5746
ED
2722 gStatementDimensions.LeftColumn + gModalSkipColumn, \r
2723 Link == TopOfScreen ? SkipValue : 0, \r
2724 BottomRow,\r
f0c5095b
ED
2725 (BOOLEAN) ((Link == NewPos) && IsSelectable(MenuOption)),\r
2726 TRUE\r
ae4f5746
ED
2727 );\r
2728 } else {\r
72f2eca2 2729 Status = DisplayOneMenu (MenuOption, \r
6f05c023 2730 MenuOption->Col - gStatementDimensions.LeftColumn,\r
ae4f5746
ED
2731 gStatementDimensions.LeftColumn, \r
2732 Link == TopOfScreen ? SkipValue : 0, \r
2733 BottomRow,\r
f0c5095b
ED
2734 (BOOLEAN) ((Link == NewPos) && IsSelectable(MenuOption)),\r
2735 TRUE\r
2736 );\r
ae4f5746 2737 }\r
7c6c064c 2738\r
72f2eca2 2739 if (EFI_ERROR (Status)) {\r
42645c3d
ED
2740 if (gMisMatch) {\r
2741 return EFI_SUCCESS;\r
2742 } else {\r
2743 return Status;\r
2744 }\r
72f2eca2 2745 }\r
7c6c064c
ED
2746 //\r
2747 // 3. Update the row info which will be used by next menu.\r
2748 //\r
2749 if (Link == TopOfScreen) {\r
2750 Row += MenuOption->Skip - SkipValue;\r
2751 } else {\r
2752 Row += MenuOption->Skip;\r
2753 }\r
2754\r
2755 if (Row > BottomRow) {\r
2756 if (!ValueIsScroll (FALSE, Link)) {\r
2757 DownArrow = TRUE;\r
2758 }\r
2759\r
2760 Row = BottomRow + 1;\r
2761 break;\r
2762 }\r
2763 }\r
2764\r
af047db7
ED
2765 //\r
2766 // 3. Menus in this form may not cover all form, clean the remain field.\r
2767 //\r
2768 while (Row <= BottomRow) {\r
2769 if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
ae4f5746 2770 PrintStringAtWithWidth(gStatementDimensions.LeftColumn + gModalSkipColumn, Row++, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn);\r
af047db7
ED
2771 } else {\r
2772 PrintStringAtWithWidth(gStatementDimensions.LeftColumn, Row++, L"", gStatementDimensions.RightColumn - gHelpBlockWidth - gStatementDimensions.LeftColumn);\r
2773 }\r
7c6c064c
ED
2774 }\r
2775\r
af047db7
ED
2776 //\r
2777 // 4. Print the down arrow row.\r
2778 //\r
ae4f5746
ED
2779 if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
2780 PrintStringAtWithWidth(gStatementDimensions.LeftColumn + gModalSkipColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * + gModalSkipColumn);\r
2781 } else {\r
2782 PrintStringAtWithWidth(gStatementDimensions.LeftColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);\r
2783 }\r
7c6c064c
ED
2784 if (DownArrow) {\r
2785 gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());\r
2786 PrintCharAt (\r
2787 gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
2788 BottomRow + SCROLL_ARROW_HEIGHT,\r
2789 ARROW_DOWN\r
2790 );\r
2791 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
2792 }\r
2793\r
2794 MenuOption = NULL;\r
2795 }\r
2796 break;\r
2797\r
2798 case CfRefreshHighLight:\r
2799\r
2800 //\r
2801 // MenuOption: Last menu option that need to remove hilight\r
2802 // MenuOption is set to NULL in Repaint\r
2803 // NewPos: Current menu option that need to hilight\r
2804 //\r
2805 ControlFlag = CfUpdateHelpString;\r
2806\r
42645c3d
ED
2807 UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);\r
2808\r
af047db7 2809 if (SkipHighLight) {\r
af047db7 2810 SkipHighLight = FALSE;\r
42645c3d
ED
2811 MenuOption = SavedMenuOption;\r
2812 RefreshKeyHelp(gFormData, SavedMenuOption->ThisTag, FALSE);\r
af047db7
ED
2813 break;\r
2814 }\r
2815\r
8924aecd
ED
2816 if (IsListEmpty (&gMenuOption)) {\r
2817 //\r
2818 // No menu option, just update the hotkey filed.\r
2819 //\r
2820 RefreshKeyHelp(gFormData, NULL, FALSE);\r
2821 break;\r
2822 }\r
2823\r
7c6c064c
ED
2824 if (MenuOption != NULL && TopOfScreen == &MenuOption->Link) {\r
2825 Temp = SkipValue;\r
2826 } else {\r
2827 Temp = 0;\r
2828 }\r
2829 if (NewPos == TopOfScreen) {\r
2830 Temp2 = SkipValue;\r
2831 } else {\r
2832 Temp2 = 0;\r
2833 }\r
2834\r
2835 if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {\r
2836 if (MenuOption != NULL) {\r
2837 //\r
ab369468 2838 // Remove the old highlight menu.\r
7c6c064c 2839 //\r
ab369468
ED
2840 Status = DisplayOneMenu (MenuOption, \r
2841 MenuOption->Col - gStatementDimensions.LeftColumn,\r
2842 gStatementDimensions.LeftColumn, \r
2843 Temp, \r
2844 BottomRow,\r
f0c5095b 2845 FALSE,\r
ab369468
ED
2846 FALSE\r
2847 );\r
7c6c064c
ED
2848 }\r
2849\r
2850 //\r
2851 // This is the current selected statement\r
2852 //\r
2853 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
42645c3d 2854 RefreshKeyHelp(gFormData, MenuOption->ThisTag, FALSE);\r
7c6c064c
ED
2855\r
2856 if (!IsSelectable (MenuOption)) {\r
7c6c064c
ED
2857 break;\r
2858 }\r
2859\r
ab369468
ED
2860 Status = DisplayOneMenu (MenuOption, \r
2861 MenuOption->Col - gStatementDimensions.LeftColumn,\r
2862 gStatementDimensions.LeftColumn, \r
2863 Temp2, \r
2864 BottomRow,\r
f0c5095b
ED
2865 TRUE,\r
2866 FALSE\r
ab369468 2867 );\r
7c6c064c
ED
2868 }\r
2869 break;\r
2870\r
2871 case CfUpdateHelpString:\r
2872 ControlFlag = CfPrepareToReadKey;\r
2873 if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
2874 break;\r
2875 }\r
2876\r
ab369468
ED
2877 //\r
2878 // NewLine means only update highlight menu (remove old highlight and highlith\r
2879 // the new one), not need to full repain the form.\r
2880 //\r
7c6c064c 2881 if (Repaint || NewLine) {\r
8924aecd
ED
2882 if (IsListEmpty (&gMenuOption)) {\r
2883 //\r
2884 // Don't print anything if no mwnu option.\r
2885 //\r
7c6c064c
ED
2886 StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
2887 } else {\r
8924aecd
ED
2888 //\r
2889 // Don't print anything if it is a NULL help token\r
2890 //\r
2891 ASSERT(MenuOption != NULL);\r
2892 HelpInfo = ((EFI_IFR_STATEMENT_HEADER *) ((CHAR8 *)MenuOption->ThisTag->OpCode + sizeof (EFI_IFR_OP_HEADER)))->Help;\r
cc63add8
DB
2893 Statement = MenuOption->ThisTag;\r
2894 StatementValue = &Statement->CurrentValue;\r
8924aecd 2895 if (HelpInfo == 0 || !IsSelectable (MenuOption)) {\r
cc63add8
DB
2896 if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP && StatementValue->Value.date.Month== 0xff)||(Statement->OpCode->OpCode == EFI_IFR_TIME_OP && StatementValue->Value.time.Hour == 0xff)){\r
2897 StringPtr = GetToken (STRING_TOKEN (GET_TIME_FAIL), gHiiHandle);\r
2898 } else {\r
2899 StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
2900 }\r
8924aecd 2901 } else {\r
cc63add8
DB
2902 if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP && StatementValue->Value.date.Month== 0xff)||(Statement->OpCode->OpCode == EFI_IFR_TIME_OP && StatementValue->Value.time.Hour == 0xff)){\r
2903 StringRightPtr = GetToken (HelpInfo, gFormData->HiiHandle);\r
2904 StringErrorPtr = GetToken (STRING_TOKEN (GET_TIME_FAIL), gHiiHandle);\r
2905 StringPtr = AllocateZeroPool ((StrLen (StringRightPtr) + StrLen (StringErrorPtr)+ 1 ) * sizeof (CHAR16));\r
2906 StrCpyS (StringPtr, StrLen (StringRightPtr) + StrLen (StringErrorPtr) + 1, StringRightPtr);\r
2907 StrCatS (StringPtr, StrLen (StringRightPtr) + StrLen (StringErrorPtr) + 1, StringErrorPtr);\r
2908 FreePool (StringRightPtr);\r
2909 FreePool (StringErrorPtr);\r
2910 } else {\r
2911 StringPtr = GetToken (HelpInfo, gFormData->HiiHandle);\r
2912 }\r
8924aecd 2913 }\r
7c6c064c
ED
2914 }\r
2915\r
2916 RowCount = BottomRow - TopRow + 1;\r
2917 HelpPageIndex = 0;\r
2918 //\r
2919 // 1.Calculate how many line the help string need to print.\r
2920 //\r
2921 if (HelpString != NULL) {\r
2922 FreePool (HelpString);\r
2923 HelpString = NULL;\r
2924 }\r
2925 HelpLine = ProcessHelpString (StringPtr, &HelpString, &EachLineWidth, RowCount);\r
2926 FreePool (StringPtr);\r
2927\r
2928 if (HelpLine > RowCount) {\r
2929 MultiHelpPage = TRUE;\r
2930 StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP), gHiiHandle);\r
2931 if (HelpHeaderString != NULL) {\r
2932 FreePool (HelpHeaderString);\r
2933 HelpHeaderString = NULL;\r
2934 }\r
2935 HelpHeaderLine = ProcessHelpString (StringPtr, &HelpHeaderString, &HeaderLineWidth, 0);\r
2936 FreePool (StringPtr);\r
2937 StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN), gHiiHandle);\r
2938 if (HelpBottomString != NULL) {\r
2939 FreePool (HelpBottomString);\r
2940 HelpBottomString = NULL;\r
2941 }\r
2942 HelpBottomLine = ProcessHelpString (StringPtr, &HelpBottomString, &BottomLineWidth, 0);\r
2943 FreePool (StringPtr);\r
2944 //\r
2945 // Calculate the help page count.\r
2946 //\r
2947 if (HelpLine > 2 * RowCount - 2) {\r
2948 HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1;\r
2949 if ((HelpLine - RowCount + 1) % (RowCount - 2) > 1) {\r
2950 HelpPageCount += 1;\r
2951 }\r
2952 } else {\r
2953 HelpPageCount = 2;\r
2954 }\r
2955 } else {\r
2956 MultiHelpPage = FALSE;\r
2957 }\r
2958 }\r
2959\r
2960 //\r
2961 // Check whether need to show the 'More(U/u)' at the begin.\r
2962 // Base on current direct info, here shows aligned to the right side of the column.\r
2963 // If the direction is multi line and aligned to right side may have problem, so \r
2964 // add ASSERT code here.\r
2965 //\r
2966 if (HelpPageIndex > 0) {\r
2967 gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ());\r
2968 for (Index = 0; Index < HelpHeaderLine; Index++) {\r
2969 ASSERT (HelpHeaderLine == 1);\r
2970 ASSERT (GetStringWidth (HelpHeaderString) / 2 < (UINTN) (gHelpBlockWidth - 1));\r
2971 PrintStringAtWithWidth (\r
2972 gStatementDimensions.RightColumn - gHelpBlockWidth,\r
2973 Index + TopRow,\r
2974 gEmptyString,\r
2975 gHelpBlockWidth\r
2976 );\r
2977 PrintStringAt (\r
2978 gStatementDimensions.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1,\r
2979 Index + TopRow,\r
2980 &HelpHeaderString[Index * HeaderLineWidth]\r
2981 );\r
2982 }\r
2983 }\r
2984\r
2985 gST->ConOut->SetAttribute (gST->ConOut, GetHelpTextColor ());\r
2986 //\r
2987 // Print the help string info.\r
2988 //\r
2989 if (!MultiHelpPage) {\r
2990 for (Index = 0; Index < HelpLine; Index++) {\r
2991 PrintStringAtWithWidth (\r
2992 gStatementDimensions.RightColumn - gHelpBlockWidth,\r
2993 Index + TopRow,\r
2994 &HelpString[Index * EachLineWidth],\r
2995 gHelpBlockWidth\r
2996 );\r
2997 }\r
2998 for (; Index < RowCount; Index ++) {\r
2999 PrintStringAtWithWidth (\r
3000 gStatementDimensions.RightColumn - gHelpBlockWidth,\r
3001 Index + TopRow,\r
3002 gEmptyString,\r
3003 gHelpBlockWidth\r
3004 );\r
3005 }\r
3006 gST->ConOut->SetCursorPosition(gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);\r
3007 } else {\r
3008 if (HelpPageIndex == 0) {\r
3009 for (Index = 0; Index < RowCount - HelpBottomLine; Index++) {\r
3010 PrintStringAtWithWidth (\r
3011 gStatementDimensions.RightColumn - gHelpBlockWidth,\r
3012 Index + TopRow,\r
3013 &HelpString[Index * EachLineWidth],\r
3014 gHelpBlockWidth\r
3015 );\r
3016 }\r
3017 } else {\r
3018 for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) && \r
3019 (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++) {\r
3020 PrintStringAtWithWidth (\r
3021 gStatementDimensions.RightColumn - gHelpBlockWidth,\r
3022 Index + TopRow + HelpHeaderLine,\r
3023 &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* EachLineWidth],\r
3024 gHelpBlockWidth\r
3025 );\r
3026 }\r
3027 if (HelpPageIndex == HelpPageCount - 1) {\r
3028 for (; Index < RowCount - HelpHeaderLine; Index ++) {\r
3029 PrintStringAtWithWidth (\r
3030 gStatementDimensions.RightColumn - gHelpBlockWidth,\r
3031 Index + TopRow + HelpHeaderLine,\r
3032 gEmptyString,\r
3033 gHelpBlockWidth\r
3034 );\r
3035 }\r
3036 gST->ConOut->SetCursorPosition(gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);\r
3037 }\r
3038 } \r
3039 }\r
3040\r
3041 //\r
3042 // Check whether need to print the 'More(D/d)' at the bottom.\r
3043 // Base on current direct info, here shows aligned to the right side of the column.\r
3044 // If the direction is multi line and aligned to right side may have problem, so \r
3045 // add ASSERT code here.\r
3046 //\r
3047 if (HelpPageIndex < HelpPageCount - 1 && MultiHelpPage) {\r
3048 gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ());\r
3049 for (Index = 0; Index < HelpBottomLine; Index++) {\r
3050 ASSERT (HelpBottomLine == 1);\r
3051 ASSERT (GetStringWidth (HelpBottomString) / 2 < (UINTN) (gHelpBlockWidth - 1)); \r
3052 PrintStringAtWithWidth (\r
3053 gStatementDimensions.RightColumn - gHelpBlockWidth,\r
3054 BottomRow + Index - HelpBottomLine + 1,\r
3055 gEmptyString,\r
3056 gHelpBlockWidth\r
3057 );\r
3058 PrintStringAt (\r
3059 gStatementDimensions.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1,\r
3060 BottomRow + Index - HelpBottomLine + 1,\r
3061 &HelpBottomString[Index * BottomLineWidth]\r
3062 );\r
3063 }\r
3064 }\r
3065 //\r
3066 // Reset this flag every time we finish using it.\r
3067 //\r
3068 Repaint = FALSE;\r
3069 NewLine = FALSE;\r
3070 break;\r
3071\r
3072 case CfPrepareToReadKey:\r
3073 ControlFlag = CfReadKey;\r
3074 ScreenOperation = UiNoOperation;\r
3075 break;\r
3076\r
3077 case CfReadKey:\r
3078 ControlFlag = CfScreenOperation;\r
3079\r
3080 //\r
3081 // Wait for user's selection\r
3082 //\r
3083 while (TRUE) {\r
3084 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
3085 if (!EFI_ERROR (Status)) {\r
3086 EventType = UIEventKey;\r
3087 break;\r
3088 }\r
3089\r
3090 //\r
3091 // If we encounter error, continue to read another key in.\r
3092 //\r
3093 if (Status != EFI_NOT_READY) {\r
3094 continue;\r
3095 }\r
3096 \r
3097 EventType = UiWaitForEvent(gST->ConIn->WaitForKey);\r
3098 if (EventType == UIEventKey) {\r
3099 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
3100 }\r
3101 break;\r
3102 }\r
3103\r
3104 if (EventType == UIEventDriver) {\r
42645c3d 3105 gMisMatch = TRUE;\r
7c6c064c
ED
3106 gUserInput->Action = BROWSER_ACTION_NONE;\r
3107 ControlFlag = CfExit;\r
3108 break;\r
3109 }\r
3110 \r
3111 if (EventType == UIEventTimeOut) {\r
3112 gUserInput->Action = BROWSER_ACTION_FORM_EXIT;\r
3113 ControlFlag = CfExit;\r
3114 break;\r
3115 }\r
3116\r
3117 switch (Key.UnicodeChar) {\r
3118 case CHAR_CARRIAGE_RETURN:\r
3119 if(MenuOption == NULL || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
3120 ControlFlag = CfReadKey;\r
3121 break;\r
3122 }\r
3123\r
3124 ScreenOperation = UiSelect;\r
3125 gDirection = 0;\r
3126 break;\r
3127\r
3128 //\r
3129 // We will push the adjustment of these numeric values directly to the input handler\r
3130 // NOTE: we won't handle manual input numeric\r
3131 //\r
3132 case '+':\r
3133 case '-':\r
3134 //\r
3135 // If the screen has no menu items, and the user didn't select UiReset\r
3136 // ignore the selection and go back to reading keys.\r
3137 //\r
05de47ef 3138 ASSERT(MenuOption != NULL);\r
7c6c064c
ED
3139 if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
3140 ControlFlag = CfReadKey;\r
3141 break;\r
3142 }\r
3143\r
7c6c064c
ED
3144 Statement = MenuOption->ThisTag;\r
3145 if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP)\r
3146 || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)\r
3147 || ((Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (GetFieldFromNum(Statement->OpCode) != 0))\r
3148 ){\r
3149 if (Key.UnicodeChar == '+') {\r
3150 gDirection = SCAN_RIGHT;\r
3151 } else {\r
3152 gDirection = SCAN_LEFT;\r
3153 }\r
3154 \r
3155 Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);\r
3156 if (OptionString != NULL) {\r
3157 FreePool (OptionString);\r
3158 }\r
3159 if (EFI_ERROR (Status)) {\r
3160 //\r
3161 // Repaint to clear possible error prompt pop-up\r
3162 //\r
3163 Repaint = TRUE;\r
3164 NewLine = TRUE;\r
3165 } else {\r
3166 ControlFlag = CfExit;\r
3167 }\r
3168 }\r
3169 break;\r
3170\r
3171 case '^':\r
3172 ScreenOperation = UiUp;\r
3173 break;\r
3174\r
3175 case 'V':\r
3176 case 'v':\r
3177 ScreenOperation = UiDown;\r
3178 break;\r
3179\r
3180 case ' ':\r
3181 if(IsListEmpty (&gMenuOption)) {\r
3182 ControlFlag = CfReadKey;\r
3183 break;\r
3184 }\r
3185 \r
3186 ASSERT(MenuOption != NULL);\r
3187 if (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) {\r
3188 ScreenOperation = UiSelect;\r
3189 }\r
3190 break;\r
3191\r
3192 case 'D':\r
3193 case 'd':\r
3194 if (!MultiHelpPage) {\r
3195 ControlFlag = CfReadKey;\r
3196 break;\r
3197 }\r
3198 ControlFlag = CfUpdateHelpString;\r
3199 HelpPageIndex = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1;\r
3200 break;\r
3201\r
3202 case 'U':\r
3203 case 'u':\r
3204 if (!MultiHelpPage) {\r
3205 ControlFlag = CfReadKey;\r
3206 break;\r
3207 }\r
3208 ControlFlag = CfUpdateHelpString;\r
3209 HelpPageIndex = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0;\r
3210 break;\r
3211\r
3212 case CHAR_NULL:\r
3213 for (Index = 0; Index < mScanCodeNumber; Index++) {\r
3214 if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
3215 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
3216 break;\r
3217 }\r
3218 }\r
3219 \r
3220 if (((FormData->Attribute & HII_DISPLAY_MODAL) != 0) && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) {\r
3221 //\r
3222 // ModalForm has no ESC key and Hot Key.\r
3223 //\r
3224 ControlFlag = CfReadKey;\r
3225 } else if (Index == mScanCodeNumber) {\r
3226 //\r
3227 // Check whether Key matches the registered hot key.\r
3228 //\r
3229 HotKey = NULL;\r
3230 HotKey = GetHotKeyFromRegisterList (&Key);\r
3231 if (HotKey != NULL) {\r
3232 ScreenOperation = UiHotKey;\r
3233 }\r
3234 }\r
3235 break;\r
3236 }\r
3237 break;\r
3238\r
3239 case CfScreenOperation:\r
8924aecd 3240 if ((ScreenOperation != UiReset) && (ScreenOperation != UiHotKey)) {\r
7c6c064c 3241 //\r
8924aecd 3242 // If the screen has no menu items, and the user didn't select UiReset or UiHotKey\r
7c6c064c
ED
3243 // ignore the selection and go back to reading keys.\r
3244 //\r
3245 if (IsListEmpty (&gMenuOption)) {\r
3246 ControlFlag = CfReadKey;\r
3247 break;\r
3248 }\r
3249 }\r
3250\r
3251 for (Index = 0;\r
3252 Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
3253 Index++\r
3254 ) {\r
3255 if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
3256 ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
3257 break;\r
3258 }\r
3259 }\r
3260 break;\r
3261\r
3262 case CfUiSelect:\r
3263 ControlFlag = CfRepaint;\r
3264\r
3265 ASSERT(MenuOption != NULL);\r
3266 Statement = MenuOption->ThisTag;\r
3267 if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {\r
3268 break;\r
3269 }\r
3270\r
3271 switch (Statement->OpCode->OpCode) {\r
3272 case EFI_IFR_REF_OP:\r
3273 case EFI_IFR_ACTION_OP:\r
3274 case EFI_IFR_RESET_BUTTON_OP:\r
3275 ControlFlag = CfExit;\r
3276 break;\r
3277\r
3278 default:\r
3279 //\r
3280 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password\r
3281 //\r
3282 RefreshKeyHelp (gFormData, Statement, TRUE);\r
3283 Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);\r
3284 \r
3285 if (OptionString != NULL) {\r
3286 FreePool (OptionString);\r
3287 }\r
3288 \r
3289 if (EFI_ERROR (Status)) {\r
3290 Repaint = TRUE;\r
3291 NewLine = TRUE;\r
3292 RefreshKeyHelp (gFormData, Statement, FALSE);\r
3293 break;\r
3294 } else {\r
3295 ControlFlag = CfExit;\r
3296 break;\r
3297 }\r
3298 }\r
3299 break;\r
3300\r
3301 case CfUiReset:\r
3302 //\r
3303 // We come here when someone press ESC\r
3304 // If the policy is not exit front page when user press ESC, process here.\r
3305 //\r
3306 if (!FormExitPolicy()) {\r
3307 Repaint = TRUE;\r
3308 NewLine = TRUE;\r
3309 ControlFlag = CfRepaint;\r
3310 break;\r
3311 }\r
3312\r
7c6c064c
ED
3313 gUserInput->Action = BROWSER_ACTION_FORM_EXIT;\r
3314 ControlFlag = CfExit;\r
3315 break;\r
3316\r
3317 case CfUiHotKey:\r
3318 ControlFlag = CfRepaint;\r
05de47ef
ED
3319\r
3320 ASSERT (HotKey != NULL);\r
23c7d425
ED
3321\r
3322 if (FxConfirmPopup(HotKey->Action)) {\r
3323 gUserInput->Action = HotKey->Action;\r
a687a1d2
ED
3324 if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
3325 gUserInput->DefaultId = HotKey->DefaultId;\r
3326 }\r
23c7d425
ED
3327 ControlFlag = CfExit;\r
3328 } else {\r
3329 Repaint = TRUE;\r
3330 NewLine = TRUE;\r
3331 ControlFlag = CfRepaint;\r
3332 }\r
3333\r
7c6c064c
ED
3334 break;\r
3335\r
3336 case CfUiLeft:\r
3337 ControlFlag = CfRepaint;\r
3338 ASSERT(MenuOption != NULL);\r
3339 if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {\r
3340 if (MenuOption->Sequence != 0) {\r
3341 //\r
3342 // In the middle or tail of the Date/Time op-code set, go left.\r
3343 //\r
3344 ASSERT(NewPos != NULL);\r
3345 NewPos = NewPos->BackLink;\r
3346 }\r
3347 }\r
3348 break;\r
3349\r
3350 case CfUiRight:\r
3351 ControlFlag = CfRepaint;\r
3352 ASSERT(MenuOption != NULL);\r
3353 if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {\r
3354 if (MenuOption->Sequence != 2) {\r
3355 //\r
3356 // In the middle or tail of the Date/Time op-code set, go left.\r
3357 //\r
3358 ASSERT(NewPos != NULL);\r
3359 NewPos = NewPos->ForwardLink;\r
3360 }\r
3361 }\r
3362 break;\r
3363\r
3364 case CfUiUp:\r
3365 ControlFlag = CfRepaint;\r
ab369468 3366 NewLine = TRUE;\r
7c6c064c
ED
3367\r
3368 SavedListEntry = NewPos;\r
7c6c064c 3369 ASSERT(NewPos != NULL);\r
f0c5095b
ED
3370\r
3371 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
3372 ASSERT (MenuOption != NULL);\r
3373\r
7c6c064c
ED
3374 //\r
3375 // Adjust Date/Time position before we advance forward.\r
3376 //\r
3377 AdjustDateAndTimePosition (TRUE, &NewPos);\r
7c6c064c 3378\r
ab369468
ED
3379 NewPos = NewPos->BackLink;\r
3380 //\r
3381 // Find next selectable menu or the first menu beyond current form.\r
3382 //\r
3383 Difference = MoveToNextStatement (TRUE, &NewPos, MenuOption->Row - TopRow, FALSE);\r
3384 if (Difference < 0) {\r
3385 //\r
3386 // We hit the begining MenuOption that can be focused\r
3387 // so we simply scroll to the top.\r
3388 //\r
3389 Repaint = TRUE;\r
3390 if (TopOfScreen != gMenuOption.ForwardLink || SkipValue != 0) {\r
3391 TopOfScreen = gMenuOption.ForwardLink;\r
3392 NewPos = SavedListEntry;\r
3393 SkipValue = 0;\r
3394 } else {\r
7c6c064c 3395 //\r
ab369468 3396 // Scroll up to the last page when we have arrived at top page.\r
7c6c064c 3397 //\r
ab369468
ED
3398 TopOfScreen = FindTopOfScreenMenu (gMenuOption.BackLink, BottomRow - TopRow, &SkipValue);\r
3399 NewPos = gMenuOption.BackLink;\r
3400 MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow, TRUE);\r
3401 }\r
3402 } else {\r
3403 NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
3404\r
3405 if (MenuOption->Row < TopRow + Difference + NextMenuOption->Skip) {\r
7c6c064c
ED
3406 //\r
3407 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
3408 //\r
3409 TopOfScreen = NewPos;\r
3410 Repaint = TRUE;\r
ab369468 3411 SkipValue = 0;\r
7c6c064c
ED
3412 }\r
3413\r
3414 //\r
ab369468 3415 // Check whether new highlight menu is selectable, if not, keep highlight on the old one.\r
7c6c064c 3416 //\r
ab369468
ED
3417 // BottomRow - TopRow + 1 means the total rows current forms supported.\r
3418 // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu \r
3419 // and new top menu. New top menu will all shows in next form, but last highlight menu \r
3420 // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the \r
3421 // last highlight menu.\r
3422 // \r
3423 if (!IsSelectable(NextMenuOption) && IsSelectable(MenuOption) && \r
3424 (BottomRow - TopRow + 1 >= Difference + NextMenuOption->Skip + 1)) {\r
3425 NewPos = SavedListEntry;\r
6f05c023 3426 }\r
7c6c064c 3427 }\r
7c6c064c 3428\r
ab369468 3429 UpdateStatusBar (INPUT_ERROR, FALSE);\r
7c6c064c 3430\r
7c6c064c 3431 //\r
ab369468 3432 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
7c6c064c 3433 //\r
ab369468
ED
3434 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3435 AdjustDateAndTimePosition (TRUE, &NewPos);\r
42645c3d
ED
3436\r
3437 UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);\r
ab369468 3438 break;\r
7c6c064c 3439\r
ab369468 3440 case CfUiPageUp:\r
7c6c064c 3441 //\r
ab369468 3442 // SkipValue means lines is skipped when show the top menu option.\r
7c6c064c 3443 //\r
ab369468
ED
3444 ControlFlag = CfRepaint;\r
3445 NewLine = TRUE;\r
3446 Repaint = TRUE;\r
7c6c064c
ED
3447\r
3448 Link = TopOfScreen;\r
3449 //\r
3450 // First minus the menu of the top screen, it's value is SkipValue.\r
3451 //\r
2e7183ba 3452 if (SkipValue >= BottomRow - TopRow + 1) {\r
7c6c064c 3453 //\r
ab369468
ED
3454 // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one\r
3455 // form of options to be show, so just update the SkipValue to show the next\r
3456 // parts of options.\r
7c6c064c 3457 //\r
ab369468
ED
3458 SkipValue -= BottomRow - TopRow + 1;\r
3459 NewPos = TopOfScreen;\r
3460 break;\r
3461 } else {\r
3462 Index = (BottomRow + 1) - SkipValue - TopRow;\r
7c6c064c 3463 }\r
ab369468
ED
3464 \r
3465 TopOfScreen = FindTopOfScreenMenu(TopOfScreen, Index, &SkipValue);\r
3466 NewPos = TopOfScreen;\r
3467 MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow, FALSE);\r
3468 \r
3469 UpdateStatusBar (INPUT_ERROR, FALSE);\r
7c6c064c
ED
3470\r
3471 //\r
3472 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
3473 // Don't do this when we are already in the first page.\r
3474 //\r
3475 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3476 AdjustDateAndTimePosition (TRUE, &NewPos);\r
42645c3d
ED
3477\r
3478 UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);\r
7c6c064c
ED
3479 break;\r
3480\r
3481 case CfUiPageDown:\r
3482 //\r
3483 // SkipValue means lines is skipped when show the top menu option.\r
3484 //\r
ab369468
ED
3485 ControlFlag = CfRepaint;\r
3486 NewLine = TRUE;\r
3487 Repaint = TRUE;\r
7c6c064c 3488\r
7c6c064c
ED
3489 Link = TopOfScreen;\r
3490 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
3491 Index = TopRow + NextMenuOption->Skip - SkipValue;\r
3492 //\r
3493 // Count to the menu option which will show at the top of the next form.\r
3494 //\r
3495 while ((Index <= BottomRow + 1) && (Link->ForwardLink != &gMenuOption)) {\r
3496 Link = Link->ForwardLink;\r
3497 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
3498 Index = Index + NextMenuOption->Skip;\r
3499 }\r
3500\r
3501 if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) {\r
3502 //\r
ab369468 3503 // Highlight on the last menu which can be highlight.\r
7c6c064c
ED
3504 //\r
3505 Repaint = FALSE;\r
ab369468 3506 MoveToNextStatement (TRUE, &Link, Index - TopRow, TRUE);\r
7c6c064c
ED
3507 } else {\r
3508 //\r
3509 // Calculate the skip line for top of screen menu.\r
3510 //\r
3511 if (Link == TopOfScreen) {\r
3512 //\r
3513 // The top of screen menu option occupies the entire form.\r
3514 //\r
3515 SkipValue += BottomRow - TopRow + 1;\r
3516 } else {\r
3517 SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1));\r
3518 }\r
7c6c064c
ED
3519 TopOfScreen = Link;\r
3520 MenuOption = NULL;\r
3521 //\r
3522 // Move to the Next selectable menu.\r
3523 //\r
ab369468 3524 MoveToNextStatement (FALSE, &Link, BottomRow - TopRow, TRUE);\r
7c6c064c
ED
3525 }\r
3526\r
3527 //\r
3528 // Save the menu as the next highlight menu.\r
3529 //\r
3530 NewPos = Link;\r
3531\r
ab369468
ED
3532 UpdateStatusBar (INPUT_ERROR, FALSE);\r
3533\r
7c6c064c
ED
3534 //\r
3535 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
3536 // Don't do this when we are already in the last page.\r
3537 //\r
3538 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3539 AdjustDateAndTimePosition (TRUE, &NewPos);\r
42645c3d
ED
3540\r
3541 UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);\r
7c6c064c
ED
3542 break;\r
3543\r
3544 case CfUiDown:\r
3545 //\r
3546 // SkipValue means lines is skipped when show the top menu option.\r
3547 // NewPos points to the menu which is highlighted now.\r
3548 //\r
3549 ControlFlag = CfRepaint;\r
ab369468 3550 NewLine = TRUE;\r
7c6c064c 3551\r
ab369468
ED
3552 if (NewPos == TopOfScreen) {\r
3553 Temp2 = SkipValue;\r
3554 } else {\r
3555 Temp2 = 0;\r
3556 }\r
3557\r
3558 SavedListEntry = NewPos;\r
7c6c064c
ED
3559 //\r
3560 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
3561 // to be one that progresses to the next set of op-codes, we need to advance to the last\r
3562 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
3563 // checking can be done. The only other logic we need to introduce is that if a Date/Time\r
3564 // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
3565 // the Date/Time op-code.\r
3566 //\r
7c6c064c
ED
3567 AdjustDateAndTimePosition (FALSE, &NewPos);\r
3568\r
ab369468
ED
3569 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
3570 NewPos = NewPos->ForwardLink;\r
3571 //\r
3572 // Find the next selectable menu.\r
3573 //\r
3574 if (MenuOption->Row + MenuOption->Skip - Temp2 > BottomRow + 1) {\r
3575 if (gMenuOption.ForwardLink == NewPos || &gMenuOption == NewPos) {\r
3576 Difference = -1;\r
3577 } else {\r
3578 Difference = 0;\r
3579 }\r
3580 } else {\r
3581 Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow + 1 - (MenuOption->Row + MenuOption->Skip - Temp2), FALSE);\r
3582 }\r
3583 if (Difference < 0) {\r
3584 //\r
3585 // Scroll to the first page.\r
3586 //\r
3587 if (TopOfScreen != gMenuOption.ForwardLink || SkipValue != 0) { \r
3588 TopOfScreen = gMenuOption.ForwardLink;\r
3589 Repaint = TRUE;\r
3590 MenuOption = NULL;\r
6f05c023 3591 } else {\r
ab369468 3592 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
6f05c023 3593 }\r
ab369468
ED
3594 NewPos = gMenuOption.ForwardLink;\r
3595 MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow, TRUE);\r
6f05c023 3596\r
ab369468
ED
3597 SkipValue = 0;\r
3598 //\r
3599 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
3600 //\r
3601 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3602 AdjustDateAndTimePosition (TRUE, &NewPos);\r
42645c3d
ED
3603\r
3604 UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);\r
ab369468
ED
3605 break;\r
3606 } \r
7c6c064c 3607\r
ab369468
ED
3608 //\r
3609 // Get next selected menu info.\r
3610 //\r
3611 AdjustDateAndTimePosition (FALSE, &NewPos);\r
3612 NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
3613 if (NextMenuOption->Row == 0) {\r
3614 UpdateOptionSkipLines (NextMenuOption);\r
3615 }\r
3616\r
3617 //\r
3618 // Calculate new highlight menu end row.\r
3619 //\r
3620 Temp = (MenuOption->Row + MenuOption->Skip - Temp2) + Difference + NextMenuOption->Skip - 1;\r
3621 if (Temp > BottomRow) {\r
7c6c064c 3622 //\r
ab369468 3623 // Get the top screen menu info.\r
7c6c064c 3624 //\r
ab369468
ED
3625 AdjustDateAndTimePosition (FALSE, &TopOfScreen);\r
3626 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
3627\r
3628 //\r
3629 // Current Top screen menu occupy (SavedMenuOption->Skip - SkipValue) rows.\r
3630 // Full shows the new selected menu need to skip (Temp - BottomRow - 1) rows.\r
3631 //\r
3632 if ((Temp - BottomRow) >= (SavedMenuOption->Skip - SkipValue)) {\r
7c6c064c 3633 //\r
ab369468 3634 // Skip the top op-code\r
7c6c064c 3635 //\r
ab369468
ED
3636 TopOfScreen = TopOfScreen->ForwardLink;\r
3637 DistanceValue = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);\r
7c6c064c 3638\r
ab369468 3639 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
7c6c064c 3640\r
ab369468
ED
3641 //\r
3642 // If we have a remainder, skip that many more op-codes until we drain the remainder\r
3643 // Special case is the selected highlight menu has more than one form of menus.\r
3644 //\r
3645 while (DistanceValue >= SavedMenuOption->Skip && TopOfScreen != NewPos) {\r
7c6c064c 3646 //\r
ab369468 3647 // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
7c6c064c 3648 //\r
ab369468
ED
3649 DistanceValue = DistanceValue - (INTN) SavedMenuOption->Skip;\r
3650 TopOfScreen = TopOfScreen->ForwardLink;\r
7c6c064c 3651 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
ab369468 3652 }\r
7c6c064c 3653 //\r
ab369468
ED
3654 // Since we will act on this op-code in the next routine, and increment the\r
3655 // SkipValue, set the skips to one less than what is required.\r
7c6c064c 3656 //\r
ab369468
ED
3657 if (TopOfScreen != NewPos) {\r
3658 SkipValue = DistanceValue;\r
3659 } else {\r
3660 SkipValue = 0;\r
3661 }\r
7c6c064c
ED
3662 } else {\r
3663 //\r
ab369468
ED
3664 // Since we will act on this op-code in the next routine, and increment the\r
3665 // SkipValue, set the skips to one less than what is required.\r
7c6c064c 3666 //\r
ab369468 3667 SkipValue += Temp - BottomRow;\r
7c6c064c 3668 }\r
ab369468
ED
3669 Repaint = TRUE;\r
3670 } else if (!IsSelectable (NextMenuOption)) {\r
7c6c064c 3671 //\r
ab369468 3672 // Continue to go down until scroll to next page or the selectable option is found.\r
7c6c064c 3673 //\r
ab369468
ED
3674 ScreenOperation = UiDown;\r
3675 ControlFlag = CfScreenOperation;\r
3676 break;\r
3677 }\r
3678\r
3679 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3680\r
3681 //\r
3682 // Check whether new highlight menu is selectable, if not, keep highlight on the old one.\r
3683 //\r
3684 // BottomRow - TopRow + 1 means the total rows current forms supported.\r
3685 // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu \r
3686 // and new top menu. New top menu will all shows in next form, but last highlight menu \r
3687 // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the \r
3688 // last highlight menu.\r
3689 // \r
3690 if (!IsSelectable (NextMenuOption) && IsSelectable (MenuOption) && \r
3691 (BottomRow - TopRow + 1 >= Difference + NextMenuOption->Skip + 1)) {\r
3692 NewPos = SavedListEntry;\r
7c6c064c
ED
3693 }\r
3694\r
ab369468
ED
3695 UpdateStatusBar (INPUT_ERROR, FALSE);\r
3696\r
7c6c064c
ED
3697 //\r
3698 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
3699 //\r
3700 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3701 AdjustDateAndTimePosition (TRUE, &NewPos);\r
42645c3d
ED
3702\r
3703 UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);\r
7c6c064c
ED
3704 break;\r
3705\r
3706 case CfUiNoOperation:\r
3707 ControlFlag = CfRepaint;\r
3708 break;\r
3709\r
3710 case CfExit:\r
5a9f73bf 3711 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
7c6c064c
ED
3712 if (HelpString != NULL) {\r
3713 FreePool (HelpString);\r
3714 }\r
3715 if (HelpHeaderString != NULL) {\r
3716 FreePool (HelpHeaderString);\r
3717 }\r
3718 if (HelpBottomString != NULL) {\r
3719 FreePool (HelpBottomString);\r
3720 }\r
3721 return EFI_SUCCESS;\r
3722\r
3723 default:\r
3724 break;\r
3725 }\r
3726 }\r
3727}\r
3728\r
3729/**\r
3730\r
3731 Base on the browser status info to show an pop up message.\r
3732\r
3733**/\r
3734VOID\r
3735BrowserStatusProcess (\r
3736 VOID\r
3737 )\r
3738{\r
bfae1330
ED
3739 CHAR16 *ErrorInfo;\r
3740 EFI_INPUT_KEY Key;\r
3741 EFI_EVENT WaitList[2];\r
3742 EFI_EVENT RefreshIntervalEvent;\r
3743 EFI_EVENT TimeOutEvent;\r
3744 UINT8 TimeOut;\r
3745 EFI_STATUS Status;\r
3746 UINTN Index;\r
3747 WARNING_IF_CONTEXT EventContext;\r
3748 EFI_IFR_OP_HEADER *OpCodeBuf;\r
3749 EFI_STRING_ID StringToken;\r
4d4deaac
ED
3750 CHAR16 DiscardChange;\r
3751 CHAR16 JumpToFormSet;\r
3752 CHAR16 *PrintString;\r
7c6c064c
ED
3753\r
3754 if (gFormData->BrowserStatus == BROWSER_SUCCESS) {\r
3755 return;\r
3756 }\r
3757\r
bfae1330
ED
3758 StringToken = 0;\r
3759 TimeOutEvent = NULL;\r
3760 RefreshIntervalEvent = NULL;\r
3761 OpCodeBuf = NULL;\r
3762 if (gFormData->HighLightedStatement != NULL) {\r
3763 OpCodeBuf = gFormData->HighLightedStatement->OpCode;\r
3764 }\r
3765\r
3766 if (gFormData->BrowserStatus == (BROWSER_WARNING_IF)) {\r
3767 ASSERT (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_WARNING_IF_OP);\r
3768\r
3769 TimeOut = ((EFI_IFR_WARNING_IF *) OpCodeBuf)->TimeOut;\r
3770 StringToken = ((EFI_IFR_WARNING_IF *) OpCodeBuf)->Warning;\r
3771 } else {\r
3772 TimeOut = 0;\r
3773 if ((gFormData->BrowserStatus == (BROWSER_NO_SUBMIT_IF)) &&\r
3774 (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_NO_SUBMIT_IF_OP)) {\r
3775 StringToken = ((EFI_IFR_NO_SUBMIT_IF *) OpCodeBuf)->Error;\r
3776 } else if ((gFormData->BrowserStatus == (BROWSER_INCONSISTENT_IF)) &&\r
3777 (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_INCONSISTENT_IF_OP)) {\r
3778 StringToken = ((EFI_IFR_INCONSISTENT_IF *) OpCodeBuf)->Error;\r
3779 }\r
3780 }\r
3781\r
3782 if (StringToken != 0) {\r
3783 ErrorInfo = GetToken (StringToken, gFormData->HiiHandle);\r
3784 } else if (gFormData->ErrorString != NULL) {\r
3785 //\r
3786 // Only used to compatible with old setup browser.\r
3787 // Not use this field in new browser core.\r
3788 //\r
7c6c064c
ED
3789 ErrorInfo = gFormData->ErrorString;\r
3790 } else {\r
3791 switch (gFormData->BrowserStatus) {\r
3792 case BROWSER_SUBMIT_FAIL:\r
3793 ErrorInfo = gSaveFailed;\r
3794 break;\r
3795\r
7c6c064c
ED
3796 case BROWSER_FORM_NOT_FOUND:\r
3797 ErrorInfo = gFormNotFound;\r
3798 break;\r
3799\r
3800 case BROWSER_FORM_SUPPRESS:\r
3801 ErrorInfo = gFormSuppress;\r
3802 break;\r
3803\r
3804 case BROWSER_PROTOCOL_NOT_FOUND:\r
3805 ErrorInfo = gProtocolNotFound;\r
3806 break;\r
3807\r
4d4deaac
ED
3808 case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF:\r
3809 ErrorInfo = gNoSubmitIfFailed;\r
3810 break;\r
3811\r
f2e7732e
ED
3812 case BROWSER_RECONNECT_FAIL:\r
3813 ErrorInfo = gReconnectFail;\r
3814 break;\r
3815\r
3816 case BROWSER_RECONNECT_SAVE_CHANGES:\r
3817 ErrorInfo = gReconnectConfirmChanges;\r
3818 break;\r
3819\r
3820 case BROWSER_RECONNECT_REQUIRED:\r
3821 ErrorInfo = gReconnectRequired;\r
3822 break;\r
3823\r
7c6c064c 3824 default:\r
f2e7732e 3825 ErrorInfo = gBrowserError;\r
7c6c064c
ED
3826 break;\r
3827 }\r
3828 }\r
3829\r
4d4deaac
ED
3830 switch (gFormData->BrowserStatus) {\r
3831 case BROWSER_SUBMIT_FAIL:\r
3832 case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF:\r
f2e7732e 3833 case BROWSER_RECONNECT_SAVE_CHANGES:\r
4d4deaac
ED
3834 ASSERT (gUserInput != NULL);\r
3835 if (gFormData->BrowserStatus == (BROWSER_SUBMIT_FAIL)) {\r
3836 PrintString = gSaveProcess;\r
3837 JumpToFormSet = gJumpToFormSet[0];\r
f2e7732e
ED
3838 DiscardChange = gDiscardChange[0];\r
3839 } else if (gFormData->BrowserStatus == (BROWSER_RECONNECT_SAVE_CHANGES)){\r
3840 PrintString = gChangesOpt;\r
3841 JumpToFormSet = gConfirmOptYes[0];\r
3842 DiscardChange = gConfirmOptNo[0];\r
4d4deaac
ED
3843 } else {\r
3844 PrintString = gSaveNoSubmitProcess;\r
3845 JumpToFormSet = gCheckError[0];\r
f2e7732e 3846 DiscardChange = gDiscardChange[0];\r
4d4deaac 3847 }\r
4d4deaac 3848\r
bfae1330 3849 do {\r
4d4deaac
ED
3850 CreateDialog (&Key, gEmptyString, ErrorInfo, PrintString, gEmptyString, NULL);\r
3851 } while (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (DiscardChange | UPPER_LOWER_CASE_OFFSET)) &&\r
3852 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (JumpToFormSet | UPPER_LOWER_CASE_OFFSET)));\r
bfae1330 3853\r
4d4deaac
ED
3854 if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (DiscardChange | UPPER_LOWER_CASE_OFFSET)) {\r
3855 gUserInput->Action = BROWSER_ACTION_DISCARD;\r
3856 } else {\r
3857 gUserInput->Action = BROWSER_ACTION_GOTO;\r
3858 }\r
3859 break;\r
bfae1330 3860\r
4d4deaac
ED
3861 default:\r
3862 if (TimeOut == 0) {\r
3863 do {\r
3864 CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);\r
3865 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
3866 } else {\r
3867 Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_CALLBACK, EmptyEventProcess, NULL, &TimeOutEvent);\r
3868 ASSERT_EFI_ERROR (Status);\r
bfae1330 3869\r
4d4deaac
ED
3870 EventContext.SyncEvent = TimeOutEvent;\r
3871 EventContext.TimeOut = &TimeOut;\r
3872 EventContext.ErrorInfo = ErrorInfo;\r
bfae1330 3873\r
4d4deaac
ED
3874 Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshTimeOutProcess, &EventContext, &RefreshIntervalEvent);\r
3875 ASSERT_EFI_ERROR (Status);\r
bfae1330 3876\r
4d4deaac
ED
3877 //\r
3878 // Show the dialog first to avoid long time not reaction.\r
3879 //\r
3880 gBS->SignalEvent (RefreshIntervalEvent);\r
3881 \r
3882 Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, ONE_SECOND);\r
3883 ASSERT_EFI_ERROR (Status);\r
bfae1330 3884\r
4d4deaac
ED
3885 while (TRUE) {\r
3886 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
3887 if (!EFI_ERROR (Status) && Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
3888 break;\r
3889 }\r
bfae1330 3890\r
4d4deaac
ED
3891 if (Status != EFI_NOT_READY) {\r
3892 continue;\r
3893 }\r
bfae1330 3894\r
4d4deaac
ED
3895 WaitList[0] = TimeOutEvent;\r
3896 WaitList[1] = gST->ConIn->WaitForKey;\r
bfae1330 3897\r
4d4deaac
ED
3898 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
3899 ASSERT_EFI_ERROR (Status);\r
3900\r
3901 if (Index == 0) {\r
3902 //\r
3903 // Timeout occur, close the hoot time out event.\r
3904 //\r
3905 break;\r
3906 }\r
bfae1330 3907 }\r
4d4deaac
ED
3908\r
3909 gBS->CloseEvent (TimeOutEvent);\r
3910 gBS->CloseEvent (RefreshIntervalEvent);\r
bfae1330 3911 }\r
4d4deaac 3912 break;\r
bfae1330
ED
3913 }\r
3914\r
bfae1330
ED
3915 if (StringToken != 0) {\r
3916 FreePool (ErrorInfo);\r
3917 }\r
7c6c064c
ED
3918}\r
3919\r
3920/**\r
3921 Display one form, and return user input.\r
3922 \r
3923 @param FormData Form Data to be shown.\r
3924 @param UserInputData User input data.\r
3925 \r
3926 @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.\r
3927 2.Error info has show and return.\r
3928 @retval EFI_INVALID_PARAMETER The input screen dimension is not valid\r
3929 @retval EFI_NOT_FOUND New form data has some error.\r
3930**/\r
3931EFI_STATUS\r
3932EFIAPI \r
3933FormDisplay (\r
3934 IN FORM_DISPLAY_ENGINE_FORM *FormData,\r
3935 OUT USER_INPUT *UserInputData\r
3936 )\r
3937{\r
3938 EFI_STATUS Status;\r
3939\r
3940 ASSERT (FormData != NULL);\r
3941 if (FormData == NULL) {\r
3942 return EFI_INVALID_PARAMETER;\r
3943 }\r
3944\r
3945 gUserInput = UserInputData;\r
3946 gFormData = FormData;\r
3947\r
3948 //\r
3949 // Process the status info first.\r
3950 //\r
3951 BrowserStatusProcess();\r
4d4deaac 3952 if (gFormData->BrowserStatus != BROWSER_SUCCESS) {\r
7c6c064c 3953 //\r
4d4deaac 3954 // gFormData->BrowserStatus != BROWSER_SUCCESS, means only need to print the error info, return here.\r
7c6c064c
ED
3955 //\r
3956 return EFI_SUCCESS;\r
3957 }\r
3958\r
7c6c064c
ED
3959 Status = DisplayPageFrame (FormData, &gStatementDimensions);\r
3960 if (EFI_ERROR (Status)) {\r
3961 return Status;\r
3962 }\r
3963\r
c4866c77
SEHM
3964 //\r
3965 // Global Widths should be initialized before any MenuOption creation\r
3966 // or the GetWidth() used in UiAddMenuOption() will return incorrect value.\r
3967 //\r
3968 //\r
3969 // Left right\r
3970 // |<-.->|<-.........->|<- .........->|<-...........->|\r
3971 // Skip Prompt Option Help \r
3972 //\r
3973 gOptionBlockWidth = (CHAR16) ((gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 3) + 1;\r
3974 gHelpBlockWidth = (CHAR16) (gOptionBlockWidth - 1 - LEFT_SKIPPED_COLUMNS);\r
3975 gPromptBlockWidth = (CHAR16) (gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * (gOptionBlockWidth - 1) - 1);\r
3976\r
3977 ConvertStatementToMenu();\r
3978\r
5a9f73bf
ED
3979 //\r
3980 // Check whether layout is changed.\r
3981 //\r
3982 if (mIsFirstForm \r
3983 || (gOldFormEntry.HiiHandle != FormData->HiiHandle)\r
3984 || (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid))\r
3985 || (gOldFormEntry.FormId != FormData->FormId)) {\r
7c6c064c 3986 mStatementLayoutIsChanged = TRUE;\r
5a9f73bf
ED
3987 } else {\r
3988 mStatementLayoutIsChanged = FALSE;\r
7c6c064c
ED
3989 }\r
3990\r
3991 Status = UiDisplayMenu(FormData);\r
5a9f73bf
ED
3992 \r
3993 //\r
3994 // Backup last form info.\r
3995 //\r
3996 mIsFirstForm = FALSE;\r
3997 gOldFormEntry.HiiHandle = FormData->HiiHandle;\r
3998 CopyGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid);\r
3999 gOldFormEntry.FormId = FormData->FormId;\r
7c6c064c
ED
4000\r
4001 return Status;\r
4002}\r
4003\r
5a9f73bf
ED
4004/**\r
4005 Clear Screen to the initial state.\r
4006**/\r
4007VOID\r
4008EFIAPI \r
4009DriverClearDisplayPage (\r
4010 VOID\r
4011 )\r
4012{\r
4013 ClearDisplayPage ();\r
4014 mIsFirstForm = TRUE;\r
4015}\r
4016\r
4017/**\r
4018 Set Buffer to Value for Size bytes.\r
4019\r
4020 @param Buffer Memory to set.\r
4021 @param Size Number of bytes to set\r
4022 @param Value Value of the set operation.\r
4023\r
4024**/\r
4025VOID\r
4026SetUnicodeMem (\r
4027 IN VOID *Buffer,\r
4028 IN UINTN Size,\r
4029 IN CHAR16 Value\r
4030 )\r
4031{\r
4032 CHAR16 *Ptr;\r
4033\r
4034 Ptr = Buffer;\r
4035 while ((Size--) != 0) {\r
4036 *(Ptr++) = Value;\r
4037 }\r
4038}\r
4039\r
7c6c064c
ED
4040/**\r
4041 Initialize Setup Browser driver.\r
4042\r
4043 @param ImageHandle The image handle.\r
4044 @param SystemTable The system table.\r
4045\r
4046 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..\r
4047 @return Other value if failed to initialize the Setup Browser module.\r
4048\r
4049**/\r
4050EFI_STATUS\r
4051EFIAPI\r
4052InitializeDisplayEngine (\r
4053 IN EFI_HANDLE ImageHandle,\r
4054 IN EFI_SYSTEM_TABLE *SystemTable\r
4055 )\r
4056{\r
4057 EFI_STATUS Status;\r
4058 EFI_INPUT_KEY HotKey;\r
4059 EFI_STRING NewString;\r
4060 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;\r
4061\r
4062 //\r
4063 // Publish our HII data\r
4064 //\r
4065 gHiiHandle = HiiAddPackages (\r
4066 &gDisplayEngineGuid,\r
4067 ImageHandle,\r
4068 DisplayEngineStrings,\r
4069 NULL\r
4070 );\r
4071 ASSERT (gHiiHandle != NULL);\r
4072\r
4073 //\r
4074 // Install Form Display protocol\r
4075 //\r
4076 Status = gBS->InstallProtocolInterface (\r
4077 &mPrivateData.Handle,\r
4078 &gEdkiiFormDisplayEngineProtocolGuid,\r
4079 EFI_NATIVE_INTERFACE,\r
4080 &mPrivateData.FromDisplayProt\r
4081 );\r
4082 ASSERT_EFI_ERROR (Status);\r
4083\r
4084 InitializeDisplayStrings();\r
5a9f73bf
ED
4085 \r
4086 ZeroMem (&gHighligthMenuInfo, sizeof (gHighligthMenuInfo));\r
4087 ZeroMem (&gOldFormEntry, sizeof (gOldFormEntry));\r
7c6c064c
ED
4088\r
4089 //\r
4090 // Use BrowserEx2 protocol to register HotKey.\r
4091 // \r
4092 Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **) &FormBrowserEx2);\r
4093 if (!EFI_ERROR (Status)) {\r
4094 //\r
4095 // Register the default HotKey F9 and F10 again.\r
4096 //\r
4097 HotKey.UnicodeChar = CHAR_NULL;\r
4098 HotKey.ScanCode = SCAN_F10;\r
4099 NewString = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_TEN_STRING), NULL);\r
4100 ASSERT (NewString != NULL);\r
4101 FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_SUBMIT, 0, NewString);\r
4102\r
4103 HotKey.ScanCode = SCAN_F9;\r
4104 NewString = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_NINE_STRING), NULL);\r
4105 ASSERT (NewString != NULL);\r
4106 FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, NewString);\r
4107 }\r
4108\r
4109 return EFI_SUCCESS;\r
4110}\r
4111\r
4112/**\r
4113 This is the default unload handle for display core drivers.\r
4114\r
4115 @param[in] ImageHandle The drivers' driver image.\r
4116\r
4117 @retval EFI_SUCCESS The image is unloaded.\r
4118 @retval Others Failed to unload the image.\r
4119\r
4120**/\r
4121EFI_STATUS\r
4122EFIAPI\r
4123UnloadDisplayEngine (\r
4124 IN EFI_HANDLE ImageHandle\r
4125 )\r
4126{\r
4127 HiiRemovePackages(gHiiHandle);\r
4128\r
4129 FreeDisplayStrings ();\r
4130\r
42645c3d
ED
4131 if (gHighligthMenuInfo.HLTOpCode != NULL) {\r
4132 FreePool (gHighligthMenuInfo.HLTOpCode);\r
4133 }\r
4134\r
4135 if (gHighligthMenuInfo.TOSOpCode != NULL) {\r
4136 FreePool (gHighligthMenuInfo.TOSOpCode);\r
336c8e11
ED
4137 }\r
4138\r
7c6c064c
ED
4139 return EFI_SUCCESS;\r
4140}\r