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