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