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