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