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