Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendirectui.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Boot Loader 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: boot/freeldr/freeldr/ui/directui.c 00005 * PURPOSE: FreeLDR UI Routines 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 */ 00008 #ifdef _M_ARM 00009 00010 /* INCLUDES *******************************************************************/ 00011 00012 #include <freeldr.h> 00013 #include <debug.h> 00014 00015 /* GLOBALS ********************************************************************/ 00016 00017 /* FUNCTIONS ******************************************************************/ 00018 00019 ULONG UiScreenWidth; 00020 ULONG UiScreenHeight; 00021 UCHAR UiMenuFgColor = COLOR_GRAY; 00022 UCHAR UiMenuBgColor = COLOR_BLACK; 00023 UCHAR UiTextColor = COLOR_GRAY; 00024 UCHAR UiSelectedTextColor = COLOR_BLACK; 00025 UCHAR UiSelectedTextBgColor = COLOR_GRAY; 00026 CHAR UiTimeText[260] = "Seconds until highlighted choice will be started automatically: "; 00027 00028 INT 00029 TuiPrintf(const char *Format, 00030 ...) 00031 { 00032 int i; 00033 int Length; 00034 va_list ap; 00035 CHAR Buffer[512]; 00036 00037 va_start(ap, Format); 00038 Length = _vsnprintf(Buffer, sizeof(Buffer), Format, ap); 00039 va_end(ap); 00040 00041 if (Length == -1) Length = sizeof(Buffer); 00042 00043 for (i = 0; i < Length; i++) 00044 { 00045 MachConsPutChar(Buffer[i]); 00046 } 00047 00048 return Length; 00049 } 00050 00051 BOOLEAN 00052 UiInitialize(IN BOOLEAN ShowGui) 00053 { 00054 ULONG Depth; 00055 00056 /* Nothing to do */ 00057 if (!ShowGui) return TRUE; 00058 00059 /* Set mode and query size */ 00060 MachVideoSetDisplayMode(NULL, TRUE); 00061 MachVideoGetDisplaySize(&UiScreenWidth, &UiScreenHeight, &Depth); 00062 return TRUE; 00063 } 00064 00065 VOID 00066 UiUnInitialize(IN PCSTR BootText) 00067 { 00068 /* Nothing to do */ 00069 return; 00070 } 00071 00072 VOID 00073 UiDrawBackdrop(VOID) 00074 { 00075 /* Clear the screen */ 00076 MachVideoClearScreen(ATTR(COLOR_WHITE, COLOR_BLACK)); 00077 } 00078 00079 VOID 00080 UiDrawText(IN ULONG X, 00081 IN ULONG Y, 00082 IN PCSTR Text, 00083 IN UCHAR Attr) 00084 { 00085 ULONG i, j; 00086 00087 /* Draw the text character by character, but don't exceed the width */ 00088 for (i = X, j = 0; Text[j] && i < UiScreenWidth; i++, j++) 00089 { 00090 /* Write the character */ 00091 MachVideoPutChar(Text[j], Attr, i, Y); 00092 } 00093 } 00094 00095 VOID 00096 UiDrawCenteredText(IN ULONG Left, 00097 IN ULONG Top, 00098 IN ULONG Right, 00099 IN ULONG Bottom, 00100 IN PCSTR TextString, 00101 IN UCHAR Attr) 00102 { 00103 ULONG TextLength, BoxWidth, BoxHeight, LineBreakCount, Index, LastIndex; 00104 ULONG RealLeft, RealTop, X, Y; 00105 CHAR Temp[2]; 00106 00107 /* Query text length */ 00108 TextLength = strlen(TextString); 00109 00110 /* Count the new lines and the box width */ 00111 LineBreakCount = 0; 00112 BoxWidth = 0; 00113 LastIndex = 0; 00114 for (Index=0; Index < TextLength; Index++) 00115 { 00116 /* Scan for new lines */ 00117 if (TextString[Index] == '\n') 00118 { 00119 /* Remember the new line */ 00120 LastIndex = Index; 00121 LineBreakCount++; 00122 } 00123 else 00124 { 00125 /* Check for new larger box width */ 00126 if ((Index - LastIndex) > BoxWidth) 00127 { 00128 /* Update it */ 00129 BoxWidth = (Index - LastIndex); 00130 } 00131 } 00132 } 00133 00134 /* Base the box height on the number of lines */ 00135 BoxHeight = LineBreakCount + 1; 00136 00137 /* Create the centered coordinates */ 00138 RealLeft = (((Right - Left) - BoxWidth) / 2) + Left; 00139 RealTop = (((Bottom - Top) - BoxHeight) / 2) + Top; 00140 00141 /* Now go for a second scan */ 00142 LastIndex = 0; 00143 for (Index=0; Index < TextLength; Index++) 00144 { 00145 /* Look for new lines again */ 00146 if (TextString[Index] == '\n') 00147 { 00148 /* Update where the text should start */ 00149 RealTop++; 00150 LastIndex = 0; 00151 } 00152 else 00153 { 00154 /* We've got a line of text to print, do it */ 00155 X = RealLeft + LastIndex; 00156 Y = RealTop; 00157 LastIndex++; 00158 Temp[0] = TextString[Index]; 00159 Temp[1] = 0; 00160 UiDrawText(X, Y, Temp, Attr); 00161 } 00162 } 00163 } 00164 00165 VOID 00166 UiDrawStatusText(IN PCSTR StatusText) 00167 { 00168 return; 00169 } 00170 00171 VOID 00172 UiInfoBox(IN PCSTR MessageText) 00173 { 00174 TuiPrintf(MessageText); 00175 } 00176 00177 VOID 00178 UiMessageBox(IN PCSTR MessageText) 00179 { 00180 TuiPrintf(MessageText); 00181 } 00182 00183 VOID 00184 UiMessageBoxCritical(IN PCSTR MessageText) 00185 { 00186 TuiPrintf(MessageText); 00187 } 00188 00189 VOID 00190 UiDrawProgressBarCenter(IN ULONG Position, 00191 IN ULONG Range, 00192 IN PCHAR ProgressText) 00193 { 00194 ULONG Left, Top, Right, Bottom, Width, Height; 00195 00196 /* Build the coordinates and sizes */ 00197 Height = 2; 00198 Width = UiScreenWidth; 00199 Left = 0; 00200 Right = (Left + Width) - 1; 00201 Top = UiScreenHeight - Height - 4; 00202 Bottom = Top + Height + 1; 00203 00204 /* Draw the progress bar */ 00205 UiDrawProgressBar(Left, Top, Right, Bottom, Position, Range, ProgressText); 00206 } 00207 00208 VOID 00209 UiDrawProgressBar(IN ULONG Left, 00210 IN ULONG Top, 00211 IN ULONG Right, 00212 IN ULONG Bottom, 00213 IN ULONG Position, 00214 IN ULONG Range, 00215 IN PCHAR ProgressText) 00216 { 00217 ULONG i, ProgressBarWidth; 00218 00219 /* Calculate the width of the bar proper */ 00220 ProgressBarWidth = (Right - Left) - 3; 00221 00222 /* First make sure the progress bar text fits */ 00223 UiTruncateStringEllipsis(ProgressText, ProgressBarWidth - 4); 00224 if (Position > Range) Position = Range; 00225 00226 /* Draw the "Loading..." text */ 00227 UiDrawCenteredText(Left + 2, Top + 1, Right - 2, Top + 1, ProgressText, ATTR(7, 0)); 00228 00229 /* Draw the percent complete */ 00230 for (i = 0; i < (Position * ProgressBarWidth) / Range; i++) 00231 { 00232 /* Use the fill character */ 00233 UiDrawText(Left + 2 + i, Top + 2, "\xDB", ATTR(UiTextColor, UiMenuBgColor)); 00234 } 00235 } 00236 00237 VOID 00238 UiShowMessageBoxesInSection(IN PCSTR SectionName) 00239 { 00240 return; 00241 } 00242 00243 VOID 00244 UiTruncateStringEllipsis(IN PCHAR StringText, 00245 IN ULONG MaxChars) 00246 { 00247 /* If it's too large, just add some ellipsis past the maximum */ 00248 if (strlen(StringText) > MaxChars) strcpy(&StringText[MaxChars - 3], "..."); 00249 } 00250 00251 VOID 00252 NTAPI 00253 UiDrawMenuBox(IN PUI_MENU_INFO MenuInfo) 00254 { 00255 CHAR MenuLineText[80], TempString[80]; 00256 ULONG i; 00257 00258 /* If there is a timeout draw the time remaining */ 00259 if (MenuInfo->MenuTimeRemaining >= 0) 00260 { 00261 /* Copy the integral time text string, and remove the last 2 chars */ 00262 strcpy(TempString, UiTimeText); 00263 i = strlen(TempString); 00264 TempString[i - 2] = 0; 00265 00266 /* Display the first part of the string and the remaining time */ 00267 strcpy(MenuLineText, TempString); 00268 _itoa(MenuInfo->MenuTimeRemaining, TempString, 10); 00269 strcat(MenuLineText, TempString); 00270 00271 /* Add the last 2 chars */ 00272 strcat(MenuLineText, &UiTimeText[i - 2]); 00273 00274 /* Display under the menu directly */ 00275 UiDrawText(0, 00276 MenuInfo->Bottom + 3, 00277 MenuLineText, 00278 ATTR(UiMenuFgColor, UiMenuBgColor)); 00279 } 00280 else 00281 { 00282 /* Erase the timeout string with spaces, and 0-terminate for sure */ 00283 for (i=0; i<sizeof(MenuLineText)-1; i++) 00284 { 00285 MenuLineText[i] = ' '; 00286 } 00287 MenuLineText[sizeof(MenuLineText)-1] = 0; 00288 00289 /* Draw this "empty" string to erase */ 00290 UiDrawText(0, 00291 MenuInfo->Bottom + 3, 00292 MenuLineText, 00293 ATTR(UiMenuFgColor, UiMenuBgColor)); 00294 } 00295 00296 /* Loop each item */ 00297 for (i = 0; i < MenuInfo->MenuItemCount; i++) 00298 { 00299 /* Check if it's a separator */ 00300 if (!(_stricmp(MenuInfo->MenuItemList[i], "SEPARATOR"))) 00301 { 00302 /* Draw the separator line */ 00303 UiDrawText(MenuInfo->Left, 00304 MenuInfo->Top + i + 1, 00305 "\xC7", 00306 ATTR(UiMenuFgColor, UiMenuBgColor)); 00307 UiDrawText(MenuInfo->Right, 00308 MenuInfo->Top + i + 1, 00309 "\xB6", 00310 ATTR(UiMenuFgColor, UiMenuBgColor)); 00311 } 00312 } 00313 } 00314 00315 VOID 00316 NTAPI 00317 UiDrawMenuItem(IN PUI_MENU_INFO MenuInfo, 00318 IN ULONG MenuItemNumber) 00319 { 00320 CHAR MenuLineText[80]; 00321 UCHAR Attribute = ATTR(UiTextColor, UiMenuBgColor); 00322 00323 /* Simply left-align it */ 00324 MenuLineText[0] = '\0'; 00325 strcat(MenuLineText, " "); 00326 00327 /* Now append the text string */ 00328 strcat(MenuLineText, MenuInfo->MenuItemList[MenuItemNumber]); 00329 00330 /* If it is a separator */ 00331 if (!(_stricmp(MenuInfo->MenuItemList[MenuItemNumber], "SEPARATOR"))) 00332 { 00333 /* Make it a separator line and use menu colors */ 00334 memset(MenuLineText, 0, 80); 00335 memset(MenuLineText, 0xC4, (MenuInfo->Right - MenuInfo->Left - 1)); 00336 Attribute = ATTR(UiMenuFgColor, UiMenuBgColor); 00337 } 00338 else if (MenuItemNumber == MenuInfo->SelectedMenuItem) 00339 { 00340 /* If this is the selected item, use the selected colors */ 00341 Attribute = ATTR(UiSelectedTextColor, UiSelectedTextBgColor); 00342 } 00343 00344 /* Draw the item */ 00345 UiDrawText(MenuInfo->Left + 1, 00346 MenuInfo->Top + 1 + MenuItemNumber, 00347 MenuLineText, 00348 Attribute); 00349 } 00350 00351 VOID 00352 UiDrawMenu(IN PUI_MENU_INFO MenuInfo) 00353 { 00354 ULONG i; 00355 00356 /* No GUI status bar text, just minimal text. first to tell the user to choose */ 00357 UiDrawText(0, 00358 MenuInfo->Top - 2, 00359 "Please select the operating system to start:", 00360 ATTR(UiMenuFgColor, UiMenuBgColor)); 00361 00362 /* Now tell him how to choose */ 00363 UiDrawText(0, 00364 MenuInfo->Bottom + 1, 00365 "Use the up and down arrow keys to move the highlight to " 00366 "your choice.", 00367 ATTR(UiMenuFgColor, UiMenuBgColor)); 00368 UiDrawText(0, 00369 MenuInfo->Bottom + 2, 00370 "Press ENTER to choose.", 00371 ATTR(UiMenuFgColor, UiMenuBgColor)); 00372 00373 /* And offer F8 options */ 00374 UiDrawText(0, 00375 UiScreenHeight - 4, 00376 "For troubleshooting and advanced startup options for " 00377 "ReactOS, press F8.", 00378 ATTR(UiMenuFgColor, UiMenuBgColor)); 00379 00380 /* Draw the menu box */ 00381 UiDrawMenuBox(MenuInfo); 00382 00383 /* Draw each line of the menu */ 00384 for (i = 0; i < MenuInfo->MenuItemCount; i++) UiDrawMenuItem(MenuInfo, i); 00385 } 00386 00387 ULONG 00388 NTAPI 00389 UiProcessMenuKeyboardEvent(IN PUI_MENU_INFO MenuInfo, 00390 IN UiMenuKeyPressFilterCallback KeyPressFilter) 00391 { 00392 ULONG KeyEvent = 0, Selected, Count; 00393 00394 /* Check for a keypress */ 00395 if (MachConsKbHit()) 00396 { 00397 /* Check if the timeout is not already complete */ 00398 if (MenuInfo->MenuTimeRemaining != -1) 00399 { 00400 // 00401 // Cancel it and remove it 00402 // 00403 MenuInfo->MenuTimeRemaining = -1; 00404 UiDrawMenuBox(MenuInfo); 00405 } 00406 00407 /* Get the key */ 00408 KeyEvent = MachConsGetCh(); 00409 00410 /* Is it extended? Then get the extended key */ 00411 if (!KeyEvent) KeyEvent = MachConsGetCh(); 00412 00413 /* Call the supplied key filter callback function to see if it is going to handle this keypress. */ 00414 if ((KeyPressFilter) && (KeyPressFilter(KeyEvent))) 00415 { 00416 /* It processed the key character, so redraw and exit */ 00417 UiDrawMenu(MenuInfo); 00418 return 0; 00419 } 00420 00421 /* Process the key */ 00422 if ((KeyEvent == KEY_UP) || (KeyEvent == KEY_DOWN)) 00423 { 00424 /* Get the current selected item and count */ 00425 Selected = MenuInfo->SelectedMenuItem; 00426 Count = MenuInfo->MenuItemCount - 1; 00427 00428 /* Check if this was a key up and there's a selected menu item */ 00429 if ((KeyEvent == KEY_UP) && (Selected)) 00430 { 00431 /* Update the menu (Deselect previous item) */ 00432 MenuInfo->SelectedMenuItem--; 00433 UiDrawMenuItem(MenuInfo, Selected); 00434 Selected--; 00435 00436 /* Skip past any separators */ 00437 if ((Selected) && 00438 !(_stricmp(MenuInfo->MenuItemList[Selected], "SEPARATOR"))) 00439 { 00440 MenuInfo->SelectedMenuItem--; 00441 } 00442 } 00443 else if ((KeyEvent == KEY_DOWN) && (Selected < Count)) 00444 { 00445 /* Update the menu (deselect previous item) */ 00446 MenuInfo->SelectedMenuItem++; 00447 UiDrawMenuItem(MenuInfo, Selected); 00448 Selected++; 00449 00450 /* Skip past any separators */ 00451 if ((Selected < Count) && 00452 !(_stricmp(MenuInfo->MenuItemList[Selected], "SEPARATOR"))) 00453 { 00454 MenuInfo->SelectedMenuItem++; 00455 } 00456 } 00457 00458 /* Select new item and update video buffer */ 00459 UiDrawMenuItem(MenuInfo, MenuInfo->SelectedMenuItem); 00460 } 00461 } 00462 00463 /* Return the pressed key */ 00464 return KeyEvent; 00465 } 00466 00467 VOID 00468 NTAPI 00469 UiCalcMenuBoxSize(IN PUI_MENU_INFO MenuInfo) 00470 { 00471 ULONG i, Width = 0, Height, Length; 00472 00473 /* Height is the menu item count plus 2 (top border & bottom border) */ 00474 Height = MenuInfo->MenuItemCount + 2; 00475 Height -= 1; // Height is zero-based 00476 00477 /* Loop every item */ 00478 for (i = 0; i < MenuInfo->MenuItemCount; i++) 00479 { 00480 /* Get the string length and make it become the new width if necessary */ 00481 Length = strlen(MenuInfo->MenuItemList[i]); 00482 if (Length > Width) Width = Length; 00483 } 00484 00485 /* Allow room for left & right borders, plus 8 spaces on each side */ 00486 Width += 18; 00487 00488 /* Put the menu in the default left-corner position */ 00489 MenuInfo->Left = -1; 00490 MenuInfo->Top = 4; 00491 00492 /* The other margins are the same */ 00493 MenuInfo->Right = (MenuInfo->Left) + Width; 00494 MenuInfo->Bottom = (MenuInfo->Top) + Height; 00495 } 00496 00497 BOOLEAN 00498 UiDisplayMenu(IN PCSTR MenuItemList[], 00499 IN ULONG MenuItemCount, 00500 IN ULONG DefaultMenuItem, 00501 IN LONG MenuTimeOut, 00502 OUT PULONG SelectedMenuItem, 00503 IN BOOLEAN CanEscape, 00504 IN UiMenuKeyPressFilterCallback KeyPressFilter) 00505 { 00506 UI_MENU_INFO MenuInformation; 00507 ULONG LastClockSecond; 00508 ULONG CurrentClockSecond; 00509 ULONG KeyPress; 00510 00511 /* Check if there's no timeout */ 00512 if (!MenuTimeOut) 00513 { 00514 /* Return the default selected item */ 00515 if (SelectedMenuItem) *SelectedMenuItem = DefaultMenuItem; 00516 return TRUE; 00517 } 00518 00519 /* Setup the MENU_INFO structure */ 00520 MenuInformation.MenuItemList = MenuItemList; 00521 MenuInformation.MenuItemCount = MenuItemCount; 00522 MenuInformation.MenuTimeRemaining = MenuTimeOut; 00523 MenuInformation.SelectedMenuItem = DefaultMenuItem; 00524 00525 /* Calculate the size of the menu box */ 00526 UiCalcMenuBoxSize(&MenuInformation); 00527 00528 /* Draw the menu */ 00529 UiDrawMenu(&MenuInformation); 00530 00531 /* Get the current second of time */ 00532 LastClockSecond = ArcGetTime()->Second; 00533 00534 /* Process keys */ 00535 while (TRUE) 00536 { 00537 /* Process key presses */ 00538 KeyPress = UiProcessMenuKeyboardEvent(&MenuInformation, 00539 KeyPressFilter); 00540 00541 /* Check for ENTER or ESC */ 00542 if (KeyPress == KEY_ENTER) break; 00543 if (CanEscape && KeyPress == KEY_ESC) return FALSE; 00544 00545 /* Check if there is a countdown */ 00546 if (MenuInformation.MenuTimeRemaining) 00547 { 00548 /* Get the updated time, seconds only */ 00549 CurrentClockSecond = ArcGetTime()->Second; 00550 00551 /* Check if more then a second has now elapsed */ 00552 if (CurrentClockSecond != LastClockSecond) 00553 { 00554 /* Update the time information */ 00555 LastClockSecond = CurrentClockSecond; 00556 MenuInformation.MenuTimeRemaining--; 00557 00558 /* Update the menu */ 00559 UiDrawMenuBox(&MenuInformation); 00560 } 00561 } 00562 else 00563 { 00564 /* A time out occurred, exit this loop and return default OS */ 00565 break; 00566 } 00567 } 00568 00569 /* Return the selected item */ 00570 if (SelectedMenuItem) *SelectedMenuItem = MenuInformation.SelectedMenuItem; 00571 return TRUE; 00572 } 00573 00574 #endif Generated on Sun May 27 2012 04:19:17 for ReactOS by
1.7.6.1
|