/** @file\r
Implementation for handling user input from the User Interfaces.\r
\r
-Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
\r
@param MenuOption Pointer to the current input menu.\r
@param Prompt The prompt string shown on popup window.\r
- @param StringPtr Destination for use input string.\r
+ @param StringPtr Old user input and destination for use input string.\r
\r
@retval EFI_SUCCESS If string input is read successfully\r
@retval EFI_DEVICE_ERROR If operation fails\r
**/\r
EFI_STATUS\r
ReadString (\r
- IN UI_MENU_OPTION *MenuOption,\r
- IN CHAR16 *Prompt,\r
- OUT CHAR16 *StringPtr\r
+ IN UI_MENU_OPTION *MenuOption,\r
+ IN CHAR16 *Prompt,\r
+ IN OUT CHAR16 *StringPtr\r
)\r
{\r
EFI_STATUS Status;\r
CHAR16 *TempString;\r
CHAR16 *BufferedString;\r
UINTN Index;\r
+ UINTN Index2;\r
UINTN Count;\r
UINTN Start;\r
UINTN Top;\r
UINTN DimensionsWidth;\r
UINTN DimensionsHeight;\r
+ UINTN CurrentCursor;\r
BOOLEAN CursorVisible;\r
UINTN Minimum;\r
UINTN Maximum;\r
CursorVisible = gST->ConOut->Mode->CursorVisible;\r
gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
\r
+ CurrentCursor = GetStringWidth (StringPtr) / 2 - 1;\r
+ if (CurrentCursor != 0) {\r
+ //\r
+ // Show the string which has beed saved before.\r
+ //\r
+ SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');\r
+ PrintStringAt (Start + 1, Top + 3, BufferedString);\r
+\r
+ if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {\r
+ Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;\r
+ } else {\r
+ Index = 0;\r
+ }\r
+\r
+ if (IsPassword) {\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);\r
+ }\r
+\r
+ for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {\r
+ BufferedString[Count] = StringPtr[Index];\r
+\r
+ if (IsPassword) {\r
+ PrintChar (L'*');\r
+ }\r
+ }\r
+\r
+ if (!IsPassword) {\r
+ PrintStringAt (Start + 1, Top + 3, BufferedString);\r
+ }\r
+ \r
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);\r
+ }\r
+ \r
do {\r
Status = WaitForKeyStroke (&Key);\r
ASSERT_EFI_ERROR (Status);\r
case CHAR_NULL:\r
switch (Key.ScanCode) {\r
case SCAN_LEFT:\r
+ if (CurrentCursor > 0) {\r
+ CurrentCursor--;\r
+ }\r
break;\r
\r
case SCAN_RIGHT:\r
+ if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) {\r
+ CurrentCursor++;\r
+ }\r
break;\r
\r
case SCAN_ESC:\r
break;\r
\r
case CHAR_BACKSPACE:\r
- if (StringPtr[0] != CHAR_NULL) {\r
- for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {\r
+ if (StringPtr[0] != CHAR_NULL && CurrentCursor != 0) {\r
+ for (Index = 0; Index < CurrentCursor - 1; Index++) {\r
TempString[Index] = StringPtr[Index];\r
}\r
+ Count = GetStringWidth (StringPtr) / 2 - 1;\r
+ if (Count >= CurrentCursor) {\r
+ for (Index = CurrentCursor - 1, Index2 = CurrentCursor; Index2 < Count; Index++, Index2++) {\r
+ TempString[Index] = StringPtr[Index2];\r
+ }\r
+ TempString[Index] = CHAR_NULL;\r
+ }\r
//\r
// Effectively truncate string by 1 character\r
//\r
- TempString[Index - 1] = CHAR_NULL;\r
StrCpy (StringPtr, TempString);\r
+ CurrentCursor --;\r
}\r
\r
default:\r
//\r
if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
StrnCpy (StringPtr, &Key.UnicodeChar, 1);\r
- StrnCpy (TempString, &Key.UnicodeChar, 1);\r
+ CurrentCursor++;\r
} else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
KeyPad[0] = Key.UnicodeChar;\r
KeyPad[1] = CHAR_NULL;\r
- StrCat (StringPtr, KeyPad);\r
- StrCat (TempString, KeyPad);\r
+ Count = GetStringWidth (StringPtr) / 2 - 1;\r
+ if (CurrentCursor < Count) {\r
+ for (Index = 0; Index < CurrentCursor; Index++) {\r
+ TempString[Index] = StringPtr[Index];\r
+ }\r
+ TempString[Index] = CHAR_NULL;\r
+ StrCat (TempString, KeyPad);\r
+ StrCat (TempString, StringPtr + CurrentCursor);\r
+ StrCpy (StringPtr, TempString);\r
+ } else {\r
+ StrCat (StringPtr, KeyPad);\r
+ }\r
+ CurrentCursor++;\r
}\r
\r
//\r
}\r
\r
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
- gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3);\r
} while (TRUE);\r
\r
}\r
\r
+/**\r
+ Adjust the value to the correct one. Rules follow the sample:\r
+ like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01\r
+ Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28\r
+\r
+ @param Question Pointer to current question.\r
+ @param Sequence The sequence of the field in the question.\r
+**/\r
+VOID\r
+AdjustQuestionValue (\r
+ IN FORM_BROWSER_STATEMENT *Question,\r
+ IN UINT8 Sequence\r
+ )\r
+{\r
+ UINT8 Month;\r
+ UINT16 Year;\r
+ UINT8 Maximum;\r
+ UINT8 Minimum;\r
+\r
+ if (Question->Operand != EFI_IFR_DATE_OP) {\r
+ return;\r
+ }\r
+\r
+ Month = Question->HiiValue.Value.date.Month;\r
+ Year = Question->HiiValue.Value.date.Year;\r
+ Minimum = 1;\r
+\r
+ switch (Month) {\r
+ case 2:\r
+ if ((Year % 4) == 0 && ((Year % 100) != 0 || (Year % 400) == 0)) {\r
+ Maximum = 29;\r
+ } else {\r
+ Maximum = 28;\r
+ }\r
+ break;\r
+ case 4:\r
+ case 6:\r
+ case 9:\r
+ case 11:\r
+ Maximum = 30;\r
+ break;\r
+ default:\r
+ Maximum = 31;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Change the month area.\r
+ //\r
+ if (Sequence == 0) {\r
+ if (Question->HiiValue.Value.date.Day > Maximum) {\r
+ Question->HiiValue.Value.date.Day = Maximum;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Change the Year area.\r
+ //\r
+ if (Sequence == 2) {\r
+ if (Question->HiiValue.Value.date.Day > Maximum) {\r
+ Question->HiiValue.Value.date.Day = Minimum;\r
+ }\r
+ }\r
+}\r
\r
/**\r
This routine reads a numeric value from the user input.\r
break;\r
\r
case 1:\r
- Maximum = 31;\r
+ switch (QuestionValue->Value.date.Month) {\r
+ case 2:\r
+ if ((QuestionValue->Value.date.Year % 4) == 0 && \r
+ ((QuestionValue->Value.date.Year % 100) != 0 || \r
+ (QuestionValue->Value.date.Year % 400) == 0)) {\r
+ Maximum = 29;\r
+ } else {\r
+ Maximum = 28;\r
+ }\r
+ break;\r
+ case 4:\r
+ case 6:\r
+ case 9:\r
+ case 11:\r
+ Maximum = 30;\r
+ break;\r
+ default:\r
+ Maximum = 31;\r
+ break;\r
+ } \r
+\r
EraseLen = 3;\r
EditValue = QuestionValue->Value.date.Day;\r
break;\r
\r
if ((Step != 0) && !ManualInput) {\r
if (Key.ScanCode == SCAN_LEFT) {\r
- if (EditValue > Step) {\r
+ if (EditValue >= Minimum + Step) {\r
EditValue = EditValue - Step;\r
- } else {\r
+ } else if (EditValue > Minimum){\r
EditValue = Minimum;\r
+ } else {\r
+ EditValue = Maximum;\r
}\r
} else if (Key.ScanCode == SCAN_RIGHT) {\r
- EditValue = EditValue + Step;\r
- if (EditValue > Maximum) {\r
+ if (EditValue + Step <= Maximum) {\r
+ EditValue = EditValue + Step;\r
+ } else if (EditValue < Maximum) {\r
EditValue = Maximum;\r
+ } else {\r
+ EditValue = Minimum;\r
}\r
}\r
\r
PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
}\r
\r
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
for (Loop = 0; Loop < EraseLen; Loop++) {\r
PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");\r
}\r
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor));\r
\r
if (MenuOption->Sequence == 0) {\r
PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);\r
QuestionValue->Value.u64 = EditValue;\r
}\r
\r
+ //\r
+ // Adjust the value to the correct one.\r
+ // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01\r
+ // 2013.03.29 -> 2013.02.29 -> 2013.02.28\r
+ //\r
+ if (Question->Operand == EFI_IFR_DATE_OP && \r
+ (MenuOption->Sequence == 0 || MenuOption->Sequence == 2)) {\r
+ AdjustQuestionValue (Question, (UINT8)MenuOption->Sequence);\r
+ }\r
+\r
//\r
// Check to see if the Value is something reasonable against consistency limitations.\r
// If not, let's kick the error specified.\r
//\r
// NV flag is unnecessary for RTC type of Date/Time\r
//\r
- UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
+ UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
}\r
}\r
\r
// Remove a character\r
//\r
EditValue = PreviousNumber[Count - 1];\r
- UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE);\r
+ UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);\r
Count--;\r
Column--;\r
PrintAt (Column, Row, L" ");\r
} else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {\r
Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A);\r
} else {\r
- UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE);\r
+ UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);\r
break;\r
}\r
} else {\r
if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {\r
- UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE);\r
+ UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);\r
break;\r
}\r
}\r
}\r
\r
if (EditValue > Maximum) {\r
- UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE);\r
+ UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);\r
ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));\r
EditValue = PreviousNumber[Count];\r
break;\r
} else {\r
- UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE);\r
+ UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);\r
}\r
\r
Count++;\r
QUESTION_OPTION *OneOfOption;\r
QUESTION_OPTION *CurrentOption;\r
FORM_BROWSER_STATEMENT *Question;\r
+ INTN Result;\r
\r
DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
\r
RemoveEntryList (&OneOfOption->Link);\r
\r
if ((OneOfOption->SuppressExpression != NULL) &&\r
- (OneOfOption->SuppressExpression->Result.Value.b)) {\r
+ EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {\r
//\r
// This option is suppressed, insert to tail\r
//\r
}\r
FreePool (StringPtr);\r
\r
- if (!OrderedList && CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, NULL) == 0) {\r
+ if (!OrderedList && (CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {\r
//\r
// Find current selected Option for OneOf\r
//\r
Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn;\r
End = Start + PopUpWidth + POPUP_FRAME_WIDTH;\r
Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;\r
- Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - 1;\r
+ Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - 1;\r
\r
MenuLinesInView = Bottom - Top - 1;\r
if (MenuLinesInView >= PopUpMenuLines) {\r
Link = GetNextNode (&Question->OptionListHead, Link);\r
\r
StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);\r
+ ASSERT (StringPtr != NULL);\r
//\r
// If the string occupies multiple lines, truncate it to fit in one line,\r
// and append a "..." for indication.\r
GetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
} else {\r
SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
- UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
+ UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
}\r
\r
return Status;\r