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