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