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