]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/DisplayEngineDxe/Popup.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / Popup.c
CommitLineData
06aad9a2
DB
1/** @file\r
2Implementation for Hii Popup Protocol.\r
3\r
4Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
9d510e61 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
06aad9a2
DB
6\r
7**/\r
8\r
9#include "FormDisplay.h"\r
10\r
11EFI_SCREEN_DESCRIPTOR gPopupDimensions;\r
12LIST_ENTRY gUserSelectableOptions;\r
13EFI_STRING gMessageString;\r
14UINTN gMesStrLineNum;\r
15UINTN gMaxRowWidth;\r
16\r
17/**\r
18 Free the user selectable option structure data.\r
19\r
20 @param OptionList Point to the selectable option list which need to be freed.\r
21\r
22**/\r
23VOID\r
1436aea4
MK
24FreeSelectableOptions (\r
25 LIST_ENTRY *OptionList\r
06aad9a2
DB
26 )\r
27{\r
28 LIST_ENTRY *Link;\r
29 USER_SELECTABLE_OPTION *SelectableOption;\r
30\r
31 while (!IsListEmpty (OptionList)) {\r
1436aea4 32 Link = GetFirstNode (OptionList);\r
06aad9a2
DB
33 SelectableOption = SELECTABLE_OPTION_FROM_LINK (Link);\r
34 RemoveEntryList (&SelectableOption->Link);\r
35 FreePool (SelectableOption);\r
36 }\r
37}\r
38\r
39/**\r
40 Display one selectable option.\r
41\r
42 @param SelectableOption The selectable option need to be drew.\r
43 @param Highlight Whether the option need to be highlighted.\r
44\r
45**/\r
46VOID\r
1436aea4
MK
47DisplayOneSelectableOption (\r
48 IN USER_SELECTABLE_OPTION *SelectableOption,\r
49 IN BOOLEAN Highlight\r
06aad9a2
DB
50 )\r
51{\r
52 if (Highlight) {\r
53 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
54 }\r
1436aea4 55\r
06aad9a2
DB
56 PrintStringAt (SelectableOption->OptionCol, SelectableOption->OptionRow, SelectableOption->OptionString);\r
57 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
58}\r
59\r
60/**\r
61 Add one selectable option to option list. This is the work function for AddUserSelectableOptions.\r
62\r
63 @param PopupType The option need to be drew.\r
64 @param OptionType The type of this selection option.\r
65 @param OptionString Point to the option string that to be shown.\r
66 @param OptionCol The column that the option need to be drew at.\r
67 @param OptionRow The row that the option need to be drew at.\r
68\r
69 @retval EFI_SUCCESS This function implement successfully.\r
70 @retval EFI_OUT_OF_RESOURCES There are not enough resources available.\r
71\r
72**/\r
73EFI_STATUS\r
74AddOneSelectableOption (\r
1436aea4
MK
75 IN EFI_HII_POPUP_TYPE PopupType,\r
76 IN EFI_HII_POPUP_SELECTION OptionType,\r
77 IN CHAR16 *OptionString,\r
78 IN UINTN OptionCol,\r
79 IN UINTN OptionRow\r
06aad9a2
DB
80 )\r
81{\r
82 USER_SELECTABLE_OPTION *UserSelectableOption;\r
83\r
84 UserSelectableOption = AllocateZeroPool (sizeof (USER_SELECTABLE_OPTION));\r
85 if (UserSelectableOption == NULL) {\r
86 return EFI_OUT_OF_RESOURCES;\r
87 }\r
1436aea4 88\r
06aad9a2
DB
89 //\r
90 // Initialize the user selectable option based on the PopupType and OptionType.\r
91 // And then add the option to the option list gUserSelectableOptions.\r
92 //\r
1436aea4 93 UserSelectableOption->Signature = USER_SELECTABLE_OPTION_SIGNATURE;\r
06aad9a2 94 UserSelectableOption->OptionString = OptionString;\r
1436aea4
MK
95 UserSelectableOption->OptionType = OptionType;\r
96 UserSelectableOption->OptionCol = OptionCol;\r
97 UserSelectableOption->OptionRow = OptionRow;\r
98 UserSelectableOption->MinSequence = 0;\r
06aad9a2
DB
99\r
100 switch (PopupType) {\r
1436aea4
MK
101 case EfiHiiPopupTypeOk:\r
102 UserSelectableOption->MaxSequence = 0;\r
103 UserSelectableOption->Sequence = 0;\r
104 break;\r
105 case EfiHiiPopupTypeOkCancel:\r
106 UserSelectableOption->MaxSequence = 1;\r
107 if (OptionType == EfiHiiPopupSelectionOk) {\r
108 UserSelectableOption->Sequence = 0;\r
109 } else {\r
110 UserSelectableOption->Sequence = 1;\r
111 }\r
112\r
113 break;\r
114 case EfiHiiPopupTypeYesNo:\r
115 UserSelectableOption->MaxSequence = 1;\r
116 if (OptionType == EfiHiiPopupSelectionYes) {\r
117 UserSelectableOption->Sequence = 0;\r
118 } else {\r
119 UserSelectableOption->Sequence = 1;\r
120 }\r
121\r
122 break;\r
123 case EfiHiiPopupTypeYesNoCancel:\r
124 UserSelectableOption->MaxSequence = 2;\r
125 if (OptionType == EfiHiiPopupSelectionYes) {\r
126 UserSelectableOption->Sequence = 0;\r
127 } else if (OptionType == EfiHiiPopupSelectionNo) {\r
128 UserSelectableOption->Sequence = 1;\r
129 } else {\r
130 UserSelectableOption->Sequence = 2;\r
131 }\r
132\r
133 break;\r
134 default:\r
135 break;\r
06aad9a2 136 }\r
1436aea4 137\r
06aad9a2
DB
138 InsertTailList (&gUserSelectableOptions, &UserSelectableOption->Link);\r
139\r
140 return EFI_SUCCESS;\r
141}\r
142\r
143/**\r
144 Add user selectable options to option list for different types of Popup.\r
145\r
146 @param PopupType Type of the popup to display.\r
147\r
148 @retval EFI_SUCCESS This function implement successfully.\r
149 @retval EFI_OUT_OF_RESOURCES There are not enough resources available.\r
150\r
151**/\r
152EFI_STATUS\r
153AddUserSelectableOptions (\r
154 IN EFI_HII_POPUP_TYPE PopupType\r
155 )\r
156{\r
1436aea4
MK
157 EFI_STATUS Status;\r
158 UINTN EndCol;\r
159 UINTN StartCol;\r
160 UINTN OptionCol;\r
161 UINTN OptionRow;\r
162 UINTN ColDimension;\r
163\r
164 Status = EFI_SUCCESS;\r
165 EndCol = gPopupDimensions.RightColumn;\r
166 StartCol = gPopupDimensions.LeftColumn;\r
167 OptionRow = gPopupDimensions.BottomRow - POPUP_BORDER;\r
06aad9a2
DB
168 ColDimension = EndCol - StartCol + 1;\r
169\r
170 InitializeListHead (&gUserSelectableOptions);\r
171\r
172 switch (PopupType) {\r
1436aea4
MK
173 case EfiHiiPopupTypeOk:\r
174 //\r
175 // Add [Ok] option to the option list.\r
176 //\r
177 OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_OK_WIDTH) / 2;\r
178 Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionOk, gOkOption, OptionCol, OptionRow);\r
179 break;\r
180 case EfiHiiPopupTypeOkCancel:\r
181 //\r
182 // Add [Ok] and [Cancel] options to the option list.\r
183 //\r
184 OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_OK_CAL_WIDTH) / 3;\r
185 Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionOk, gOkOption, OptionCol, OptionRow);\r
186 OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_OK_CAL_WIDTH) / 3 - (GetStringWidth (gCancelOption) -2) / 2 + 1;\r
187 Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionCancel, gCancelOption, OptionCol, OptionRow);\r
188 break;\r
189 case EfiHiiPopupTypeYesNo:\r
190 //\r
191 // Add [Yes] and [No] options to the option list.\r
192 //\r
193 OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_YES_NO_WIDTH) / 3;\r
194 Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionYes, gYesOption, OptionCol, OptionRow);\r
195 OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_YES_NO_WIDTH) / 3 - (GetStringWidth (gNoOption)- 2) / 2 + 1;\r
196 Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionNo, gNoOption, OptionCol, OptionRow);\r
197 break;\r
198 case EfiHiiPopupTypeYesNoCancel:\r
199 //\r
200 // Add [Yes], [No] and [Cancel] options to the option list.\r
201 //\r
202 OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH) / 4;\r
203 Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionYes, gYesOption, OptionCol, OptionRow);\r
204 OptionCol = StartCol + (ColDimension - (GetStringWidth (gNoOption) -2) / 2) / 2;\r
205 Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionNo, gNoOption, OptionCol, OptionRow);\r
206 OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH) / 4 - (GetStringWidth (gCancelOption) - 2) / 2 + 1;\r
207 Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionCancel, gCancelOption, OptionCol, OptionRow);\r
208 break;\r
209 default:\r
210 break;\r
06aad9a2 211 }\r
1436aea4 212\r
06aad9a2
DB
213 return Status;\r
214}\r
215\r
216/**\r
217 Show selectable options to user and get the one that user select.\r
218\r
219 @param PopupType Type of the popup to display.\r
220 @param UserSelection User selection.\r
221\r
222**/\r
223VOID\r
224GetUserSelection (\r
225 IN EFI_HII_POPUP_TYPE PopupType,\r
226 OUT EFI_HII_POPUP_SELECTION *UserSelection\r
227 )\r
228{\r
1436aea4
MK
229 LIST_ENTRY *HighlightPos;\r
230 LIST_ENTRY *Link;\r
231 USER_SELECTABLE_OPTION *SelectableOption;\r
232 USER_SELECTABLE_OPTION *HighlightOption;\r
233 EFI_INPUT_KEY KeyValue;\r
234 EFI_STATUS Status;\r
06aad9a2
DB
235\r
236 //\r
237 // Display user selectable options in gUserSelectableOptions and get the option which user selects.\r
238 //\r
239 HighlightPos = gUserSelectableOptions.ForwardLink;\r
240 do {\r
241 for (Link = gUserSelectableOptions.ForwardLink; Link != &gUserSelectableOptions; Link = Link->ForwardLink) {\r
1436aea4 242 SelectableOption = SELECTABLE_OPTION_FROM_LINK (Link);\r
06aad9a2
DB
243 DisplayOneSelectableOption (SelectableOption, (BOOLEAN)(Link == HighlightPos));\r
244 }\r
1436aea4 245\r
06aad9a2 246 //\r
1436aea4 247 // If UserSelection is NULL, there is no need to handle the key user input, just return.\r
06aad9a2
DB
248 //\r
249 if (UserSelection == NULL) {\r
250 return;\r
251 }\r
252\r
253 Status = WaitForKeyStroke (&KeyValue);\r
254 ASSERT_EFI_ERROR (Status);\r
255\r
256 HighlightOption = SELECTABLE_OPTION_FROM_LINK (HighlightPos);\r
257 switch (KeyValue.UnicodeChar) {\r
1436aea4
MK
258 case CHAR_NULL:\r
259 switch (KeyValue.ScanCode) {\r
260 case SCAN_RIGHT:\r
261 if (HighlightOption->Sequence < HighlightOption->MaxSequence) {\r
262 HighlightPos = HighlightPos->ForwardLink;\r
263 } else {\r
264 HighlightPos = gUserSelectableOptions.ForwardLink;\r
265 }\r
266\r
267 break;\r
268 case SCAN_LEFT:\r
269 if (HighlightOption->Sequence > HighlightOption->MinSequence) {\r
270 HighlightPos = HighlightPos->BackLink;\r
271 } else {\r
272 HighlightPos = gUserSelectableOptions.BackLink;\r
273 }\r
274\r
275 break;\r
276 default:\r
277 break;\r
06aad9a2 278 }\r
1436aea4 279\r
06aad9a2 280 break;\r
06aad9a2 281\r
1436aea4
MK
282 case CHAR_CARRIAGE_RETURN:\r
283 *UserSelection = HighlightOption->OptionType;\r
06aad9a2 284 return;\r
1436aea4
MK
285 default:\r
286 if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptYes | UPPER_LOWER_CASE_OFFSET)) &&\r
287 ((PopupType == EfiHiiPopupTypeYesNo) || (PopupType == EfiHiiPopupTypeYesNoCancel)))\r
288 {\r
289 *UserSelection = EfiHiiPopupSelectionYes;\r
290 return;\r
291 } else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptNo| UPPER_LOWER_CASE_OFFSET)) &&\r
292 ((PopupType == EfiHiiPopupTypeYesNo) || (PopupType == EfiHiiPopupTypeYesNoCancel)))\r
293 {\r
294 *UserSelection = EfiHiiPopupSelectionNo;\r
295 return;\r
296 } else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptOk | UPPER_LOWER_CASE_OFFSET)) &&\r
297 ((PopupType == EfiHiiPopupTypeOk) || (PopupType == EfiHiiPopupTypeOkCancel)))\r
298 {\r
299 *UserSelection = EfiHiiPopupSelectionOk;\r
300 return;\r
301 } else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptCancel| UPPER_LOWER_CASE_OFFSET)) &&\r
302 ((PopupType == EfiHiiPopupTypeOkCancel) || (PopupType == EfiHiiPopupTypeYesNoCancel)))\r
303 {\r
304 *UserSelection = EfiHiiPopupSelectionCancel;\r
305 return;\r
306 }\r
307\r
308 break;\r
06aad9a2
DB
309 }\r
310 } while (TRUE);\r
311}\r
312\r
313/**\r
314 Get the offset in the input string when the width reaches to a fixed one.\r
315\r
316 The input string may contain NARROW_CHAR and WIDE_CHAR.\r
317 Notice: the input string doesn't contain line break characters.\r
318\r
319 @param String The input string to be counted.\r
320 @param MaxWidth The max length this function supported.\r
321 @param Offset The max index of the string can be show out. If string's width less than MaxWidth, offset will point to the "\0" of the string.\r
322\r
323**/\r
324VOID\r
325GetStringOffsetWithWidth (\r
1436aea4
MK
326 IN CHAR16 *String,\r
327 IN UINTN MaxWidth,\r
328 OUT UINTN *Offset\r
06aad9a2
DB
329 )\r
330{\r
1436aea4
MK
331 UINTN StringWidth;\r
332 UINTN CharWidth;\r
333 UINTN StrOffset;\r
06aad9a2
DB
334\r
335 StringWidth = 0;\r
336 CharWidth = 1;\r
337\r
338 for (StrOffset = 0; String[StrOffset] != CHAR_NULL; StrOffset++) {\r
339 switch (String[StrOffset]) {\r
1436aea4
MK
340 case NARROW_CHAR:\r
341 CharWidth = 1;\r
342 break;\r
343 case WIDE_CHAR:\r
344 CharWidth = 2;\r
345 break;\r
346 default:\r
347 StringWidth += CharWidth;\r
348 if (StringWidth >= MaxWidth) {\r
349 *Offset = StrOffset;\r
350 return;\r
351 }\r
06aad9a2
DB
352 }\r
353 }\r
1436aea4 354\r
06aad9a2
DB
355 *Offset = StrOffset;\r
356}\r
357\r
358/**\r
359 Parse the message to check if it contains line break characters.\r
360 For once call, caller can get the string for one line and the width of the string.\r
361 This function call be called recursively to parse the whole InputString.\r
362\r
363 (Notice: current implementation, it only checks \r, \n characters, it deals \r,\n,\n\r same as \r\n.)\r
364\r
365 @param InputString String description for this option.\r
366 @param OutputString Buffer to copy the string into, caller is responsible for freeing the buffer.\r
367 @param OutputStrWidth The width of OutputString.\r
368 @param Index Where in InputString to start the copy process\r
369\r
370 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer, include the '\0' info.\r
371\r
372**/\r
373UINTN\r
374ParseMessageString (\r
1436aea4
MK
375 IN CHAR16 *InputString,\r
376 OUT CHAR16 **OutputString,\r
377 OUT UINTN *OutputStrWidth,\r
378 IN OUT UINTN *Index\r
06aad9a2
DB
379 )\r
380{\r
1436aea4 381 UINTN StrOffset;\r
06aad9a2 382\r
1436aea4 383 if ((InputString == NULL) || (Index == NULL) || (OutputString == NULL)) {\r
06aad9a2
DB
384 return 0;\r
385 }\r
386\r
387 *OutputStrWidth = 0;\r
388\r
389 //\r
1436aea4 390 // Check the string to see if there are line break characters in the string\r
06aad9a2
DB
391 //\r
392 for (StrOffset = 0;\r
1436aea4
MK
393 InputString[*Index + StrOffset] != CHAR_CARRIAGE_RETURN && InputString[*Index + StrOffset] != CHAR_LINEFEED && InputString[*Index + StrOffset] != CHAR_NULL;\r
394 StrOffset++\r
395 )\r
396 {\r
397 }\r
06aad9a2
DB
398\r
399 //\r
400 // The CHAR_NULL has process last time, this time just return 0 to stand for finishing parsing the InputString.\r
401 //\r
1436aea4 402 if ((StrOffset == 0) && (InputString[*Index + StrOffset] == CHAR_NULL)) {\r
06aad9a2
DB
403 return 0;\r
404 }\r
405\r
406 //\r
407 // Copy the string to OutputString buffer and calculate the width of OutputString.\r
408 //\r
1436aea4 409 *OutputString = AllocateZeroPool ((StrOffset + 1) * sizeof (CHAR16));\r
06aad9a2
DB
410 if (*OutputString == NULL) {\r
411 return 0;\r
412 }\r
1436aea4
MK
413\r
414 CopyMem ((*OutputString), &InputString[*Index], StrOffset * sizeof (CHAR16));\r
06aad9a2
DB
415 *OutputStrWidth = (GetStringWidth (*OutputString) -2) / 2;\r
416\r
417 //\r
418 // Update the value of Index, can be used for marking where to check the input string for next call.\r
419 //\r
420 if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {\r
421 //\r
422 // Skip the /n or /n/r info.\r
423 //\r
424 if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {\r
425 *Index = (*Index + StrOffset + 2);\r
426 } else {\r
427 *Index = (*Index + StrOffset + 1);\r
428 }\r
429 } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) {\r
430 //\r
431 // Skip the /r or /r/n info.\r
432 //\r
433 if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) {\r
434 *Index = (*Index + StrOffset + 2);\r
435 } else {\r
436 *Index = (*Index + StrOffset + 1);\r
437 }\r
438 } else {\r
439 *Index = (*Index + StrOffset);\r
440 }\r
441\r
442 return StrOffset + 1;\r
443}\r
444\r
445/**\r
446 Calculate the position of the popup.\r
447\r
448 @param PopupType Type of the popup to display.\r
449 @param ScreenForPopup The screen dimensions for the popup.\r
450\r
451**/\r
452VOID\r
453CalculatePopupPosition (\r
454 IN EFI_HII_POPUP_TYPE PopupType,\r
455 OUT EFI_SCREEN_DESCRIPTOR *ScreenForPopup\r
456 )\r
457{\r
1436aea4
MK
458 CHAR16 *OutputString;\r
459 UINTN StringIndex;\r
460 UINTN OutputStrWidth;\r
461 UINTN OptionRowWidth;\r
462 UINTN Columns;\r
463 UINTN Rows;\r
06aad9a2
DB
464\r
465 OptionRowWidth = 0;\r
466\r
467 //\r
468 // Calculate the row number which is needed to show the message string and the max width of the string in one row.\r
469 //\r
470 for (StringIndex = 0; ParseMessageString (gMessageString, &OutputString, &OutputStrWidth, &StringIndex) != 0;) {\r
1436aea4 471 gMesStrLineNum++;\r
06aad9a2
DB
472 if (gMaxRowWidth < OutputStrWidth) {\r
473 gMaxRowWidth = OutputStrWidth;\r
474 }\r
1436aea4 475\r
06aad9a2
DB
476 FreePool (OutputString);\r
477 }\r
478\r
479 //\r
480 // Calculate the row width for the selectable options.(OptionRowWidth = Number * SkipWidth + OptionWidth)\r
481 //\r
482 if (PopupType == EfiHiiPopupTypeOk) {\r
483 OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *2 + USER_SELECTABLE_OPTION_OK_WIDTH;\r
484 } else if (PopupType == EfiHiiPopupTypeOkCancel) {\r
485 OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *3 + USER_SELECTABLE_OPTION_OK_CAL_WIDTH;\r
486 } else if (PopupType == EfiHiiPopupTypeYesNo) {\r
487 OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *3 + USER_SELECTABLE_OPTION_YES_NO_WIDTH;\r
488 } else if (PopupType == EfiHiiPopupTypeYesNoCancel) {\r
489 OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *4 + USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH;\r
490 }\r
1436aea4 491\r
06aad9a2
DB
492 if (OptionRowWidth > gMaxRowWidth) {\r
493 gMaxRowWidth = OptionRowWidth;\r
494 }\r
495\r
496 //\r
497 // Avialble row width for message string = screen width - left popup border width - right popup border width.\r
498 // Avialble line number for message string = screen height - 1 - popup header height - popup footer height.\r
499 // (Notice: screen height - 1 because in current UI page, the bottom row of srceen is usded to show Status Bar,not for form itself.\r
500 // So we don't use the bottom row for popup either. If macro STATUS_BAR_HEIGHT changed, we also need to update the height here.)\r
501 //\r
502 // Select the smaller one between actual dimension of message string and the avialble dimension for message string.\r
503 //\r
504 gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Columns, &Rows);\r
1436aea4 505 gMaxRowWidth = MIN (gMaxRowWidth, Columns - 2 * POPUP_BORDER);\r
06aad9a2
DB
506 gMesStrLineNum = MIN (gMesStrLineNum, Rows -1 - POPUP_FOOTER_HEIGHT - POPUP_HEADER_HEIGHT);\r
507\r
508 //\r
509 // Calculate the start column, end column, top row and bottom row for the popup.\r
510 //\r
1436aea4 511 ScreenForPopup->LeftColumn = (Columns -2 * POPUP_BORDER - gMaxRowWidth) / 2;\r
06aad9a2 512 ScreenForPopup->RightColumn = ScreenForPopup->LeftColumn + gMaxRowWidth + 2 * POPUP_BORDER - 1;\r
1436aea4
MK
513 ScreenForPopup->TopRow = (Rows - 1 - POPUP_FOOTER_HEIGHT - POPUP_HEADER_HEIGHT - gMesStrLineNum) / 2;\r
514 ScreenForPopup->BottomRow = ScreenForPopup->TopRow + gMesStrLineNum + POPUP_FOOTER_HEIGHT + POPUP_HEADER_HEIGHT - 1;\r
06aad9a2
DB
515}\r
516\r
517/**\r
518 Draw the Message box.\r
519 +-------------------------------------------+\r
520 | ERROR/WARNING/INFO |\r
521 |-------------------------------------------|\r
522 | popup messages |\r
523 | |\r
524 | user selectable options |\r
525 +-------------------------------------------+\r
526\r
527 @param PopupStyle Popup style to use.\r
528\r
529**/\r
530EFI_STATUS\r
531DrawMessageBox (\r
1436aea4 532 IN EFI_HII_POPUP_STYLE PopupStyle\r
06aad9a2
DB
533 )\r
534{\r
1436aea4
MK
535 UINTN Index;\r
536 UINTN Length;\r
537 UINTN EndCol;\r
538 UINTN TopRow;\r
539 UINTN StartCol;\r
540 UINTN BottomRow;\r
541 CHAR16 Character;\r
542 UINTN DisplayRow;\r
543 UINTN StringIndex;\r
544 CHAR16 *TempString;\r
545 CHAR16 *OutputString;\r
546 UINTN ColDimension;\r
547 UINTN OutputStrWidth;\r
548 UINTN DrawMesStrRowNum;\r
549\r
550 EndCol = gPopupDimensions.RightColumn;\r
551 TopRow = gPopupDimensions.TopRow;\r
552 StartCol = gPopupDimensions.LeftColumn;\r
553 BottomRow = gPopupDimensions.BottomRow;\r
554 ColDimension = EndCol - StartCol + 1;\r
06aad9a2
DB
555 DrawMesStrRowNum = 0;\r
556\r
557 //\r
558 // 1. Draw the top of the message box.\r
559 //\r
560 Character = BOXDRAW_DOWN_RIGHT;\r
561 PrintCharAt (StartCol, TopRow, Character);\r
562 Character = BOXDRAW_HORIZONTAL;\r
563 for (Index = StartCol; Index + 1 < EndCol; Index++) {\r
564 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
565 }\r
1436aea4 566\r
06aad9a2
DB
567 Character = BOXDRAW_DOWN_LEFT;\r
568 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
569\r
570 //\r
571 // 2. Draw the prompt string for different popup styles.\r
572 //\r
1436aea4 573 Character = BOXDRAW_VERTICAL;\r
06aad9a2 574 DisplayRow = TopRow + POPUP_BORDER;\r
1436aea4 575 ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());\r
06aad9a2
DB
576 PrintCharAt (StartCol, DisplayRow, Character);\r
577 PrintCharAt (EndCol, DisplayRow, Character);\r
578 if (PopupStyle == EfiHiiPopupStyleError) {\r
579 PrintStringAt ((ColDimension - (GetStringWidth (gErrorPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gErrorPopup);\r
580 } else if (PopupStyle == EfiHiiPopupStyleWarning) {\r
581 PrintStringAt ((ColDimension - (GetStringWidth (gWarningPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gWarningPopup);\r
582 } else {\r
583 PrintStringAt ((ColDimension - (GetStringWidth (gInfoPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gInfoPopup);\r
584 }\r
585\r
586 //\r
587 // 3. Draw the horizontal line below the prompt string for different popup styles.\r
588 //\r
589 DisplayRow = TopRow + POPUP_BORDER + POPUP_STYLE_STRING_HEIGHT;\r
1436aea4 590 ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());\r
06aad9a2
DB
591 Character = BOXDRAW_HORIZONTAL;\r
592 for (Index = StartCol + 1; Index < EndCol; Index++) {\r
593 PrintCharAt (Index, DisplayRow, Character);\r
594 }\r
1436aea4 595\r
06aad9a2
DB
596 Character = BOXDRAW_VERTICAL;\r
597 PrintCharAt (StartCol, DisplayRow, Character);\r
598 PrintCharAt (EndCol, DisplayRow, Character);\r
599\r
600 //\r
601 // 4. Draw the mesage string.\r
602 //\r
603 DisplayRow = TopRow + POPUP_HEADER_HEIGHT;\r
1436aea4
MK
604 for (Index = DisplayRow, StringIndex = 0; ParseMessageString (gMessageString, &OutputString, &OutputStrWidth, &StringIndex) != 0 && DrawMesStrRowNum < gMesStrLineNum;) {\r
605 ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ());\r
06aad9a2
DB
606 PrintCharAt (StartCol, Index, Character);\r
607 PrintCharAt (EndCol, Index, Character);\r
608 if (OutputStrWidth > gMaxRowWidth) {\r
609 //\r
1436aea4 610 // OutputStrWidth > MaxMesStrWidth, cut off the string and print print ... instead.\r
06aad9a2
DB
611 //\r
612 GetStringOffsetWithWidth (OutputString, gMaxRowWidth, &Length);\r
613 TempString = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));\r
614 if (TempString == NULL) {\r
615 FreePool (OutputString);\r
616 return EFI_OUT_OF_RESOURCES;\r
617 }\r
1436aea4 618\r
06aad9a2
DB
619 StrnCpyS (TempString, Length + 1, OutputString, Length - 3);\r
620 StrCatS (TempString, Length + 1, L"...");\r
621 PrintStringAt ((ColDimension - gMaxRowWidth) / 2 + StartCol, Index, TempString);\r
622 FreePool (TempString);\r
623 } else {\r
624 PrintStringAt ((ColDimension - OutputStrWidth) / 2 + StartCol, Index, OutputString);\r
625 }\r
1436aea4
MK
626\r
627 Index++;\r
628 DrawMesStrRowNum++;\r
06aad9a2
DB
629 FreePool (OutputString);\r
630 }\r
631\r
632 //\r
633 // 5. Draw an empty line after message string.\r
634 //\r
1436aea4 635 ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ());\r
06aad9a2
DB
636 PrintCharAt (StartCol, Index, Character);\r
637 PrintCharAt (EndCol, Index, Character);\r
638 //\r
639 // Check whether the actual string row number beyond the MesStrRowNum, if yes, print the ...... in the row.\r
640 //\r
1436aea4 641 if ((OutputStrWidth > 0) && (DrawMesStrRowNum >= gMesStrLineNum)) {\r
06aad9a2
DB
642 PrintStringAt ((ColDimension - StrLen (L"......")) / 2 + StartCol, Index, L"......");\r
643 }\r
644\r
645 //\r
646 // 6. Draw an empty line which is used to show user selectable options, will draw concrete option strings in function GetUserSelection().\r
647 //\r
1436aea4 648 Character = BOXDRAW_VERTICAL;\r
06aad9a2 649 DisplayRow = BottomRow - POPUP_BORDER;\r
1436aea4 650 ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());\r
06aad9a2
DB
651 PrintCharAt (StartCol, DisplayRow, Character);\r
652 PrintCharAt (EndCol, DisplayRow, Character);\r
653\r
654 //\r
655 // 7. Draw the bottom of the message box.\r
656 //\r
657 Character = BOXDRAW_UP_RIGHT;\r
658 PrintCharAt (StartCol, BottomRow, Character);\r
659 Character = BOXDRAW_HORIZONTAL;\r
660 for (Index = StartCol; Index + 1 < EndCol; Index++) {\r
1436aea4 661 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
06aad9a2 662 }\r
1436aea4 663\r
06aad9a2 664 Character = BOXDRAW_UP_LEFT;\r
1436aea4 665 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
06aad9a2
DB
666\r
667 return EFI_SUCCESS;\r
668}\r
669\r
670/**\r
671 Displays a popup window.\r
672\r
673 @param This A pointer to the EFI_HII_POPUP_PROTOCOL instance.\r
674 @param PopupStyle Popup style to use.\r
675 @param PopupType Type of the popup to display.\r
676 @param HiiHandle HII handle of the string pack containing Message\r
677 @param Message A message to display in the popup box.\r
678 @param UserSelection User selection.\r
679\r
680 @retval EFI_SUCCESS The popup box was successfully displayed.\r
681 @retval EFI_INVALID_PARAMETER HiiHandle and Message do not define a valid HII string.\r
682 @retval EFI_INVALID_PARAMETER PopupType is not one of the values defined by this specification.\r
683 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to display the popup box.\r
684\r
685**/\r
686EFI_STATUS\r
687EFIAPI\r
688CreatePopup (\r
1436aea4
MK
689 IN EFI_HII_POPUP_PROTOCOL *This,\r
690 IN EFI_HII_POPUP_STYLE PopupStyle,\r
691 IN EFI_HII_POPUP_TYPE PopupType,\r
692 IN EFI_HII_HANDLE HiiHandle,\r
693 IN EFI_STRING_ID Message,\r
694 OUT EFI_HII_POPUP_SELECTION *UserSelection OPTIONAL\r
06aad9a2
DB
695 )\r
696{\r
697 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;\r
698 EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;\r
699 EFI_STATUS Status;\r
700\r
701 if ((PopupType < EfiHiiPopupTypeOk) || (PopupType > EfiHiiPopupTypeYesNoCancel)) {\r
702 return EFI_INVALID_PARAMETER;\r
703 }\r
704\r
1436aea4 705 if ((HiiHandle == NULL) || (Message == 0)) {\r
06aad9a2
DB
706 return EFI_INVALID_PARAMETER;\r
707 }\r
708\r
709 gMessageString = HiiGetString (HiiHandle, Message, NULL);\r
1436aea4 710 if (gMessageString == NULL) {\r
06aad9a2
DB
711 return EFI_INVALID_PARAMETER;\r
712 }\r
713\r
1436aea4
MK
714 ConOut = gST->ConOut;\r
715 gMaxRowWidth = 0;\r
06aad9a2
DB
716 gMesStrLineNum = 0;\r
717\r
718 CopyMem (&SavedConsoleMode, ConOut->Mode, sizeof (SavedConsoleMode));\r
719 ConOut->EnableCursor (ConOut, FALSE);\r
720 ConOut->SetAttribute (ConOut, GetPopupColor ());\r
721\r
722 CalculatePopupPosition (PopupType, &gPopupDimensions);\r
723\r
724 Status = DrawMessageBox (PopupStyle);\r
725 if (EFI_ERROR (Status)) {\r
726 goto Done;\r
727 }\r
728\r
729 //\r
730 // Add user selectable options to option list: gUserSelectableOptions\r
731 //\r
732 Status = AddUserSelectableOptions (PopupType);\r
733 if (EFI_ERROR (Status)) {\r
734 goto Done;\r
735 }\r
736\r
737 GetUserSelection (PopupType, UserSelection);\r
738\r
739Done:\r
740 //\r
741 // Restore Conout attributes and free the resources allocate before.\r
742 //\r
743 ConOut->EnableCursor (ConOut, SavedConsoleMode.CursorVisible);\r
744 ConOut->SetCursorPosition (ConOut, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);\r
745 ConOut->SetAttribute (ConOut, SavedConsoleMode.Attribute);\r
746 FreeSelectableOptions (&gUserSelectableOptions);\r
747 FreePool (gMessageString);\r
748\r
749 return Status;\r
750}\r