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