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