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