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