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 | }
|
---|