]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/DisplayEngineDxe/Popup.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / Popup.c
... / ...
CommitLineData
1/** @file\r
2Implementation for Hii Popup Protocol.\r
3\r
4Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
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
24FreeSelectableOptions (\r
25 LIST_ENTRY *OptionList\r
26 )\r
27{\r
28 LIST_ENTRY *Link;\r
29 USER_SELECTABLE_OPTION *SelectableOption;\r
30\r
31 while (!IsListEmpty (OptionList)) {\r
32 Link = GetFirstNode (OptionList);\r
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
47DisplayOneSelectableOption (\r
48 IN USER_SELECTABLE_OPTION *SelectableOption,\r
49 IN BOOLEAN Highlight\r
50 )\r
51{\r
52 if (Highlight) {\r
53 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
54 }\r
55\r
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
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
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
88\r
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
93 UserSelectableOption->Signature = USER_SELECTABLE_OPTION_SIGNATURE;\r
94 UserSelectableOption->OptionString = OptionString;\r
95 UserSelectableOption->OptionType = OptionType;\r
96 UserSelectableOption->OptionCol = OptionCol;\r
97 UserSelectableOption->OptionRow = OptionRow;\r
98 UserSelectableOption->MinSequence = 0;\r
99\r
100 switch (PopupType) {\r
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
136 }\r
137\r
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
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
168 ColDimension = EndCol - StartCol + 1;\r
169\r
170 InitializeListHead (&gUserSelectableOptions);\r
171\r
172 switch (PopupType) {\r
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
211 }\r
212\r
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
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
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
242 SelectableOption = SELECTABLE_OPTION_FROM_LINK (Link);\r
243 DisplayOneSelectableOption (SelectableOption, (BOOLEAN)(Link == HighlightPos));\r
244 }\r
245\r
246 //\r
247 // If UserSelection is NULL, there is no need to handle the key user input, just return.\r
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
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
278 }\r
279\r
280 break;\r
281\r
282 case CHAR_CARRIAGE_RETURN:\r
283 *UserSelection = HighlightOption->OptionType;\r
284 return;\r
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
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
326 IN CHAR16 *String,\r
327 IN UINTN MaxWidth,\r
328 OUT UINTN *Offset\r
329 )\r
330{\r
331 UINTN StringWidth;\r
332 UINTN CharWidth;\r
333 UINTN StrOffset;\r
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
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
352 }\r
353 }\r
354\r
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
375 IN CHAR16 *InputString,\r
376 OUT CHAR16 **OutputString,\r
377 OUT UINTN *OutputStrWidth,\r
378 IN OUT UINTN *Index\r
379 )\r
380{\r
381 UINTN StrOffset;\r
382\r
383 if ((InputString == NULL) || (Index == NULL) || (OutputString == NULL)) {\r
384 return 0;\r
385 }\r
386\r
387 *OutputStrWidth = 0;\r
388\r
389 //\r
390 // Check the string to see if there are line break characters in the string\r
391 //\r
392 for (StrOffset = 0;\r
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
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
402 if ((StrOffset == 0) && (InputString[*Index + StrOffset] == CHAR_NULL)) {\r
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
409 *OutputString = AllocateZeroPool ((StrOffset + 1) * sizeof (CHAR16));\r
410 if (*OutputString == NULL) {\r
411 return 0;\r
412 }\r
413\r
414 CopyMem ((*OutputString), &InputString[*Index], StrOffset * sizeof (CHAR16));\r
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
458 CHAR16 *OutputString;\r
459 UINTN StringIndex;\r
460 UINTN OutputStrWidth;\r
461 UINTN OptionRowWidth;\r
462 UINTN Columns;\r
463 UINTN Rows;\r
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
471 gMesStrLineNum++;\r
472 if (gMaxRowWidth < OutputStrWidth) {\r
473 gMaxRowWidth = OutputStrWidth;\r
474 }\r
475\r
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
491\r
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
505 gMaxRowWidth = MIN (gMaxRowWidth, Columns - 2 * POPUP_BORDER);\r
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
511 ScreenForPopup->LeftColumn = (Columns -2 * POPUP_BORDER - gMaxRowWidth) / 2;\r
512 ScreenForPopup->RightColumn = ScreenForPopup->LeftColumn + gMaxRowWidth + 2 * POPUP_BORDER - 1;\r
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
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
532 IN EFI_HII_POPUP_STYLE PopupStyle\r
533 )\r
534{\r
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
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
566\r
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
573 Character = BOXDRAW_VERTICAL;\r
574 DisplayRow = TopRow + POPUP_BORDER;\r
575 ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());\r
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
590 ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());\r
591 Character = BOXDRAW_HORIZONTAL;\r
592 for (Index = StartCol + 1; Index < EndCol; Index++) {\r
593 PrintCharAt (Index, DisplayRow, Character);\r
594 }\r
595\r
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
604 for (Index = DisplayRow, StringIndex = 0; ParseMessageString (gMessageString, &OutputString, &OutputStrWidth, &StringIndex) != 0 && DrawMesStrRowNum < gMesStrLineNum;) {\r
605 ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ());\r
606 PrintCharAt (StartCol, Index, Character);\r
607 PrintCharAt (EndCol, Index, Character);\r
608 if (OutputStrWidth > gMaxRowWidth) {\r
609 //\r
610 // OutputStrWidth > MaxMesStrWidth, cut off the string and print print ... instead.\r
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
618\r
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
626\r
627 Index++;\r
628 DrawMesStrRowNum++;\r
629 FreePool (OutputString);\r
630 }\r
631\r
632 //\r
633 // 5. Draw an empty line after message string.\r
634 //\r
635 ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ());\r
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
641 if ((OutputStrWidth > 0) && (DrawMesStrRowNum >= gMesStrLineNum)) {\r
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
648 Character = BOXDRAW_VERTICAL;\r
649 DisplayRow = BottomRow - POPUP_BORDER;\r
650 ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());\r
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
661 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
662 }\r
663\r
664 Character = BOXDRAW_UP_LEFT;\r
665 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
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
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
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
705 if ((HiiHandle == NULL) || (Message == 0)) {\r
706 return EFI_INVALID_PARAMETER;\r
707 }\r
708\r
709 gMessageString = HiiGetString (HiiHandle, Message, NULL);\r
710 if (gMessageString == NULL) {\r
711 return EFI_INVALID_PARAMETER;\r
712 }\r
713\r
714 ConOut = gST->ConOut;\r
715 gMaxRowWidth = 0;\r
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