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