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