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