]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
Add support for newly defined Browser action type EFI_BROWSER_ACTION_FORM_OPEN and...
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
CommitLineData
7936fb6a 1/** @file\r
2Utility functions for User Interface functions.\r
3\r
d66e6c16 4Copyright (c) 2004 - 2009, Intel Corporation\r
7936fb6a 5All rights reserved. This 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 "Ui.h"\r
16#include "Setup.h"\r
17\r
18LIST_ENTRY Menu;\r
d66e6c16 19LIST_ENTRY gMenuList = INITIALIZE_LIST_HEAD_VARIABLE (gMenuList);\r
7936fb6a 20MENU_REFRESH_ENTRY *gMenuRefreshHead;\r
21\r
22//\r
23// Search table for UiDisplayMenu()\r
24//\r
25SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {\r
26 {\r
27 SCAN_UP,\r
28 UiUp,\r
29 },\r
30 {\r
31 SCAN_DOWN,\r
32 UiDown,\r
33 },\r
34 {\r
35 SCAN_PAGE_UP,\r
36 UiPageUp,\r
37 },\r
38 {\r
39 SCAN_PAGE_DOWN,\r
40 UiPageDown,\r
41 },\r
42 {\r
43 SCAN_ESC,\r
44 UiReset,\r
45 },\r
7936fb6a 46 {\r
47 SCAN_LEFT,\r
48 UiLeft,\r
49 },\r
50 {\r
51 SCAN_RIGHT,\r
52 UiRight,\r
53 },\r
54 {\r
55 SCAN_F9,\r
56 UiDefault,\r
57 },\r
58 {\r
59 SCAN_F10,\r
60 UiSave\r
61 }\r
62};\r
63\r
64SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {\r
65 {\r
66 UiNoOperation,\r
67 CfUiNoOperation,\r
68 },\r
69 {\r
70 UiDefault,\r
71 CfUiDefault,\r
72 },\r
73 {\r
74 UiSelect,\r
75 CfUiSelect,\r
76 },\r
77 {\r
78 UiUp,\r
79 CfUiUp,\r
80 },\r
81 {\r
82 UiDown,\r
83 CfUiDown,\r
84 },\r
85 {\r
86 UiLeft,\r
87 CfUiLeft,\r
88 },\r
89 {\r
90 UiRight,\r
91 CfUiRight,\r
92 },\r
93 {\r
94 UiReset,\r
95 CfUiReset,\r
96 },\r
97 {\r
98 UiSave,\r
99 CfUiSave,\r
100 },\r
7936fb6a 101 {\r
102 UiPageUp,\r
103 CfUiPageUp,\r
104 },\r
105 {\r
106 UiPageDown,\r
107 CfUiPageDown\r
108 }\r
109};\r
110\r
19b15d63 111BOOLEAN mInputError;\r
aa79b0b3 112BOOLEAN GetLineByWidthFinished = FALSE;\r
19b15d63 113\r
7936fb6a 114\r
115/**\r
116 Set Buffer to Value for Size bytes.\r
117\r
118 @param Buffer Memory to set.\r
119 @param Size Number of bytes to set\r
120 @param Value Value of the set operation.\r
121\r
122**/\r
123VOID\r
124SetUnicodeMem (\r
125 IN VOID *Buffer,\r
126 IN UINTN Size,\r
127 IN CHAR16 Value\r
128 )\r
129{\r
130 CHAR16 *Ptr;\r
131\r
132 Ptr = Buffer;\r
133 while ((Size--) != 0) {\r
134 *(Ptr++) = Value;\r
135 }\r
136}\r
137\r
138\r
139/**\r
140 Initialize Menu option list.\r
141\r
142**/\r
143VOID\r
144UiInitMenu (\r
145 VOID\r
146 )\r
147{\r
148 InitializeListHead (&Menu);\r
149}\r
150\r
151\r
152/**\r
d66e6c16 153 Free Menu option linked list.\r
7936fb6a 154\r
155**/\r
156VOID\r
d66e6c16 157UiFreeMenu (\r
7936fb6a 158 VOID\r
159 )\r
160{\r
d66e6c16 161 UI_MENU_OPTION *MenuOption;\r
162\r
163 while (!IsListEmpty (&Menu)) {\r
164 MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink);\r
165 RemoveEntryList (&MenuOption->Link);\r
166\r
167 //\r
168 // We allocated space for this description when we did a GetToken, free it here\r
169 //\r
170 if (MenuOption->Skip != 0) {\r
171 //\r
172 // For date/time, MenuOption->Description is shared by three Menu Options\r
173 // Data format : [01/02/2004] [11:22:33]\r
174 // Line number : 0 0 1 0 0 1\r
175 //\r
176 FreePool (MenuOption->Description);\r
177 }\r
178 FreePool (MenuOption);\r
179 }\r
7936fb6a 180}\r
181\r
182\r
183/**\r
d66e6c16 184 Create a menu with specified formset GUID and form ID, and add it as a child\r
185 of the given parent menu.\r
7936fb6a 186\r
d66e6c16 187 @param Parent The parent of menu to be added.\r
188 @param FormSetGuid The Formset Guid of menu to be added.\r
189 @param FormId The Form ID of menu to be added.\r
190\r
191 @return A pointer to the newly added menu or NULL if memory is insufficient.\r
7936fb6a 192\r
193**/\r
d66e6c16 194UI_MENU_LIST *\r
195UiAddMenuList (\r
196 IN OUT UI_MENU_LIST *Parent,\r
197 IN EFI_GUID *FormSetGuid,\r
198 IN UINT16 FormId\r
7936fb6a 199 )\r
200{\r
d66e6c16 201 UI_MENU_LIST *MenuList;\r
7936fb6a 202\r
d66e6c16 203 MenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));\r
204 if (MenuList == NULL) {\r
205 return NULL;\r
7936fb6a 206 }\r
7936fb6a 207\r
d66e6c16 208 MenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
209 InitializeListHead (&MenuList->ChildListHead);\r
7936fb6a 210\r
d66e6c16 211 CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));\r
212 MenuList->FormId = FormId;\r
213 MenuList->Parent = Parent;\r
7936fb6a 214\r
d66e6c16 215 if (Parent == NULL) {\r
216 //\r
217 // If parent is not specified, it is the root Form of a Formset\r
218 //\r
219 InsertTailList (&gMenuList, &MenuList->Link);\r
220 } else {\r
221 InsertTailList (&Parent->ChildListHead, &MenuList->Link);\r
7936fb6a 222 }\r
d66e6c16 223\r
224 return MenuList;\r
7936fb6a 225}\r
226\r
227\r
228/**\r
d66e6c16 229 Search Menu with given FormId in the parent menu and all its child menus.\r
7936fb6a 230\r
d66e6c16 231 @param Parent The parent of menu to search.\r
232 @param FormId The Form ID of menu to search.\r
233\r
234 @return A pointer to menu found or NULL if not found.\r
7936fb6a 235\r
236**/\r
d66e6c16 237UI_MENU_LIST *\r
238UiFindChildMenuList (\r
239 IN UI_MENU_LIST *Parent,\r
240 IN UINT16 FormId\r
7936fb6a 241 )\r
242{\r
d66e6c16 243 LIST_ENTRY *Link;\r
244 UI_MENU_LIST *Child;\r
245 UI_MENU_LIST *MenuList;\r
246\r
247 if (Parent->FormId == FormId) {\r
248 return Parent;\r
249 }\r
7936fb6a 250\r
d66e6c16 251 Link = GetFirstNode (&Parent->ChildListHead);\r
252 while (!IsNull (&Parent->ChildListHead, Link)) {\r
253 Child = UI_MENU_LIST_FROM_LINK (Link);\r
7936fb6a 254\r
d66e6c16 255 MenuList = UiFindChildMenuList (Child, FormId);\r
256 if (MenuList != NULL) {\r
257 return MenuList;\r
258 }\r
7936fb6a 259\r
d66e6c16 260 Link = GetNextNode (&Parent->ChildListHead, Link);\r
261 }\r
262\r
263 return NULL;\r
7936fb6a 264}\r
265\r
266\r
267/**\r
d66e6c16 268 Search Menu with given FormSetGuid and FormId in all cached menu list.\r
269\r
270 @param FormSetGuid The Formset GUID of the menu to search.\r
271 @param FormId The Form ID of menu to search.\r
272\r
273 @return A pointer to menu found or NULL if not found.\r
7936fb6a 274\r
275**/\r
d66e6c16 276UI_MENU_LIST *\r
277UiFindMenuList (\r
278 IN EFI_GUID *FormSetGuid,\r
279 IN UINT16 FormId\r
7936fb6a 280 )\r
281{\r
d66e6c16 282 LIST_ENTRY *Link;\r
283 UI_MENU_LIST *MenuList;\r
284 UI_MENU_LIST *Child;\r
7936fb6a 285\r
d66e6c16 286 Link = GetFirstNode (&gMenuList);\r
287 while (!IsNull (&gMenuList, Link)) {\r
288 MenuList = UI_MENU_LIST_FROM_LINK (Link);\r
7936fb6a 289\r
d66e6c16 290 if (CompareGuid (FormSetGuid, &MenuList->FormSetGuid)) {\r
7936fb6a 291 //\r
d66e6c16 292 // This is the formset we are looking for, find the form in this formset\r
7936fb6a 293 //\r
d66e6c16 294 Child = UiFindChildMenuList (MenuList, FormId);\r
295 if (Child != NULL) {\r
296 return Child;\r
297 }\r
7936fb6a 298 }\r
d66e6c16 299\r
300 Link = GetNextNode (&gMenuList, Link);\r
7936fb6a 301 }\r
d66e6c16 302\r
303 return NULL;\r
7936fb6a 304}\r
305\r
306\r
307/**\r
308 Free Menu option linked list.\r
309\r
310**/\r
311VOID\r
312UiFreeRefreshList (\r
313 VOID\r
314 )\r
315{\r
316 MENU_REFRESH_ENTRY *OldMenuRefreshEntry;\r
317\r
318 while (gMenuRefreshHead != NULL) {\r
319 OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
f4113e1f 320 FreePool (gMenuRefreshHead);\r
7936fb6a 321 gMenuRefreshHead = OldMenuRefreshEntry;\r
322 }\r
323\r
324 gMenuRefreshHead = NULL;\r
325}\r
326\r
327\r
328\r
329/**\r
330 Refresh screen.\r
331\r
332**/\r
8d00a0f1 333EFI_STATUS\r
7936fb6a 334RefreshForm (\r
335 VOID\r
336 )\r
337{\r
8d00a0f1 338 CHAR16 *OptionString;\r
339 MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
340 UINTN Index;\r
341 EFI_STATUS Status;\r
342 UI_MENU_SELECTION *Selection;\r
343 FORM_BROWSER_STATEMENT *Question;\r
344 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
345 EFI_HII_VALUE *HiiValue;\r
346 EFI_BROWSER_ACTION_REQUEST ActionRequest;\r
7936fb6a 347\r
348 if (gMenuRefreshHead != NULL) {\r
349\r
350 MenuRefreshEntry = gMenuRefreshHead;\r
351\r
8d00a0f1 352 //\r
353 // Reset FormPackage update flag\r
354 //\r
355 mHiiPackageListUpdated = FALSE;\r
356\r
7936fb6a 357 do {\r
358 gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
359\r
360 Selection = MenuRefreshEntry->Selection;\r
361 Question = MenuRefreshEntry->MenuOption->ThisTag;\r
362\r
8d00a0f1 363 Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\r
364 if (EFI_ERROR (Status)) {\r
365 return Status;\r
366 }\r
367\r
368 OptionString = NULL;\r
369 ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString);\r
370\r
371 if (OptionString != NULL) {\r
372 //\r
373 // If leading spaces on OptionString - remove the spaces\r
374 //\r
375 for (Index = 0; OptionString[Index] == L' '; Index++)\r
376 ;\r
377\r
378 PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, &OptionString[Index]);\r
f4113e1f 379 FreePool (OptionString);\r
8d00a0f1 380 }\r
381\r
7936fb6a 382 //\r
8d00a0f1 383 // Question value may be changed, need invoke its Callback()\r
7936fb6a 384 //\r
8d00a0f1 385 ConfigAccess = Selection->FormSet->ConfigAccess;\r
7064c0a5 386 if (((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {\r
8d00a0f1 387 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
7936fb6a 388\r
8d00a0f1 389 HiiValue = &Question->HiiValue;\r
390 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
391 //\r
392 // Create String in HII database for Configuration Driver to retrieve\r
393 //\r
394 HiiValue->Value.string = NewString ((CHAR16 *) Question->BufferValue, Selection->FormSet->HiiHandle);\r
7936fb6a 395 }\r
396\r
8d00a0f1 397 Status = ConfigAccess->Callback (\r
398 ConfigAccess,\r
399 EFI_BROWSER_ACTION_CHANGING,\r
400 Question->QuestionId,\r
401 HiiValue->Type,\r
402 &HiiValue->Value,\r
403 &ActionRequest\r
404 );\r
7936fb6a 405\r
8d00a0f1 406 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
7936fb6a 407 //\r
8d00a0f1 408 // Clean the String in HII Database\r
7936fb6a 409 //\r
8d00a0f1 410 DeleteString (HiiValue->Value.string, Selection->FormSet->HiiHandle);\r
411 }\r
7936fb6a 412\r
8d00a0f1 413 if (!EFI_ERROR (Status)) {\r
414 switch (ActionRequest) {\r
415 case EFI_BROWSER_ACTION_REQUEST_RESET:\r
416 gResetRequired = TRUE;\r
417 break;\r
7936fb6a 418\r
8d00a0f1 419 case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
420 SubmitForm (Selection->FormSet, Selection->Form);\r
421 break;\r
7936fb6a 422\r
8d00a0f1 423 case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
424 Selection->Action = UI_ACTION_EXIT;\r
425 gNvUpdateRequired = FALSE;\r
426 break;\r
427\r
428 default:\r
429 break;\r
430 }\r
7936fb6a 431 }\r
432 }\r
433\r
434 MenuRefreshEntry = MenuRefreshEntry->Next;\r
435\r
436 } while (MenuRefreshEntry != NULL);\r
8d00a0f1 437\r
438 if (mHiiPackageListUpdated) {\r
439 //\r
440 // Package list is updated, force to reparse IFR binary of target Formset\r
441 //\r
442 mHiiPackageListUpdated = FALSE;\r
443 Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
444 return EFI_SUCCESS;\r
445 }\r
7936fb6a 446 }\r
8d00a0f1 447\r
448 return EFI_TIMEOUT;\r
7936fb6a 449}\r
450\r
451\r
452/**\r
453 Wait for a given event to fire, or for an optional timeout to expire.\r
454\r
455 @param Event The event to wait for\r
456 @param Timeout An optional timeout value in 100 ns units.\r
457 @param RefreshInterval Menu refresh interval (in seconds).\r
458\r
459 @retval EFI_SUCCESS Event fired before Timeout expired.\r
460 @retval EFI_TIME_OUT Timout expired before Event fired.\r
461\r
462**/\r
463EFI_STATUS\r
464UiWaitForSingleEvent (\r
465 IN EFI_EVENT Event,\r
466 IN UINT64 Timeout, OPTIONAL\r
467 IN UINT8 RefreshInterval OPTIONAL\r
468 )\r
469{\r
470 EFI_STATUS Status;\r
471 UINTN Index;\r
472 EFI_EVENT TimerEvent;\r
473 EFI_EVENT WaitList[2];\r
474\r
475 if (Timeout != 0) {\r
476 //\r
477 // Create a timer event\r
478 //\r
479 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
480 if (!EFI_ERROR (Status)) {\r
481 //\r
482 // Set the timer event\r
483 //\r
484 gBS->SetTimer (\r
485 TimerEvent,\r
486 TimerRelative,\r
487 Timeout\r
488 );\r
489\r
490 //\r
491 // Wait for the original event or the timer\r
492 //\r
493 WaitList[0] = Event;\r
494 WaitList[1] = TimerEvent;\r
495 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
496 gBS->CloseEvent (TimerEvent);\r
497\r
498 //\r
499 // If the timer expired, change the return to timed out\r
500 //\r
501 if (!EFI_ERROR (Status) && Index == 1) {\r
502 Status = EFI_TIMEOUT;\r
503 }\r
504 }\r
505 } else {\r
506 //\r
507 // Update screen every second\r
508 //\r
509 if (RefreshInterval == 0) {\r
510 Timeout = ONE_SECOND;\r
511 } else {\r
512 Timeout = RefreshInterval * ONE_SECOND;\r
513 }\r
514\r
515 do {\r
516 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
517\r
518 //\r
519 // Set the timer event\r
520 //\r
521 gBS->SetTimer (\r
522 TimerEvent,\r
523 TimerRelative,\r
524 Timeout\r
525 );\r
526\r
527 //\r
528 // Wait for the original event or the timer\r
529 //\r
530 WaitList[0] = Event;\r
531 WaitList[1] = TimerEvent;\r
532 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
533\r
534 //\r
535 // If the timer expired, update anything that needs a refresh and keep waiting\r
536 //\r
537 if (!EFI_ERROR (Status) && Index == 1) {\r
538 Status = EFI_TIMEOUT;\r
539 if (RefreshInterval != 0) {\r
8d00a0f1 540 Status = RefreshForm ();\r
7936fb6a 541 }\r
542 }\r
543\r
544 gBS->CloseEvent (TimerEvent);\r
545 } while (Status == EFI_TIMEOUT);\r
546 }\r
547\r
548 return Status;\r
549}\r
550\r
551\r
552/**\r
553 Add one menu option by specified description and context.\r
554\r
555 @param String String description for this option.\r
556 @param Handle Hii handle for the package list.\r
557 @param Statement Statement of this Menu Option.\r
558 @param NumberOfLines Display lines for this Menu Option.\r
559 @param MenuItemCount The index for this Option in the Menu.\r
560\r
561**/\r
562VOID\r
563UiAddMenuOption (\r
564 IN CHAR16 *String,\r
565 IN EFI_HII_HANDLE Handle,\r
566 IN FORM_BROWSER_STATEMENT *Statement,\r
567 IN UINT16 NumberOfLines,\r
568 IN UINT16 MenuItemCount\r
569 )\r
570{\r
571 UI_MENU_OPTION *MenuOption;\r
572 UINTN Index;\r
573 UINTN Count;\r
574\r
575 Count = 1;\r
576\r
577 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
578 //\r
579 // Add three MenuOptions for Date/Time\r
580 // Data format : [01/02/2004] [11:22:33]\r
581 // Line number : 0 0 1 0 0 1\r
582 //\r
583 NumberOfLines = 0;\r
584 Count = 3;\r
585\r
586 if (Statement->Storage == NULL) {\r
587 //\r
588 // For RTC type of date/time, set default refresh interval to be 1 second\r
589 //\r
590 if (Statement->RefreshInterval == 0) {\r
591 Statement->RefreshInterval = 1;\r
592 }\r
593 }\r
594 }\r
595\r
596 for (Index = 0; Index < Count; Index++) {\r
597 MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
598 ASSERT (MenuOption);\r
599\r
600 MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;\r
601 MenuOption->Description = String;\r
602 MenuOption->Handle = Handle;\r
603 MenuOption->ThisTag = Statement;\r
604 MenuOption->EntryNumber = MenuItemCount;\r
605\r
606 if (Index == 2) {\r
607 //\r
608 // Override LineNumber for the MenuOption in Date/Time sequence\r
609 //\r
610 MenuOption->Skip = 1;\r
611 } else {\r
612 MenuOption->Skip = NumberOfLines;\r
613 }\r
614 MenuOption->Sequence = Index;\r
615\r
616 if (Statement->GrayOutExpression != NULL) {\r
617 MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;\r
618 }\r
619\r
620 if ((Statement->ValueExpression != NULL) ||\r
621 ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {\r
622 MenuOption->ReadOnly = TRUE;\r
623 }\r
624\r
625 InsertTailList (&Menu, &MenuOption->Link);\r
626 }\r
627}\r
628\r
629\r
630/**\r
631 Routine used to abstract a generic dialog interface and return the selected key or string\r
632\r
633 @param NumberOfLines The number of lines for the dialog box\r
634 @param HotKey Defines whether a single character is parsed\r
635 (TRUE) and returned in KeyValue or a string is\r
636 returned in StringBuffer. Two special characters\r
637 are considered when entering a string, a SCAN_ESC\r
638 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates\r
639 string input and returns\r
640 @param MaximumStringSize The maximum size in bytes of a typed in string\r
641 (each character is a CHAR16) and the minimum\r
642 string returned is two bytes\r
643 @param StringBuffer The passed in pointer to the buffer which will\r
644 hold the typed in string if HotKey is FALSE\r
645 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..\r
7936fb6a 646 @param ... A series of (quantity == NumberOfLines) text\r
647 strings which will be used to construct the dialog\r
648 box\r
649\r
650 @retval EFI_SUCCESS Displayed dialog and received user interaction\r
651 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.\r
652 (StringBuffer == NULL) && (HotKey == FALSE))\r
653 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine\r
654\r
655**/\r
656EFI_STATUS\r
657CreateDialog (\r
658 IN UINTN NumberOfLines,\r
659 IN BOOLEAN HotKey,\r
660 IN UINTN MaximumStringSize,\r
661 OUT CHAR16 *StringBuffer,\r
662 OUT EFI_INPUT_KEY *KeyValue,\r
7936fb6a 663 ...\r
664 )\r
665{\r
666 VA_LIST Marker;\r
667 UINTN Count;\r
668 EFI_INPUT_KEY Key;\r
669 UINTN LargestString;\r
670 CHAR16 *TempString;\r
671 CHAR16 *BufferedString;\r
672 CHAR16 *StackString;\r
673 CHAR16 KeyPad[2];\r
674 UINTN Start;\r
675 UINTN Top;\r
676 UINTN Index;\r
677 EFI_STATUS Status;\r
678 BOOLEAN SelectionComplete;\r
679 UINTN InputOffset;\r
680 UINTN CurrentAttribute;\r
681 UINTN DimensionsWidth;\r
682 UINTN DimensionsHeight;\r
683\r
684 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
685 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
686\r
687 SelectionComplete = FALSE;\r
688 InputOffset = 0;\r
689 TempString = AllocateZeroPool (MaximumStringSize * 2);\r
690 BufferedString = AllocateZeroPool (MaximumStringSize * 2);\r
691 CurrentAttribute = gST->ConOut->Mode->Attribute;\r
692\r
693 ASSERT (TempString);\r
694 ASSERT (BufferedString);\r
695\r
f4bcc90f 696 VA_START (Marker, KeyValue);\r
7936fb6a 697\r
698 //\r
699 // Zero the outgoing buffer\r
700 //\r
701 ZeroMem (StringBuffer, MaximumStringSize);\r
702\r
703 if (HotKey) {\r
704 if (KeyValue == NULL) {\r
705 return EFI_INVALID_PARAMETER;\r
706 }\r
707 } else {\r
708 if (StringBuffer == NULL) {\r
709 return EFI_INVALID_PARAMETER;\r
710 }\r
711 }\r
712 //\r
713 // Disable cursor\r
714 //\r
715 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
716\r
f4bcc90f 717 LargestString = 0;\r
7936fb6a 718\r
7936fb6a 719 //\r
720 // Determine the largest string in the dialog box\r
721 // Notice we are starting with 1 since String is the first string\r
722 //\r
f4bcc90f 723 for (Count = 0; Count < NumberOfLines; Count++) {\r
7936fb6a 724 StackString = VA_ARG (Marker, CHAR16 *);\r
725\r
726 if (StackString[0] == L' ') {\r
727 InputOffset = Count + 1;\r
728 }\r
729\r
730 if ((GetStringWidth (StackString) / 2) > LargestString) {\r
731 //\r
732 // Size of the string visually and subtract the width by one for the null-terminator\r
733 //\r
734 LargestString = (GetStringWidth (StackString) / 2);\r
735 }\r
736 }\r
1c9a7554 737 VA_END (Marker);\r
7936fb6a 738\r
739 Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
740 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
741\r
742 Count = 0;\r
743\r
744 //\r
745 // Display the Popup\r
746 //\r
1c9a7554 747 VA_START (Marker, KeyValue);\r
748 CreateSharedPopUp (LargestString, NumberOfLines, Marker);\r
749 VA_END (Marker);\r
7936fb6a 750\r
751 //\r
752 // Take the first key typed and report it back?\r
753 //\r
754 if (HotKey) {\r
755 Status = WaitForKeyStroke (&Key);\r
756 ASSERT_EFI_ERROR (Status);\r
757 CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));\r
758\r
759 } else {\r
760 do {\r
761 Status = WaitForKeyStroke (&Key);\r
762\r
763 switch (Key.UnicodeChar) {\r
764 case CHAR_NULL:\r
765 switch (Key.ScanCode) {\r
766 case SCAN_ESC:\r
f4113e1f 767 FreePool (TempString);\r
768 FreePool (BufferedString);\r
7936fb6a 769 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
770 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
771 return EFI_DEVICE_ERROR;\r
772\r
773 default:\r
774 break;\r
775 }\r
776\r
777 break;\r
778\r
779 case CHAR_CARRIAGE_RETURN:\r
780 SelectionComplete = TRUE;\r
f4113e1f 781 FreePool (TempString);\r
782 FreePool (BufferedString);\r
7936fb6a 783 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
784 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
785 return EFI_SUCCESS;\r
786 break;\r
787\r
788 case CHAR_BACKSPACE:\r
789 if (StringBuffer[0] != CHAR_NULL) {\r
790 for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) {\r
791 TempString[Index] = StringBuffer[Index];\r
792 }\r
793 //\r
794 // Effectively truncate string by 1 character\r
795 //\r
796 TempString[Index - 1] = CHAR_NULL;\r
797 StrCpy (StringBuffer, TempString);\r
798 }\r
799\r
800 default:\r
801 //\r
802 // If it is the beginning of the string, don't worry about checking maximum limits\r
803 //\r
804 if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
805 StrnCpy (StringBuffer, &Key.UnicodeChar, 1);\r
806 StrnCpy (TempString, &Key.UnicodeChar, 1);\r
807 } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
808 KeyPad[0] = Key.UnicodeChar;\r
809 KeyPad[1] = CHAR_NULL;\r
810 StrCat (StringBuffer, KeyPad);\r
811 StrCat (TempString, KeyPad);\r
812 }\r
813 //\r
814 // If the width of the input string is now larger than the screen, we nee to\r
815 // adjust the index to start printing portions of the string\r
816 //\r
817 SetUnicodeMem (BufferedString, LargestString, L' ');\r
818\r
819 PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
820\r
821 if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) {\r
822 Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2;\r
823 } else {\r
824 Index = 0;\r
825 }\r
826\r
827 for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) {\r
828 BufferedString[Count] = StringBuffer[Index];\r
829 }\r
830\r
831 PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
832 break;\r
833 }\r
834 } while (!SelectionComplete);\r
835 }\r
836\r
837 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
838 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
839 return EFI_SUCCESS;\r
840}\r
841\r
842/**\r
843 Draw a pop up windows based on the dimension, number of lines and\r
844 strings specified.\r
845\r
846 @param RequestedWidth The width of the pop-up.\r
847 @param NumberOfLines The number of lines.\r
f4bcc90f 848 @param Marker The variable argument list for the list of string to be printed.\r
7936fb6a 849\r
850**/\r
851VOID\r
852CreateSharedPopUp (\r
853 IN UINTN RequestedWidth,\r
854 IN UINTN NumberOfLines,\r
f4bcc90f 855 IN VA_LIST Marker\r
7936fb6a 856 )\r
857{\r
858 UINTN Index;\r
859 UINTN Count;\r
860 CHAR16 Character;\r
861 UINTN Start;\r
862 UINTN End;\r
863 UINTN Top;\r
864 UINTN Bottom;\r
865 CHAR16 *String;\r
866 UINTN DimensionsWidth;\r
867 UINTN DimensionsHeight;\r
868\r
869 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
870 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
871\r
7936fb6a 872 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
873\r
874 if ((RequestedWidth + 2) > DimensionsWidth) {\r
875 RequestedWidth = DimensionsWidth - 2;\r
876 }\r
877\r
878 //\r
879 // Subtract the PopUp width from total Columns, allow for one space extra on\r
880 // each end plus a border.\r
881 //\r
882 Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
883 End = Start + RequestedWidth + 1;\r
884\r
885 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
886 Bottom = Top + NumberOfLines + 2;\r
887\r
888 Character = BOXDRAW_DOWN_RIGHT;\r
889 PrintCharAt (Start, Top, Character);\r
890 Character = BOXDRAW_HORIZONTAL;\r
891 for (Index = Start; Index + 2 < End; Index++) {\r
892 PrintChar (Character);\r
893 }\r
894\r
895 Character = BOXDRAW_DOWN_LEFT;\r
896 PrintChar (Character);\r
897 Character = BOXDRAW_VERTICAL;\r
f4bcc90f 898\r
899 Count = 0;\r
900 for (Index = Top; Index + 2 < Bottom; Index++, Count++) {\r
901 String = VA_ARG (Marker, CHAR16*);\r
7936fb6a 902\r
903 //\r
904 // This will clear the background of the line - we never know who might have been\r
905 // here before us. This differs from the next clear in that it used the non-reverse\r
906 // video for normal printing.\r
907 //\r
908 if (GetStringWidth (String) / 2 > 1) {\r
909 ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
910 }\r
911\r
912 //\r
913 // Passing in a space results in the assumption that this is where typing will occur\r
914 //\r
915 if (String[0] == L' ') {\r
916 ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);\r
917 }\r
918\r
919 //\r
920 // Passing in a NULL results in a blank space\r
921 //\r
922 if (String[0] == CHAR_NULL) {\r
923 ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
924 }\r
925\r
926 PrintStringAt (\r
927 ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,\r
928 Index + 1,\r
929 String\r
930 );\r
931 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
932 PrintCharAt (Start, Index + 1, Character);\r
933 PrintCharAt (End - 1, Index + 1, Character);\r
934 }\r
935\r
936 Character = BOXDRAW_UP_RIGHT;\r
937 PrintCharAt (Start, Bottom - 1, Character);\r
938 Character = BOXDRAW_HORIZONTAL;\r
939 for (Index = Start; Index + 2 < End; Index++) {\r
940 PrintChar (Character);\r
941 }\r
942\r
943 Character = BOXDRAW_UP_LEFT;\r
944 PrintChar (Character);\r
945}\r
946\r
947/**\r
948 Draw a pop up windows based on the dimension, number of lines and\r
949 strings specified.\r
950\r
951 @param RequestedWidth The width of the pop-up.\r
952 @param NumberOfLines The number of lines.\r
7936fb6a 953 @param ... A series of text strings that displayed in the pop-up.\r
954\r
955**/\r
956VOID\r
3ebb9bdb 957CreateMultiStringPopUp (\r
7936fb6a 958 IN UINTN RequestedWidth,\r
959 IN UINTN NumberOfLines,\r
7936fb6a 960 ...\r
961 )\r
962{\r
f4bcc90f 963 VA_LIST Marker;\r
964\r
965 VA_START (Marker, NumberOfLines);\r
d66e6c16 966\r
f4bcc90f 967 CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);\r
968\r
969 VA_END (Marker);\r
7936fb6a 970}\r
971\r
972\r
973/**\r
974 Update status bar on the bottom of menu.\r
975\r
976 @param MessageType The type of message to be shown.\r
977 @param Flags The flags in Question header.\r
978 @param State Set or clear.\r
979\r
980**/\r
981VOID\r
982UpdateStatusBar (\r
983 IN UINTN MessageType,\r
984 IN UINT8 Flags,\r
985 IN BOOLEAN State\r
986 )\r
987{\r
988 UINTN Index;\r
7936fb6a 989 CHAR16 *NvUpdateMessage;\r
990 CHAR16 *InputErrorMessage;\r
991\r
992 NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle);\r
993 InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle);\r
994\r
995 switch (MessageType) {\r
996 case INPUT_ERROR:\r
997 if (State) {\r
998 gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);\r
999 PrintStringAt (\r
1000 gScreenDimensions.LeftColumn + gPromptBlockWidth,\r
1001 gScreenDimensions.BottomRow - 1,\r
1002 InputErrorMessage\r
1003 );\r
19b15d63 1004 mInputError = TRUE;\r
7936fb6a 1005 } else {\r
1006 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
1007 for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) {\r
1008 PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L" ");\r
1009 }\r
1010\r
19b15d63 1011 mInputError = FALSE;\r
7936fb6a 1012 }\r
1013 break;\r
1014\r
1015 case NV_UPDATE_REQUIRED:\r
0a1147ed 1016 if (gClassOfVfr != FORMSET_CLASS_FRONT_PAGE) {\r
7936fb6a 1017 if (State) {\r
1018 gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);\r
1019 PrintStringAt (\r
1020 gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth,\r
1021 gScreenDimensions.BottomRow - 1,\r
1022 NvUpdateMessage\r
1023 );\r
1024 gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
1025\r
1026 gNvUpdateRequired = TRUE;\r
1027 } else {\r
1028 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
1029 for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {\r
1030 PrintAt (\r
1031 (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),\r
1032 gScreenDimensions.BottomRow - 1,\r
1033 L" "\r
1034 );\r
1035 }\r
1036\r
1037 gNvUpdateRequired = FALSE;\r
1038 }\r
1039 }\r
1040 break;\r
1041\r
1042 case REFRESH_STATUS_BAR:\r
19b15d63 1043 if (mInputError) {\r
7936fb6a 1044 UpdateStatusBar (INPUT_ERROR, Flags, TRUE);\r
1045 }\r
1046\r
1047 if (gNvUpdateRequired) {\r
1048 UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);\r
1049 }\r
1050 break;\r
1051\r
1052 default:\r
1053 break;\r
1054 }\r
1055\r
f4113e1f 1056 FreePool (InputErrorMessage);\r
1057 FreePool (NvUpdateMessage);\r
7936fb6a 1058 return ;\r
1059}\r
1060\r
1061\r
1062/**\r
1063 Get the supported width for a particular op-code\r
1064\r
1065 @param Statement The FORM_BROWSER_STATEMENT structure passed in.\r
1066 @param Handle The handle in the HII database being used\r
1067\r
1068 @return Returns the number of CHAR16 characters that is support.\r
1069\r
1070**/\r
1071UINT16\r
1072GetWidth (\r
1073 IN FORM_BROWSER_STATEMENT *Statement,\r
1074 IN EFI_HII_HANDLE Handle\r
1075 )\r
1076{\r
1077 CHAR16 *String;\r
1078 UINTN Size;\r
1079 UINT16 Width;\r
1080\r
1081 Size = 0;\r
1082\r
1083 //\r
1084 // See if the second text parameter is really NULL\r
1085 //\r
1086 if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
1087 String = GetToken (Statement->TextTwo, Handle);\r
1088 Size = StrLen (String);\r
f4113e1f 1089 FreePool (String);\r
7936fb6a 1090 }\r
1091\r
1092 if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) ||\r
1093 (Statement->Operand == EFI_IFR_REF_OP) ||\r
1094 (Statement->Operand == EFI_IFR_PASSWORD_OP) ||\r
1095 (Statement->Operand == EFI_IFR_ACTION_OP) ||\r
1096 (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) ||\r
1097 //\r
1098 // Allow a wide display if text op-code and no secondary text op-code\r
1099 //\r
1100 ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0))\r
1101 ) {\r
1102 Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth);\r
1103 } else {\r
1104 Width = (UINT16) gPromptBlockWidth;\r
1105 }\r
1106\r
1107 if (Statement->InSubtitle) {\r
1108 Width -= SUBTITLE_INDENT;\r
1109 }\r
1110\r
1111 return Width;\r
1112}\r
1113\r
7936fb6a 1114/**\r
1115 Will copy LineWidth amount of a string in the OutputString buffer and return the\r
1116 number of CHAR16 characters that were copied into the OutputString buffer.\r
1117\r
1118 @param InputString String description for this option.\r
1119 @param LineWidth Width of the desired string to extract in CHAR16\r
1120 characters\r
1121 @param Index Where in InputString to start the copy process\r
1122 @param OutputString Buffer to copy the string into\r
1123\r
1124 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.\r
1125\r
1126**/\r
1127UINT16\r
1128GetLineByWidth (\r
1129 IN CHAR16 *InputString,\r
1130 IN UINT16 LineWidth,\r
1131 IN OUT UINTN *Index,\r
1132 OUT CHAR16 **OutputString\r
1133 )\r
1134{\r
1135 UINT16 Count;\r
1136 UINT16 Count2;\r
1137\r
1138 if (GetLineByWidthFinished) {\r
1139 GetLineByWidthFinished = FALSE;\r
1140 return (UINT16) 0;\r
1141 }\r
1142\r
1143 Count = LineWidth;\r
1144 Count2 = 0;\r
1145\r
1146 *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));\r
1147\r
1148 //\r
1149 // Ensure we have got a valid buffer\r
1150 //\r
1151 if (*OutputString != NULL) {\r
1152\r
1153 //\r
1154 //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
1155 //To avoid displaying this empty line in screen, just skip the two CHARs here.\r
1156 //\r
1157 if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
1158 *Index = *Index + 2;\r
1159 }\r
1160\r
1161 //\r
1162 // Fast-forward the string and see if there is a carriage-return in the string\r
1163 //\r
1164 for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++)\r
1165 ;\r
1166\r
1167 //\r
1168 // Copy the desired LineWidth of data to the output buffer.\r
1169 // Also make sure that we don't copy more than the string.\r
1170 // Also make sure that if there are linefeeds, we account for them.\r
1171 //\r
1172 if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&\r
1173 (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))\r
1174 ) {\r
1175 //\r
1176 // Convert to CHAR16 value and show that we are done with this operation\r
1177 //\r
1178 LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2);\r
1179 if (LineWidth != 0) {\r
1180 GetLineByWidthFinished = TRUE;\r
1181 }\r
1182 } else {\r
1183 if (Count2 == LineWidth) {\r
1184 //\r
1185 // Rewind the string from the maximum size until we see a space to break the line\r
1186 //\r
1187 for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--)\r
1188 ;\r
1189 if (LineWidth == 0) {\r
1190 LineWidth = Count;\r
1191 }\r
1192 } else {\r
1193 LineWidth = Count2;\r
1194 }\r
1195 }\r
1196\r
1197 CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);\r
1198\r
1199 //\r
1200 // If currently pointing to a space, increment the index to the first non-space character\r
1201 //\r
1202 for (;\r
1203 (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN);\r
1204 (*Index)++\r
1205 )\r
1206 ;\r
1207 *Index = (UINT16) (*Index + LineWidth);\r
1208 return LineWidth;\r
1209 } else {\r
1210 return (UINT16) 0;\r
1211 }\r
1212}\r
1213\r
1214\r
1215/**\r
1216 Update display lines for a Menu Option.\r
1217\r
1218 @param Selection The user's selection.\r
1219 @param MenuOption The MenuOption to be checked.\r
1220 @param OptionalString The option string.\r
1221 @param SkipValue The number of lins to skip.\r
1222\r
7936fb6a 1223**/\r
1224VOID\r
1225UpdateOptionSkipLines (\r
1226 IN UI_MENU_SELECTION *Selection,\r
1227 IN UI_MENU_OPTION *MenuOption,\r
1228 OUT CHAR16 **OptionalString,\r
1229 IN UINTN SkipValue\r
1230 )\r
1231{\r
1232 UINTN Index;\r
1233 UINT16 Width;\r
1234 UINTN Row;\r
1235 UINTN OriginalRow;\r
1236 CHAR16 *OutputString;\r
1237 CHAR16 *OptionString;\r
1238\r
1239 Row = 0;\r
1240 OptionString = *OptionalString;\r
1241 OutputString = NULL;\r
1242\r
1243 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
1244\r
1245 if (OptionString != NULL) {\r
1246 Width = (UINT16) gOptionBlockWidth;\r
1247\r
1248 OriginalRow = Row;\r
1249\r
1250 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1251 //\r
1252 // If there is more string to process print on the next row and increment the Skip value\r
1253 //\r
d1a54e2c 1254 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 1255 if (SkipValue == 0) {\r
1256 Row++;\r
1257 //\r
1258 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1259 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1260 // some testing to ensure we are keeping this in-sync.\r
1261 //\r
1262 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1263 //\r
1264 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1265 MenuOption->Skip++;\r
1266 }\r
1267 }\r
1268 }\r
1269\r
f4113e1f 1270 FreePool (OutputString);\r
7936fb6a 1271 if (SkipValue != 0) {\r
1272 SkipValue--;\r
1273 }\r
1274 }\r
1275\r
1276 Row = OriginalRow;\r
1277 }\r
1278\r
1279 *OptionalString = OptionString;\r
1280}\r
1281\r
1282\r
1283/**\r
1284 Check whether this Menu Option could be highlighted.\r
1285\r
1286 This is an internal function.\r
1287\r
1288 @param MenuOption The MenuOption to be checked.\r
1289\r
1290 @retval TRUE This Menu Option is selectable.\r
1291 @retval FALSE This Menu Option could not be selected.\r
1292\r
1293**/\r
1294BOOLEAN\r
1295IsSelectable (\r
1296 UI_MENU_OPTION *MenuOption\r
1297 )\r
1298{\r
1299 if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) ||\r
1300 MenuOption->GrayOut || MenuOption->ReadOnly) {\r
1301 return FALSE;\r
1302 } else {\r
1303 return TRUE;\r
1304 }\r
1305}\r
1306\r
1307\r
1308/**\r
1309 Determine if the menu is the last menu that can be selected.\r
1310\r
1311 This is an internal function.\r
d66e6c16 1312\r
7936fb6a 1313 @param Direction The scroll direction. False is down. True is up.\r
1314 @param CurrentPos The current focus.\r
1315\r
1316 @return FALSE -- the menu isn't the last menu that can be selected.\r
1317 @return TRUE -- the menu is the last menu that can be selected.\r
1318\r
1319**/\r
1320BOOLEAN\r
1321ValueIsScroll (\r
1322 IN BOOLEAN Direction,\r
1323 IN LIST_ENTRY *CurrentPos\r
1324 )\r
1325{\r
1326 LIST_ENTRY *Temp;\r
1327 UI_MENU_OPTION *MenuOption;\r
1328\r
1329 Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
1330\r
1331 if (Temp == &Menu) {\r
1332 return TRUE;\r
1333 }\r
1334\r
1335 for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {\r
1336 MenuOption = MENU_OPTION_FROM_LINK (Temp);\r
1337 if (IsSelectable (MenuOption)) {\r
1338 return FALSE;\r
1339 }\r
1340 }\r
1341\r
1342 return TRUE;\r
1343}\r
1344\r
1345\r
1346/**\r
1347 Move to next selectable statement.\r
d66e6c16 1348\r
7936fb6a 1349 This is an internal function.\r
d66e6c16 1350\r
7936fb6a 1351 @param GoUp The navigation direction. TRUE: up, FALSE: down.\r
1352 @param CurrentPosition Current position.\r
1353\r
1354 @return The row distance from current MenuOption to next selectable MenuOption.\r
1355\r
1356**/\r
1357INTN\r
1358MoveToNextStatement (\r
1359 IN BOOLEAN GoUp,\r
1360 IN OUT LIST_ENTRY **CurrentPosition\r
1361 )\r
1362{\r
1363 INTN Distance;\r
1364 LIST_ENTRY *Pos;\r
1365 BOOLEAN HitEnd;\r
1366 UI_MENU_OPTION *NextMenuOption;\r
1367\r
1368 Distance = 0;\r
1369 Pos = *CurrentPosition;\r
1370 HitEnd = FALSE;\r
1371\r
1372 while (TRUE) {\r
1373 NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
1374 if (IsSelectable (NextMenuOption)) {\r
1375 break;\r
1376 }\r
1377 if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {\r
1378 HitEnd = TRUE;\r
1379 break;\r
1380 }\r
1381 Distance += NextMenuOption->Skip;\r
1382 Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
1383 }\r
1384\r
1385 if (HitEnd) {\r
1386 //\r
1387 // If we hit end there is still no statement can be focused,\r
1388 // we go backwards to find the statement can be focused.\r
1389 //\r
1390 Distance = 0;\r
1391 Pos = *CurrentPosition;\r
1392\r
1393 while (TRUE) {\r
1394 NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
1395 if (IsSelectable (NextMenuOption)) {\r
1396 break;\r
1397 }\r
1398 if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {\r
1399 ASSERT (FALSE);\r
1400 break;\r
1401 }\r
1402 Distance -= NextMenuOption->Skip;\r
1403 Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink);\r
1404 }\r
1405 }\r
1406\r
1407 *CurrentPosition = &NextMenuOption->Link;\r
1408 return Distance;\r
1409}\r
1410\r
1411\r
1412/**\r
1413 Adjust Data and Time position accordingly.\r
1414 Data format : [01/02/2004] [11:22:33]\r
1415 Line number : 0 0 1 0 0 1\r
d66e6c16 1416\r
7936fb6a 1417 This is an internal function.\r
1418\r
1419 @param DirectionUp the up or down direction. False is down. True is\r
1420 up.\r
1421 @param CurrentPosition Current position. On return: Point to the last\r
1422 Option (Year or Second) if up; Point to the first\r
1423 Option (Month or Hour) if down.\r
1424\r
1425 @return Return line number to pad. It is possible that we stand on a zero-advance\r
1426 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
1427\r
1428**/\r
1429UINTN\r
1430AdjustDateAndTimePosition (\r
1431 IN BOOLEAN DirectionUp,\r
1432 IN OUT LIST_ENTRY **CurrentPosition\r
1433 )\r
1434{\r
1435 UINTN Count;\r
1436 LIST_ENTRY *NewPosition;\r
1437 UI_MENU_OPTION *MenuOption;\r
1438 UINTN PadLineNumber;\r
1439\r
1440 PadLineNumber = 0;\r
1441 NewPosition = *CurrentPosition;\r
1442 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
1443\r
1444 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
1445 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
1446 //\r
1447 // Calculate the distance from current position to the last Date/Time MenuOption\r
1448 //\r
1449 Count = 0;\r
1450 while (MenuOption->Skip == 0) {\r
1451 Count++;\r
1452 NewPosition = NewPosition->ForwardLink;\r
1453 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
1454 PadLineNumber = 1;\r
1455 }\r
1456\r
1457 NewPosition = *CurrentPosition;\r
1458 if (DirectionUp) {\r
1459 //\r
1460 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended\r
1461 // to be one that back to the previous set of MenuOptions, we need to advance to the first\r
1462 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate\r
1463 // checking can be done.\r
1464 //\r
1465 while (Count++ < 2) {\r
1466 NewPosition = NewPosition->BackLink;\r
1467 }\r
1468 } else {\r
1469 //\r
1470 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended\r
1471 // to be one that progresses to the next set of MenuOptions, we need to advance to the last\r
1472 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate\r
1473 // checking can be done.\r
1474 //\r
1475 while (Count-- > 0) {\r
1476 NewPosition = NewPosition->ForwardLink;\r
1477 }\r
1478 }\r
1479\r
1480 *CurrentPosition = NewPosition;\r
1481 }\r
1482\r
1483 return PadLineNumber;\r
1484}\r
1485\r
cb7d01c0 1486/**\r
1487 Find HII Handle in the HII database associated with given Device Path.\r
1488\r
1489 If DevicePath is NULL, then ASSERT.\r
1490\r
1491 @param DevicePath Device Path associated with the HII package list\r
1492 handle.\r
1493\r
1494 @retval Handle HII package list Handle associated with the Device\r
1495 Path.\r
1496 @retval NULL Hii Package list handle is not found.\r
1497\r
1498**/\r
1499EFI_HII_HANDLE\r
1500EFIAPI\r
1501DevicePathToHiiHandle (\r
1502 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
1503 )\r
1504{\r
1505 EFI_STATUS Status;\r
1506 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
1507 UINTN BufferSize;\r
1508 UINTN HandleCount;\r
1509 UINTN Index;\r
1510 EFI_HANDLE Handle;\r
1511 EFI_HANDLE DriverHandle;\r
1512 EFI_HII_HANDLE *HiiHandles;\r
1513 EFI_HII_HANDLE HiiHandle;\r
1514\r
1515 ASSERT (DevicePath != NULL);\r
1516\r
1517 TmpDevicePath = DevicePath;\r
1518 //\r
1519 // Locate Device Path Protocol handle buffer\r
1520 //\r
1521 Status = gBS->LocateDevicePath (\r
1522 &gEfiDevicePathProtocolGuid,\r
1523 &TmpDevicePath,\r
1524 &DriverHandle\r
1525 );\r
1526 if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {\r
1527 return NULL;\r
1528 }\r
1529\r
1530 //\r
1531 // Retrieve all HII Handles from HII database\r
1532 //\r
1533 BufferSize = 0x1000;\r
1534 HiiHandles = AllocatePool (BufferSize);\r
1535 ASSERT (HiiHandles != NULL);\r
1536 Status = mHiiDatabase->ListPackageLists (\r
1537 mHiiDatabase,\r
1538 EFI_HII_PACKAGE_TYPE_ALL,\r
1539 NULL,\r
1540 &BufferSize,\r
1541 HiiHandles\r
1542 );\r
1543 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1544 FreePool (HiiHandles);\r
1545 HiiHandles = AllocatePool (BufferSize);\r
1546 ASSERT (HiiHandles != NULL);\r
1547\r
1548 Status = mHiiDatabase->ListPackageLists (\r
1549 mHiiDatabase,\r
1550 EFI_HII_PACKAGE_TYPE_ALL,\r
1551 NULL,\r
1552 &BufferSize,\r
1553 HiiHandles\r
1554 );\r
1555 }\r
1556\r
1557 if (EFI_ERROR (Status)) {\r
1558 FreePool (HiiHandles);\r
1559 return NULL;\r
1560 }\r
1561\r
1562 //\r
1563 // Search Hii Handle by Driver Handle\r
1564 //\r
1565 HiiHandle = NULL;\r
1566 HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);\r
1567 for (Index = 0; Index < HandleCount; Index++) {\r
1568 Status = mHiiDatabase->GetPackageListHandle (\r
1569 mHiiDatabase,\r
1570 HiiHandles[Index],\r
1571 &Handle\r
1572 );\r
1573 if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {\r
1574 HiiHandle = HiiHandles[Index];\r
1575 break;\r
1576 }\r
1577 }\r
1578\r
1579 FreePool (HiiHandles);\r
1580 return HiiHandle;\r
1581}\r
7936fb6a 1582\r
1583/**\r
1584 Display menu and wait for user to select one menu option, then return it.\r
1585 If AutoBoot is enabled, then if user doesn't select any option,\r
1586 after period of time, it will automatically return the first menu option.\r
1587\r
1588 @param Selection Menu selection.\r
1589\r
1590 @retval EFI_SUCESSS This function always return successfully for now.\r
1591\r
1592**/\r
1593EFI_STATUS\r
1594UiDisplayMenu (\r
1595 IN OUT UI_MENU_SELECTION *Selection\r
1596 )\r
1597{\r
1598 INTN SkipValue;\r
1599 INTN Difference;\r
1600 INTN OldSkipValue;\r
1601 UINTN DistanceValue;\r
1602 UINTN Row;\r
1603 UINTN Col;\r
1604 UINTN Temp;\r
1605 UINTN Temp2;\r
1606 UINTN TopRow;\r
1607 UINTN BottomRow;\r
1608 UINTN OriginalRow;\r
1609 UINTN Index;\r
1610 UINT32 Count;\r
1611 UINT16 Width;\r
1612 CHAR16 *StringPtr;\r
1613 CHAR16 *OptionString;\r
1614 CHAR16 *OutputString;\r
1615 CHAR16 *FormattedString;\r
1616 CHAR16 YesResponse;\r
1617 CHAR16 NoResponse;\r
1618 BOOLEAN NewLine;\r
1619 BOOLEAN Repaint;\r
1620 BOOLEAN SavedValue;\r
1621 EFI_STATUS Status;\r
1622 EFI_INPUT_KEY Key;\r
1623 LIST_ENTRY *Link;\r
1624 LIST_ENTRY *NewPos;\r
1625 LIST_ENTRY *TopOfScreen;\r
1626 LIST_ENTRY *SavedListEntry;\r
1627 UI_MENU_OPTION *MenuOption;\r
1628 UI_MENU_OPTION *NextMenuOption;\r
1629 UI_MENU_OPTION *SavedMenuOption;\r
1630 UI_MENU_OPTION *PreviousMenuOption;\r
1631 UI_CONTROL_FLAG ControlFlag;\r
1632 EFI_SCREEN_DESCRIPTOR LocalScreen;\r
1633 MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
1634 UI_SCREEN_OPERATION ScreenOperation;\r
1635 UINT8 MinRefreshInterval;\r
1636 UINTN BufferSize;\r
1637 UINT16 DefaultId;\r
1638 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1639 FORM_BROWSER_STATEMENT *Statement;\r
63d55bb9
LG
1640 CHAR16 TemStr[2];\r
1641 UINT8 *DevicePathBuffer;\r
1642 UINT8 DigitUint8;\r
d66e6c16 1643 UI_MENU_LIST *CurrentMenu;\r
1644 UI_MENU_LIST *MenuList;\r
7936fb6a 1645\r
1646 CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
1647\r
1648 Status = EFI_SUCCESS;\r
1649 FormattedString = NULL;\r
1650 OptionString = NULL;\r
1651 ScreenOperation = UiNoOperation;\r
1652 NewLine = TRUE;\r
1653 MinRefreshInterval = 0;\r
1654 DefaultId = 0;\r
1655\r
1656 OutputString = NULL;\r
1657 gUpArrow = FALSE;\r
1658 gDownArrow = FALSE;\r
1659 SkipValue = 0;\r
1660 OldSkipValue = 0;\r
1661 MenuRefreshEntry = gMenuRefreshHead;\r
1662\r
1663 NextMenuOption = NULL;\r
1664 PreviousMenuOption = NULL;\r
1665 SavedMenuOption = NULL;\r
1666\r
1667 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
1668\r
0a1147ed 1669 if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {\r
7936fb6a 1670 TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1671 Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1672 } else {\r
1673 TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1674 Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1675 }\r
1676\r
1677 Col = LocalScreen.LeftColumn;\r
1678 BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
1679\r
1680 Selection->TopRow = TopRow;\r
1681 Selection->BottomRow = BottomRow;\r
1682 Selection->PromptCol = Col;\r
1683 Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
1684 Selection->Statement = NULL;\r
1685\r
1686 TopOfScreen = Menu.ForwardLink;\r
1687 Repaint = TRUE;\r
1688 MenuOption = NULL;\r
1689\r
d66e6c16 1690 //\r
1691 // Find current Menu\r
1692 //\r
1693 CurrentMenu = UiFindMenuList (&Selection->FormSetGuid, Selection->FormId);\r
1694 if (CurrentMenu == NULL) {\r
1695 //\r
1696 // Current menu not found, add it to the menu tree\r
1697 //\r
1698 CurrentMenu = UiAddMenuList (NULL, &Selection->FormSetGuid, Selection->FormId);\r
1699 }\r
1700 ASSERT (CurrentMenu != NULL);\r
1701\r
1702 if (Selection->QuestionId == 0) {\r
1703 //\r
1704 // Highlight not specified, fetch it from cached menu\r
1705 //\r
1706 Selection->QuestionId = CurrentMenu->QuestionId;\r
1707 }\r
1708\r
7936fb6a 1709 //\r
1710 // Get user's selection\r
1711 //\r
1712 NewPos = Menu.ForwardLink;\r
1713\r
1714 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
1715 UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
1716\r
1717 ControlFlag = CfInitialization;\r
1718 Selection->Action = UI_ACTION_NONE;\r
1719 while (TRUE) {\r
1720 switch (ControlFlag) {\r
1721 case CfInitialization:\r
1722 if (IsListEmpty (&Menu)) {\r
1723 ControlFlag = CfReadKey;\r
1724 } else {\r
1725 ControlFlag = CfCheckSelection;\r
1726 }\r
1727 break;\r
1728\r
1729 case CfCheckSelection:\r
1730 if (Selection->Action != UI_ACTION_NONE) {\r
1731 ControlFlag = CfExit;\r
1732 } else {\r
1733 ControlFlag = CfRepaint;\r
1734 }\r
1735 break;\r
1736\r
1737 case CfRepaint:\r
1738 ControlFlag = CfRefreshHighLight;\r
1739\r
1740 if (Repaint) {\r
1741 //\r
1742 // Display menu\r
1743 //\r
1744 gDownArrow = FALSE;\r
1745 gUpArrow = FALSE;\r
1746 Row = TopRow;\r
1747\r
1748 Temp = SkipValue;\r
1749 Temp2 = SkipValue;\r
1750\r
1751 ClearLines (\r
1752 LocalScreen.LeftColumn,\r
1753 LocalScreen.RightColumn,\r
1754 TopRow - SCROLL_ARROW_HEIGHT,\r
1755 BottomRow + SCROLL_ARROW_HEIGHT,\r
1756 FIELD_TEXT | FIELD_BACKGROUND\r
1757 );\r
1758\r
1759 UiFreeRefreshList ();\r
1760 MinRefreshInterval = 0;\r
1761\r
1762 for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {\r
1763 MenuOption = MENU_OPTION_FROM_LINK (Link);\r
1764 MenuOption->Row = Row;\r
1765 MenuOption->Col = Col;\r
1766 MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
1767\r
1768 Statement = MenuOption->ThisTag;\r
1769 if (Statement->InSubtitle) {\r
1770 MenuOption->Col += SUBTITLE_INDENT;\r
1771 }\r
1772\r
1773 if (MenuOption->GrayOut) {\r
1774 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
1775 } else {\r
1776 if (Statement->Operand == EFI_IFR_SUBTITLE_OP) {\r
1777 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
1778 }\r
1779 }\r
1780\r
1781 Width = GetWidth (Statement, MenuOption->Handle);\r
1782 OriginalRow = Row;\r
1783\r
1784 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1785 if ((Temp == 0) && (Row <= BottomRow)) {\r
1786 PrintStringAt (MenuOption->Col, Row, OutputString);\r
1787 }\r
1788 //\r
1789 // If there is more string to process print on the next row and increment the Skip value\r
1790 //\r
d1a54e2c 1791 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 1792 if (Temp == 0) {\r
1793 Row++;\r
1794 }\r
1795 }\r
1796\r
f4113e1f 1797 FreePool (OutputString);\r
7936fb6a 1798 if (Temp != 0) {\r
1799 Temp--;\r
1800 }\r
1801 }\r
1802\r
1803 Temp = 0;\r
1804 Row = OriginalRow;\r
1805\r
1806 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
8d00a0f1 1807 Status = ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
1808 if (EFI_ERROR (Status)) {\r
1809 //\r
1810 // Repaint to clear possible error prompt pop-up\r
1811 //\r
1812 Repaint = TRUE;\r
1813 NewLine = TRUE;\r
1814 ControlFlag = CfRepaint;\r
1815 break;\r
1816 }\r
7936fb6a 1817\r
1818 if (OptionString != NULL) {\r
1819 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
1820 //\r
1821 // If leading spaces on OptionString - remove the spaces\r
1822 //\r
1823 for (Index = 0; OptionString[Index] == L' '; Index++) {\r
1824 MenuOption->OptCol++;\r
1825 }\r
1826\r
1827 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1828 OptionString[Count] = OptionString[Index];\r
1829 Count++;\r
1830 }\r
1831\r
1832 OptionString[Count] = CHAR_NULL;\r
1833 }\r
1834\r
1835 //\r
1836 // If Question request refresh, register the op-code\r
1837 //\r
1838 if (Statement->RefreshInterval != 0) {\r
1839 //\r
1840 // Menu will be refreshed at minimal interval of all Questions\r
1841 // which have refresh request\r
1842 //\r
1843 if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {\r
1844 MinRefreshInterval = Statement->RefreshInterval;\r
1845 }\r
1846\r
1847 if (gMenuRefreshHead == NULL) {\r
1848 MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1849 ASSERT (MenuRefreshEntry != NULL);\r
1850 MenuRefreshEntry->MenuOption = MenuOption;\r
1851 MenuRefreshEntry->Selection = Selection;\r
1852 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1853 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1854 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1855 gMenuRefreshHead = MenuRefreshEntry;\r
1856 } else {\r
1857 //\r
1858 // Advance to the last entry\r
1859 //\r
1860 for (MenuRefreshEntry = gMenuRefreshHead;\r
1861 MenuRefreshEntry->Next != NULL;\r
1862 MenuRefreshEntry = MenuRefreshEntry->Next\r
1863 )\r
1864 ;\r
1865 MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1866 ASSERT (MenuRefreshEntry->Next != NULL);\r
1867 MenuRefreshEntry = MenuRefreshEntry->Next;\r
1868 MenuRefreshEntry->MenuOption = MenuOption;\r
1869 MenuRefreshEntry->Selection = Selection;\r
1870 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1871 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1872 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1873 }\r
1874 }\r
1875\r
1876 Width = (UINT16) gOptionBlockWidth;\r
1877 OriginalRow = Row;\r
1878\r
1879 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1880 if ((Temp2 == 0) && (Row <= BottomRow)) {\r
1881 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1882 }\r
1883 //\r
1884 // If there is more string to process print on the next row and increment the Skip value\r
1885 //\r
d1a54e2c 1886 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 1887 if (Temp2 == 0) {\r
1888 Row++;\r
1889 //\r
1890 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1891 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1892 // some testing to ensure we are keeping this in-sync.\r
1893 //\r
1894 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1895 //\r
1896 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1897 MenuOption->Skip++;\r
1898 }\r
1899 }\r
1900 }\r
1901\r
f4113e1f 1902 FreePool (OutputString);\r
7936fb6a 1903 if (Temp2 != 0) {\r
1904 Temp2--;\r
1905 }\r
1906 }\r
1907\r
1908 Temp2 = 0;\r
1909 Row = OriginalRow;\r
1910\r
f4113e1f 1911 FreePool (OptionString);\r
7936fb6a 1912 }\r
1913 //\r
1914 // If this is a text op with secondary text information\r
1915 //\r
1916 if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
1917 StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle);\r
1918\r
1919 Width = (UINT16) gOptionBlockWidth;\r
1920 OriginalRow = Row;\r
1921\r
1922 for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
1923 if ((Temp == 0) && (Row <= BottomRow)) {\r
1924 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1925 }\r
1926 //\r
1927 // If there is more string to process print on the next row and increment the Skip value\r
1928 //\r
d1a54e2c 1929 if (StrLen (&StringPtr[Index]) != 0) {\r
7936fb6a 1930 if (Temp2 == 0) {\r
1931 Row++;\r
1932 //\r
1933 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1934 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1935 // some testing to ensure we are keeping this in-sync.\r
1936 //\r
1937 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1938 //\r
1939 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1940 MenuOption->Skip++;\r
1941 }\r
1942 }\r
1943 }\r
1944\r
f4113e1f 1945 FreePool (OutputString);\r
7936fb6a 1946 if (Temp2 != 0) {\r
1947 Temp2--;\r
1948 }\r
1949 }\r
1950\r
1951 Row = OriginalRow;\r
f4113e1f 1952 FreePool (StringPtr);\r
7936fb6a 1953 }\r
1954\r
1955 //\r
1956 // Need to handle the bottom of the display\r
1957 //\r
1958 if (MenuOption->Skip > 1) {\r
1959 Row += MenuOption->Skip - SkipValue;\r
1960 SkipValue = 0;\r
1961 } else {\r
1962 Row += MenuOption->Skip;\r
1963 }\r
1964\r
1965 if (Row > BottomRow) {\r
1966 if (!ValueIsScroll (FALSE, Link)) {\r
1967 gDownArrow = TRUE;\r
1968 }\r
1969\r
1970 Row = BottomRow + 1;\r
1971 break;\r
1972 }\r
1973 }\r
1974\r
1975 if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
1976 gUpArrow = TRUE;\r
1977 }\r
1978\r
1979 if (gUpArrow) {\r
1980 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
1981 PrintAt (\r
1982 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
1983 TopRow - SCROLL_ARROW_HEIGHT,\r
1984 L"%c",\r
1985 ARROW_UP\r
1986 );\r
1987 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1988 }\r
1989\r
1990 if (gDownArrow) {\r
1991 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
1992 PrintAt (\r
1993 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
1994 BottomRow + SCROLL_ARROW_HEIGHT,\r
1995 L"%c",\r
1996 ARROW_DOWN\r
1997 );\r
1998 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1999 }\r
2000\r
2001 MenuOption = NULL;\r
2002 }\r
2003 break;\r
2004\r
2005 case CfRefreshHighLight:\r
2006 //\r
2007 // MenuOption: Last menu option that need to remove hilight\r
2008 // MenuOption is set to NULL in Repaint\r
2009 // NewPos: Current menu option that need to hilight\r
2010 //\r
2011 ControlFlag = CfUpdateHelpString;\r
2012\r
2013 //\r
2014 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
2015 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.\r
2016 //\r
2017 SavedValue = Repaint;\r
2018 Repaint = FALSE;\r
2019\r
2020 if (Selection->QuestionId != 0) {\r
2021 NewPos = Menu.ForwardLink;\r
2022 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2023\r
2024 while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &Menu) {\r
2025 NewPos = NewPos->ForwardLink;\r
2026 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2027 }\r
2028 if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) {\r
2029 //\r
2030 // Target Question found, find its MenuOption\r
2031 //\r
2032 Link = TopOfScreen;\r
2033\r
2034 for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {\r
2035 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2036 Index += SavedMenuOption->Skip;\r
2037 Link = Link->ForwardLink;\r
2038 }\r
2039\r
2040 if (Link != NewPos || Index > BottomRow) {\r
2041 //\r
2042 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page\r
2043 //\r
2044 Link = NewPos;\r
2045 for (Index = TopRow; Index <= BottomRow; ) {\r
2046 Link = Link->BackLink;\r
2047 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2048 Index += SavedMenuOption->Skip;\r
2049 }\r
2050 TopOfScreen = Link->ForwardLink;\r
2051\r
2052 Repaint = TRUE;\r
2053 NewLine = TRUE;\r
2054 ControlFlag = CfRepaint;\r
2055 break;\r
2056 }\r
2057 } else {\r
2058 //\r
2059 // Target Question not found, highlight the default menu option\r
2060 //\r
2061 NewPos = TopOfScreen;\r
2062 }\r
2063\r
2064 Selection->QuestionId = 0;\r
2065 }\r
2066\r
2067 if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {\r
2068 if (MenuOption != NULL) {\r
2069 //\r
2070 // Remove highlight on last Menu Option\r
2071 //\r
2072 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2073 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
2074 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2075 if (OptionString != NULL) {\r
2076 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
2077 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
2078 ) {\r
2079 //\r
2080 // If leading spaces on OptionString - remove the spaces\r
2081 //\r
2082 for (Index = 0; OptionString[Index] == L' '; Index++)\r
2083 ;\r
2084\r
2085 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
2086 OptionString[Count] = OptionString[Index];\r
2087 Count++;\r
2088 }\r
2089\r
2090 OptionString[Count] = CHAR_NULL;\r
2091 }\r
2092\r
2093 Width = (UINT16) gOptionBlockWidth;\r
2094 OriginalRow = MenuOption->Row;\r
2095\r
2096 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2097 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2098 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
2099 }\r
2100 //\r
2101 // If there is more string to process print on the next row and increment the Skip value\r
2102 //\r
d1a54e2c 2103 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2104 MenuOption->Row++;\r
2105 }\r
2106\r
f4113e1f 2107 FreePool (OutputString);\r
7936fb6a 2108 }\r
2109\r
2110 MenuOption->Row = OriginalRow;\r
2111\r
f4113e1f 2112 FreePool (OptionString);\r
7936fb6a 2113 } else {\r
2114 if (NewLine) {\r
2115 if (MenuOption->GrayOut) {\r
2116 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
2117 } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
2118 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
2119 }\r
2120\r
2121 OriginalRow = MenuOption->Row;\r
2122 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
2123\r
2124 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2125 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2126 PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
2127 }\r
2128 //\r
2129 // If there is more string to process print on the next row and increment the Skip value\r
2130 //\r
d1a54e2c 2131 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2132 MenuOption->Row++;\r
2133 }\r
2134\r
f4113e1f 2135 FreePool (OutputString);\r
7936fb6a 2136 }\r
2137\r
2138 MenuOption->Row = OriginalRow;\r
2139 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2140 }\r
2141 }\r
2142 }\r
2143\r
2144 //\r
2145 // This is only possible if we entered this page and the first menu option is\r
2146 // a "non-menu" item. In that case, force it UiDown\r
2147 //\r
2148 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2149 if (!IsSelectable (MenuOption)) {\r
2150 ASSERT (ScreenOperation == UiNoOperation);\r
2151 ScreenOperation = UiDown;\r
2152 ControlFlag = CfScreenOperation;\r
2153 break;\r
2154 }\r
2155\r
2156 //\r
2157 // This is the current selected statement\r
2158 //\r
2159 Statement = MenuOption->ThisTag;\r
2160 Selection->Statement = Statement;\r
d66e6c16 2161 //\r
2162 // Record highlight for current menu\r
2163 //\r
2164 CurrentMenu->QuestionId = Statement->QuestionId;\r
7936fb6a 2165\r
2166 //\r
2167 // Set reverse attribute\r
2168 //\r
2169 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
2170 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2171\r
2172 //\r
2173 // Assuming that we have a refresh linked-list created, lets annotate the\r
2174 // appropriate entry that we are highlighting with its new attribute. Just prior to this\r
2175 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh\r
2176 //\r
2177 if (gMenuRefreshHead != NULL) {\r
2178 for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
2179 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
2180 if (MenuRefreshEntry->MenuOption == MenuOption) {\r
2181 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;\r
2182 }\r
2183 }\r
2184 }\r
2185\r
2186 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
2187 if (OptionString != NULL) {\r
2188 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
2189 //\r
2190 // If leading spaces on OptionString - remove the spaces\r
2191 //\r
2192 for (Index = 0; OptionString[Index] == L' '; Index++)\r
2193 ;\r
2194\r
2195 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
2196 OptionString[Count] = OptionString[Index];\r
2197 Count++;\r
2198 }\r
2199\r
2200 OptionString[Count] = CHAR_NULL;\r
2201 }\r
2202 Width = (UINT16) gOptionBlockWidth;\r
2203\r
2204 OriginalRow = MenuOption->Row;\r
2205\r
2206 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2207 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2208 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
2209 }\r
2210 //\r
2211 // If there is more string to process print on the next row and increment the Skip value\r
2212 //\r
d1a54e2c 2213 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2214 MenuOption->Row++;\r
2215 }\r
2216\r
f4113e1f 2217 FreePool (OutputString);\r
7936fb6a 2218 }\r
2219\r
2220 MenuOption->Row = OriginalRow;\r
2221\r
f4113e1f 2222 FreePool (OptionString);\r
7936fb6a 2223 } else {\r
2224 if (NewLine) {\r
2225 OriginalRow = MenuOption->Row;\r
2226\r
2227 Width = GetWidth (Statement, MenuOption->Handle);\r
2228\r
2229 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2230 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2231 PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
2232 }\r
2233 //\r
2234 // If there is more string to process print on the next row and increment the Skip value\r
2235 //\r
d1a54e2c 2236 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2237 MenuOption->Row++;\r
2238 }\r
2239\r
f4113e1f 2240 FreePool (OutputString);\r
7936fb6a 2241 }\r
2242\r
2243 MenuOption->Row = OriginalRow;\r
2244\r
2245 }\r
2246 }\r
2247\r
8d00a0f1 2248 UpdateKeyHelp (MenuOption, FALSE);\r
2249\r
7936fb6a 2250 //\r
2251 // Clear reverse attribute\r
2252 //\r
2253 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2254 }\r
2255 //\r
2256 // Repaint flag will be used when process CfUpdateHelpString, so restore its value\r
2257 // if we didn't break halfway when process CfRefreshHighLight.\r
2258 //\r
2259 Repaint = SavedValue;\r
2260 break;\r
2261\r
2262 case CfUpdateHelpString:\r
2263 ControlFlag = CfPrepareToReadKey;\r
2264\r
0a1147ed 2265 if (Repaint || NewLine) {\r
7936fb6a 2266 //\r
2267 // Don't print anything if it is a NULL help token\r
2268 //\r
2269 if (MenuOption->ThisTag->Help == 0) {\r
2270 StringPtr = L"\0";\r
2271 } else {\r
2272 StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
2273 }\r
2274\r
2275 ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);\r
2276\r
2277 gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
2278\r
2279 for (Index = 0; Index < BottomRow - TopRow; Index++) {\r
2280 //\r
2281 // Pad String with spaces to simulate a clearing of the previous line\r
2282 //\r
2283 for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {\r
2284 StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" ");\r
2285 }\r
2286\r
2287 PrintStringAt (\r
2288 LocalScreen.RightColumn - gHelpBlockWidth,\r
2289 Index + TopRow,\r
2290 &FormattedString[Index * gHelpBlockWidth * 2]\r
2291 );\r
2292 }\r
2293 }\r
2294 //\r
2295 // Reset this flag every time we finish using it.\r
2296 //\r
2297 Repaint = FALSE;\r
2298 NewLine = FALSE;\r
2299 break;\r
2300\r
2301 case CfPrepareToReadKey:\r
2302 ControlFlag = CfReadKey;\r
2303 ScreenOperation = UiNoOperation;\r
2304 break;\r
2305\r
2306 case CfReadKey:\r
2307 ControlFlag = CfScreenOperation;\r
2308\r
2309 //\r
2310 // Wait for user's selection\r
2311 //\r
2312 do {\r
2313 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);\r
2314 } while (Status == EFI_TIMEOUT);\r
2315\r
8d00a0f1 2316 if (Selection->Action == UI_ACTION_REFRESH_FORMSET) {\r
7936fb6a 2317 //\r
8d00a0f1 2318 // IFR is updated in Callback of refresh opcode, re-parse it\r
7936fb6a 2319 //\r
8d00a0f1 2320 Selection->Statement = NULL;\r
d66e6c16 2321 return EFI_SUCCESS;\r
8d00a0f1 2322 }\r
2323\r
2324 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2325 //\r
d66e6c16 2326 // If we encounter error, continue to read another key in.\r
8d00a0f1 2327 //\r
2328 if (EFI_ERROR (Status)) {\r
2329 ControlFlag = CfReadKey;\r
2330 break;\r
7936fb6a 2331 }\r
2332\r
7936fb6a 2333 switch (Key.UnicodeChar) {\r
2334 case CHAR_CARRIAGE_RETURN:\r
2335 ScreenOperation = UiSelect;\r
2336 gDirection = 0;\r
2337 break;\r
2338\r
2339 //\r
2340 // We will push the adjustment of these numeric values directly to the input handler\r
2341 // NOTE: we won't handle manual input numeric\r
2342 //\r
2343 case '+':\r
2344 case '-':\r
2345 Statement = MenuOption->ThisTag;\r
2346 if ((Statement->Operand == EFI_IFR_DATE_OP)\r
2347 || (Statement->Operand == EFI_IFR_TIME_OP)\r
2348 || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0))\r
2349 ){\r
2350 if (Key.UnicodeChar == '+') {\r
2351 gDirection = SCAN_RIGHT;\r
2352 } else {\r
2353 gDirection = SCAN_LEFT;\r
2354 }\r
2355 Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
8d00a0f1 2356 if (EFI_ERROR (Status)) {\r
2357 //\r
2358 // Repaint to clear possible error prompt pop-up\r
2359 //\r
2360 Repaint = TRUE;\r
2361 NewLine = TRUE;\r
2362 }\r
676df92c 2363 if (OptionString != NULL) {\r
2364 FreePool (OptionString);\r
2365 }\r
7936fb6a 2366 }\r
2367 break;\r
2368\r
2369 case '^':\r
2370 ScreenOperation = UiUp;\r
2371 break;\r
2372\r
2373 case 'V':\r
2374 case 'v':\r
2375 ScreenOperation = UiDown;\r
2376 break;\r
2377\r
2378 case ' ':\r
0a1147ed 2379 if (gClassOfVfr != FORMSET_CLASS_FRONT_PAGE) {\r
7936fb6a 2380 if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {\r
2381 ScreenOperation = UiSelect;\r
2382 }\r
2383 }\r
2384 break;\r
2385\r
2386 case CHAR_NULL:\r
2387 if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) ||\r
7936fb6a 2388 ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
2389 ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
2390 ) {\r
2391 //\r
2392 // If the function key has been disabled, just ignore the key.\r
2393 //\r
2394 } else {\r
2395 for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {\r
2396 if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
2397 if (Key.ScanCode == SCAN_F9) {\r
2398 //\r
2399 // Reset to standard default\r
2400 //\r
2401 DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;\r
2402 }\r
2403 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
2404 break;\r
2405 }\r
2406 }\r
2407 }\r
2408 break;\r
2409 }\r
2410 break;\r
2411\r
2412 case CfScreenOperation:\r
d66e6c16 2413 if (ScreenOperation != UiReset) {\r
7936fb6a 2414 //\r
d66e6c16 2415 // If the screen has no menu items, and the user didn't select UiReset\r
7936fb6a 2416 // ignore the selection and go back to reading keys.\r
2417 //\r
2418 if (IsListEmpty (&Menu)) {\r
2419 ControlFlag = CfReadKey;\r
2420 break;\r
2421 }\r
2422 //\r
2423 // if there is nothing logical to place a cursor on, just move on to wait for a key.\r
2424 //\r
2425 for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {\r
2426 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2427 if (IsSelectable (NextMenuOption)) {\r
2428 break;\r
2429 }\r
2430 }\r
2431\r
2432 if (Link == &Menu) {\r
2433 ControlFlag = CfPrepareToReadKey;\r
2434 break;\r
2435 }\r
7936fb6a 2436 }\r
2437\r
2438 for (Index = 0;\r
2439 Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
2440 Index++\r
2441 ) {\r
2442 if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
2443 ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
2444 break;\r
2445 }\r
2446 }\r
2447 break;\r
2448\r
7936fb6a 2449 case CfUiSelect:\r
2450 ControlFlag = CfCheckSelection;\r
2451\r
2452 Statement = MenuOption->ThisTag;\r
2453 if ((Statement->Operand == EFI_IFR_TEXT_OP) ||\r
2454 (Statement->Operand == EFI_IFR_DATE_OP) ||\r
2455 (Statement->Operand == EFI_IFR_TIME_OP) ||\r
2456 (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) {\r
2457 break;\r
2458 }\r
2459\r
2460 //\r
2461 // Keep highlight on current MenuOption\r
2462 //\r
2463 Selection->QuestionId = Statement->QuestionId;\r
2464\r
2465 switch (Statement->Operand) {\r
2466 case EFI_IFR_REF_OP:\r
2467 if (Statement->RefDevicePath != 0) {\r
2468 //\r
2469 // Goto another Hii Package list\r
2470 //\r
d66e6c16 2471 ControlFlag = CfCheckSelection;\r
7936fb6a 2472 Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
2473\r
2474 StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle);\r
2475 if (StringPtr == NULL) {\r
2476 //\r
2477 // No device path string not found, exit\r
2478 //\r
2479 Selection->Action = UI_ACTION_EXIT;\r
2480 Selection->Statement = NULL;\r
2481 break;\r
2482 }\r
2483 BufferSize = StrLen (StringPtr) / 2;\r
2484 DevicePath = AllocatePool (BufferSize);\r
d66e6c16 2485\r
63d55bb9
LG
2486 //\r
2487 // Convert from Device Path String to DevicePath Buffer in the reverse order.\r
2488 //\r
2489 DevicePathBuffer = (UINT8 *) DevicePath;\r
2490 for (Index = 0; StringPtr[Index] != L'\0'; Index ++) {\r
2491 TemStr[0] = StringPtr[Index];\r
2492 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
2493 if (DigitUint8 == 0 && TemStr[0] != L'0') {\r
2494 //\r
2495 // Invalid Hex Char as the tail.\r
2496 //\r
2497 break;\r
2498 }\r
2499 if ((Index & 1) == 0) {\r
2500 DevicePathBuffer [Index/2] = DigitUint8;\r
2501 } else {\r
2502 DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);\r
2503 }\r
2504 }\r
7936fb6a 2505\r
cb7d01c0 2506 Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
7936fb6a 2507 if (Selection->Handle == NULL) {\r
2508 //\r
2509 // If target Hii Handle not found, exit\r
2510 //\r
2511 Selection->Action = UI_ACTION_EXIT;\r
2512 Selection->Statement = NULL;\r
2513 break;\r
2514 }\r
2515\r
f4113e1f 2516 FreePool (StringPtr);\r
2517 FreePool (DevicePath);\r
7936fb6a 2518\r
2519 CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
2520 Selection->FormId = Statement->RefFormId;\r
2521 Selection->QuestionId = Statement->RefQuestionId;\r
2522 } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) {\r
2523 //\r
2524 // Goto another Formset, check for uncommitted data\r
2525 //\r
d66e6c16 2526 ControlFlag = CfCheckSelection;\r
7936fb6a 2527 Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
2528\r
2529 CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
2530 Selection->FormId = Statement->RefFormId;\r
2531 Selection->QuestionId = Statement->RefQuestionId;\r
2532 } else if (Statement->RefFormId != 0) {\r
2533 //\r
2534 // Goto another form inside this formset,\r
2535 //\r
2536 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2537\r
2538 //\r
d66e6c16 2539 // Link current form so that we can always go back when someone hits the ESC\r
7936fb6a 2540 //\r
d66e6c16 2541 MenuList = UiFindMenuList (&Selection->FormSetGuid, Statement->RefFormId);\r
2542 if (MenuList == NULL) {\r
2543 MenuList = UiAddMenuList (CurrentMenu, &Selection->FormSetGuid, Statement->RefFormId);\r
2544 }\r
7936fb6a 2545\r
2546 Selection->FormId = Statement->RefFormId;\r
2547 Selection->QuestionId = Statement->RefQuestionId;\r
2548 } else if (Statement->RefQuestionId != 0) {\r
2549 //\r
2550 // Goto another Question\r
2551 //\r
2552 Selection->QuestionId = Statement->RefQuestionId;\r
2553\r
2554 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
2555 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2556 } else {\r
2557 Repaint = TRUE;\r
2558 NewLine = TRUE;\r
2559 break;\r
2560 }\r
2561 }\r
2562 break;\r
2563\r
2564 case EFI_IFR_ACTION_OP:\r
2565 //\r
2566 // Process the Config string <ConfigResp>\r
2567 //\r
2568 Status = ProcessQuestionConfig (Selection, Statement);\r
2569\r
2570 if (EFI_ERROR (Status)) {\r
2571 break;\r
2572 }\r
2573\r
2574 //\r
2575 // The action button may change some Question value, so refresh the form\r
2576 //\r
2577 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2578 break;\r
2579\r
2580 case EFI_IFR_RESET_BUTTON_OP:\r
2581 //\r
2582 // Reset Question to default value specified by DefaultId\r
2583 //\r
2584 ControlFlag = CfUiDefault;\r
2585 DefaultId = Statement->DefaultId;\r
2586 break;\r
2587\r
2588 default:\r
2589 //\r
2590 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password\r
2591 //\r
2592 UpdateKeyHelp (MenuOption, TRUE);\r
2593 Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
2594\r
2595 if (EFI_ERROR (Status)) {\r
2596 Repaint = TRUE;\r
2597 NewLine = TRUE;\r
8d00a0f1 2598 UpdateKeyHelp (MenuOption, FALSE);\r
2599 } else {\r
2600 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2601 }\r
7936fb6a 2602\r
8d00a0f1 2603 if (OptionString != NULL) {\r
2604 FreePool (OptionString);\r
2605 }\r
7936fb6a 2606 break;\r
2607 }\r
2608 break;\r
2609\r
2610 case CfUiReset:\r
2611 //\r
d66e6c16 2612 // We come here when someone press ESC\r
7936fb6a 2613 //\r
2614 ControlFlag = CfCheckSelection;\r
2615\r
d66e6c16 2616 if (CurrentMenu->Parent != NULL) {\r
2617 //\r
2618 // we have a parent, so go to the parent menu\r
2619 //\r
2620 if (CompareGuid (&CurrentMenu->FormSetGuid, &CurrentMenu->Parent->FormSetGuid)) {\r
2621 //\r
2622 // The parent menu and current menu are in the same formset\r
2623 //\r
2624 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2625 } else {\r
2626 Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
2627 }\r
2628 Selection->Statement = NULL;\r
2629\r
2630 Selection->FormId = CurrentMenu->Parent->FormId;\r
2631 Selection->QuestionId = CurrentMenu->Parent->QuestionId;\r
2632\r
2633 //\r
2634 // Clear highlight record for this menu\r
2635 //\r
2636 CurrentMenu->QuestionId = 0;\r
2637 break;\r
2638 }\r
2639\r
0a1147ed 2640 if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {\r
7936fb6a 2641 //\r
d66e6c16 2642 // We never exit FrontPage, so skip the ESC\r
7936fb6a 2643 //\r
2644 Selection->Action = UI_ACTION_NONE;\r
7936fb6a 2645 break;\r
2646 }\r
2647\r
2648 //\r
d66e6c16 2649 // We are going to leave current FormSet, so check uncommited data in this FormSet\r
7936fb6a 2650 //\r
2651 if (gNvUpdateRequired) {\r
2652 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2653\r
2654 YesResponse = gYesResponse[0];\r
2655 NoResponse = gNoResponse[0];\r
2656\r
d66e6c16 2657 //\r
2658 // If NV flag is up, prompt user\r
2659 //\r
7936fb6a 2660 do {\r
d66e6c16 2661 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString);\r
7936fb6a 2662 } while\r
2663 (\r
2664 (Key.ScanCode != SCAN_ESC) &&\r
2665 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
2666 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
2667 );\r
2668\r
d66e6c16 2669 if (Key.ScanCode == SCAN_ESC) {\r
2670 //\r
2671 // User hits the ESC key\r
2672 //\r
7936fb6a 2673 Repaint = TRUE;\r
2674 NewLine = TRUE;\r
2675\r
2676 Selection->Action = UI_ACTION_NONE;\r
2677 break;\r
2678 }\r
d66e6c16 2679\r
2680 //\r
2681 // If the user hits the YesResponse key\r
2682 //\r
2683 if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
2684 Status = SubmitForm (Selection->FormSet, Selection->Form);\r
2685 }\r
7936fb6a 2686 }\r
2687\r
d66e6c16 2688 Selection->Action = UI_ACTION_EXIT;\r
2689 Selection->Statement = NULL;\r
2690 CurrentMenu->QuestionId = 0;\r
7936fb6a 2691\r
7936fb6a 2692 return EFI_SUCCESS;\r
2693\r
2694 case CfUiLeft:\r
2695 ControlFlag = CfCheckSelection;\r
2696 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
2697 if (MenuOption->Sequence != 0) {\r
2698 //\r
2699 // In the middle or tail of the Date/Time op-code set, go left.\r
2700 //\r
2701 NewPos = NewPos->BackLink;\r
2702 }\r
2703 }\r
2704 break;\r
2705\r
2706 case CfUiRight:\r
2707 ControlFlag = CfCheckSelection;\r
2708 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
2709 if (MenuOption->Sequence != 2) {\r
2710 //\r
2711 // In the middle or tail of the Date/Time op-code set, go left.\r
2712 //\r
2713 NewPos = NewPos->ForwardLink;\r
2714 }\r
2715 }\r
2716 break;\r
2717\r
2718 case CfUiUp:\r
2719 ControlFlag = CfCheckSelection;\r
2720\r
2721 SavedListEntry = TopOfScreen;\r
2722\r
2723 if (NewPos->BackLink != &Menu) {\r
2724 NewLine = TRUE;\r
2725 //\r
2726 // Adjust Date/Time position before we advance forward.\r
2727 //\r
2728 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2729\r
2730 //\r
2731 // Caution that we have already rewind to the top, don't go backward in this situation.\r
2732 //\r
2733 if (NewPos->BackLink != &Menu) {\r
2734 NewPos = NewPos->BackLink;\r
2735 }\r
2736\r
2737 PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2738 DistanceValue = PreviousMenuOption->Skip;\r
2739\r
2740 //\r
2741 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
2742 // to be one that back to the previous set of op-codes, we need to advance to the sencond\r
2743 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
2744 // checking can be done.\r
2745 //\r
2746 DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos);\r
2747\r
2748 //\r
2749 // Check the previous menu entry to see if it was a zero-length advance. If it was,\r
2750 // don't worry about a redraw.\r
2751 //\r
2752 if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {\r
2753 Repaint = TRUE;\r
2754 TopOfScreen = NewPos;\r
2755 }\r
2756\r
d66e6c16 2757 Difference = MoveToNextStatement (TRUE, &NewPos);\r
e3eb7467 2758 PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2759 DistanceValue += PreviousMenuOption->Skip;\r
d66e6c16 2760\r
2761 if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {\r
7936fb6a 2762 if (Difference > 0) {\r
2763 //\r
2764 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
2765 //\r
2766 TopOfScreen = NewPos;\r
2767 Repaint = TRUE;\r
d66e6c16 2768 SkipValue = 0;\r
2769 OldSkipValue = 0;\r
7936fb6a 2770 }\r
2771 }\r
2772 if (Difference < 0) {\r
2773 //\r
2774 // We want to goto previous MenuOption, but finally we go down.\r
2775 // it means that we hit the begining MenuOption that can be focused\r
2776 // so we simply scroll to the top\r
2777 //\r
2778 if (SavedListEntry != Menu.ForwardLink) {\r
2779 TopOfScreen = Menu.ForwardLink;\r
2780 Repaint = TRUE;\r
2781 }\r
2782 }\r
2783\r
2784 //\r
2785 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2786 //\r
2787 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2788\r
2789 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
2790 } else {\r
2791 SavedMenuOption = MenuOption;\r
2792 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2793 if (!IsSelectable (MenuOption)) {\r
2794 //\r
2795 // If we are at the end of the list and sitting on a text op, we need to more forward\r
2796 //\r
2797 ScreenOperation = UiDown;\r
2798 ControlFlag = CfScreenOperation;\r
2799 break;\r
2800 }\r
2801\r
2802 MenuOption = SavedMenuOption;\r
2803 }\r
2804 break;\r
2805\r
2806 case CfUiPageUp:\r
2807 ControlFlag = CfCheckSelection;\r
2808\r
2809 if (NewPos->BackLink == &Menu) {\r
2810 NewLine = FALSE;\r
2811 Repaint = FALSE;\r
2812 break;\r
2813 }\r
2814\r
2815 NewLine = TRUE;\r
2816 Repaint = TRUE;\r
2817 Link = TopOfScreen;\r
2818 PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2819 Index = BottomRow;\r
2820 while ((Index >= TopRow) && (Link->BackLink != &Menu)) {\r
2821 Index = Index - PreviousMenuOption->Skip;\r
2822 Link = Link->BackLink;\r
2823 PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2824 }\r
2825\r
2826 TopOfScreen = Link;\r
2827 Difference = MoveToNextStatement (TRUE, &Link);\r
2828 if (Difference > 0) {\r
2829 //\r
2830 // The focus MenuOption is above the TopOfScreen\r
2831 //\r
2832 TopOfScreen = Link;\r
2833 } else if (Difference < 0) {\r
2834 //\r
2835 // This happens when there is no MenuOption can be focused from\r
2836 // Current MenuOption to the first MenuOption\r
2837 //\r
2838 TopOfScreen = Menu.ForwardLink;\r
2839 }\r
2840 Index += Difference;\r
2841 if (Index < TopRow) {\r
2842 MenuOption = NULL;\r
2843 }\r
2844\r
2845 if (NewPos == Link) {\r
2846 Repaint = FALSE;\r
2847 NewLine = FALSE;\r
2848 } else {\r
2849 NewPos = Link;\r
2850 }\r
2851\r
2852 //\r
2853 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2854 // Don't do this when we are already in the first page.\r
2855 //\r
2856 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2857 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2858 break;\r
2859\r
2860 case CfUiPageDown:\r
2861 ControlFlag = CfCheckSelection;\r
2862\r
2863 if (NewPos->ForwardLink == &Menu) {\r
2864 NewLine = FALSE;\r
2865 Repaint = FALSE;\r
2866 break;\r
2867 }\r
2868\r
2869 NewLine = TRUE;\r
2870 Repaint = TRUE;\r
2871 Link = TopOfScreen;\r
2872 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2873 Index = TopRow;\r
2874 while ((Index <= BottomRow) && (Link->ForwardLink != &Menu)) {\r
2875 Index = Index + NextMenuOption->Skip;\r
2876 Link = Link->ForwardLink;\r
2877 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2878 }\r
2879\r
2880 Index += MoveToNextStatement (FALSE, &Link);\r
2881 if (Index > BottomRow) {\r
2882 //\r
2883 // There are more MenuOption needing scrolling\r
2884 //\r
2885 TopOfScreen = Link;\r
2886 MenuOption = NULL;\r
2887 }\r
2888 if (NewPos == Link && Index <= BottomRow) {\r
2889 //\r
2890 // Finally we know that NewPos is the last MenuOption can be focused.\r
2891 //\r
2892 NewLine = FALSE;\r
2893 Repaint = FALSE;\r
2894 } else {\r
2895 NewPos = Link;\r
2896 }\r
2897\r
2898 //\r
2899 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2900 // Don't do this when we are already in the last page.\r
2901 //\r
2902 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2903 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2904 break;\r
2905\r
2906 case CfUiDown:\r
2907 ControlFlag = CfCheckSelection;\r
2908 //\r
2909 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
2910 // to be one that progresses to the next set of op-codes, we need to advance to the last\r
2911 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
2912 // checking can be done. The only other logic we need to introduce is that if a Date/Time\r
2913 // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
2914 // the Date/Time op-code.\r
2915 //\r
2916 SavedListEntry = NewPos;\r
2917 DistanceValue = AdjustDateAndTimePosition (FALSE, &NewPos);\r
2918\r
2919 if (NewPos->ForwardLink != &Menu) {\r
2920 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2921 NewLine = TRUE;\r
2922 NewPos = NewPos->ForwardLink;\r
2923 NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2924\r
2925 DistanceValue += NextMenuOption->Skip;\r
2926 DistanceValue += MoveToNextStatement (FALSE, &NewPos);\r
2927 //\r
2928 // An option might be multi-line, so we need to reflect that data in the overall skip value\r
2929 //\r
2930 UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue);\r
2931\r
2932 Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
2933 if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\r
2934 (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
2935 NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
2936 ) {\r
2937 Temp ++;\r
2938 }\r
2939\r
2940 //\r
2941 // If we are going to scroll, update TopOfScreen\r
2942 //\r
2943 if (Temp > BottomRow) {\r
2944 do {\r
2945 //\r
2946 // Is the current top of screen a zero-advance op-code?\r
2947 // If so, keep moving forward till we hit a >0 advance op-code\r
2948 //\r
2949 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
2950\r
2951 //\r
2952 // If bottom op-code is more than one line or top op-code is more than one line\r
2953 //\r
2954 if ((DistanceValue > 1) || (MenuOption->Skip > 1)) {\r
2955 //\r
2956 // Is the bottom op-code greater than or equal in size to the top op-code?\r
2957 //\r
2958 if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) {\r
2959 //\r
2960 // Skip the top op-code\r
2961 //\r
2962 TopOfScreen = TopOfScreen->ForwardLink;\r
2963 Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);\r
2964\r
2965 OldSkipValue = Difference;\r
2966\r
2967 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
2968\r
2969 //\r
2970 // If we have a remainder, skip that many more op-codes until we drain the remainder\r
2971 //\r
2972 for (;\r
2973 Difference >= (INTN) SavedMenuOption->Skip;\r
2974 Difference = Difference - (INTN) SavedMenuOption->Skip\r
2975 ) {\r
2976 //\r
2977 // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
2978 //\r
2979 TopOfScreen = TopOfScreen->ForwardLink;\r
2980 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
2981 if (Difference < (INTN) SavedMenuOption->Skip) {\r
2982 Difference = SavedMenuOption->Skip - Difference - 1;\r
2983 break;\r
2984 } else {\r
2985 if (Difference == (INTN) SavedMenuOption->Skip) {\r
2986 TopOfScreen = TopOfScreen->ForwardLink;\r
2987 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
2988 Difference = SavedMenuOption->Skip - Difference;\r
2989 break;\r
2990 }\r
2991 }\r
2992 }\r
2993 //\r
2994 // Since we will act on this op-code in the next routine, and increment the\r
2995 // SkipValue, set the skips to one less than what is required.\r
2996 //\r
2997 SkipValue = Difference - 1;\r
2998\r
2999 } else {\r
3000 //\r
3001 // Since we will act on this op-code in the next routine, and increment the\r
3002 // SkipValue, set the skips to one less than what is required.\r
3003 //\r
3004 SkipValue = OldSkipValue + (Temp - BottomRow) - 1;\r
3005 }\r
3006 } else {\r
3007 if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
3008 TopOfScreen = TopOfScreen->ForwardLink;\r
3009 break;\r
3010 } else {\r
3011 SkipValue = OldSkipValue;\r
3012 }\r
3013 }\r
3014 //\r
3015 // If the op-code at the top of the screen is more than one line, let's not skip it yet\r
3016 // Let's set a skip flag to smoothly scroll the top of the screen.\r
3017 //\r
3018 if (SavedMenuOption->Skip > 1) {\r
3019 if (SavedMenuOption == NextMenuOption) {\r
3020 SkipValue = 0;\r
3021 } else {\r
3022 SkipValue++;\r
3023 }\r
3024 } else {\r
3025 SkipValue = 0;\r
3026 TopOfScreen = TopOfScreen->ForwardLink;\r
3027 }\r
3028 } while (SavedMenuOption->Skip == 0);\r
3029\r
3030 Repaint = TRUE;\r
3031 OldSkipValue = SkipValue;\r
3032 }\r
3033\r
3034 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3035\r
3036 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
3037\r
3038 } else {\r
3039 SavedMenuOption = MenuOption;\r
3040 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
3041 if (!IsSelectable (MenuOption)) {\r
3042 //\r
3043 // If we are at the end of the list and sitting on a text op, we need to more forward\r
3044 //\r
3045 ScreenOperation = UiUp;\r
3046 ControlFlag = CfScreenOperation;\r
3047 break;\r
3048 }\r
3049\r
3050 MenuOption = SavedMenuOption;\r
3051 //\r
3052 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
3053 //\r
3054 AdjustDateAndTimePosition (TRUE, &NewPos);\r
3055 }\r
3056 break;\r
3057\r
3058 case CfUiSave:\r
3059 ControlFlag = CfCheckSelection;\r
3060\r
3061 //\r
3062 // Submit the form\r
3063 //\r
3064 Status = SubmitForm (Selection->FormSet, Selection->Form);\r
3065\r
3066 if (!EFI_ERROR (Status)) {\r
3067 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
3068 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
3069 } else {\r
3070 do {\r
3071 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString);\r
3072 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
3073\r
3074 Repaint = TRUE;\r
3075 NewLine = TRUE;\r
3076 }\r
3077 break;\r
3078\r
3079 case CfUiDefault:\r
3080 ControlFlag = CfCheckSelection;\r
3081\r
3082 Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId);\r
3083\r
3084 if (!EFI_ERROR (Status)) {\r
3085 Selection->Action = UI_ACTION_REFRESH_FORM;\r
ebe43565 3086 Selection->Statement = NULL;\r
7936fb6a 3087\r
3088 //\r
3089 // Show NV update flag on status bar\r
3090 //\r
3091 gNvUpdateRequired = TRUE;\r
3092 }\r
3093 break;\r
3094\r
3095 case CfUiNoOperation:\r
3096 ControlFlag = CfCheckSelection;\r
3097 break;\r
3098\r
3099 case CfExit:\r
3100 UiFreeRefreshList ();\r
3101\r
3102 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
3103 gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
3104 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
3105 gST->ConOut->OutputString (gST->ConOut, L"\n");\r
3106\r
3107 return EFI_SUCCESS;\r
3108\r
3109 default:\r
3110 break;\r
3111 }\r
3112 }\r
3113}\r