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