ReactOS  0.4.14-dev-342-gdc047f9
tuimenu.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: FreeLoader
4  * FILE: boot/freeldr/freeldr/ui/tuimenu.c
5  * PURPOSE: UI Menu Functions
6  * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7  * Brian Palmer (brianp@sginet.com)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 #ifndef _M_ARM
12 #include <freeldr.h>
13 
14 /* FUNCTIONS *****************************************************************/
15 
16 BOOLEAN
18  IN PCSTR MenuHeader,
19  IN PCSTR MenuFooter OPTIONAL,
20  IN BOOLEAN ShowBootOptions,
21  IN PCSTR MenuItemList[],
22  IN ULONG MenuItemCount,
23  IN ULONG DefaultMenuItem,
24  IN LONG MenuTimeOut,
25  OUT PULONG SelectedMenuItem,
26  IN BOOLEAN CanEscape,
29 {
30  UI_MENU_INFO MenuInformation;
31  ULONG LastClockSecond;
32  ULONG CurrentClockSecond;
33  ULONG KeyPress;
34 
35  //
36  // Before taking any default action if there is no timeout,
37  // check whether the supplied key filter callback function
38  // may handle a specific user keypress. If it does, the
39  // timeout is cancelled.
40  //
41  if (!MenuTimeOut && KeyPressFilter && MachConsKbHit())
42  {
43  //
44  // Get the key (get the extended key if needed)
45  //
46  KeyPress = MachConsGetCh();
47  if (KeyPress == KEY_EXTENDED)
48  KeyPress = MachConsGetCh();
49 
50  //
51  // Call the supplied key filter callback function to see
52  // if it is going to handle this keypress.
53  //
54  if (KeyPressFilter(KeyPress, DefaultMenuItem, Context))
55  {
56  //
57  // It processed the key character, cancel the timeout
58  //
59  MenuTimeOut = -1;
60  }
61  }
62 
63  //
64  // Check if there's no timeout
65  //
66  if (!MenuTimeOut)
67  {
68  //
69  // Return the default selected item
70  //
71  if (SelectedMenuItem) *SelectedMenuItem = DefaultMenuItem;
72  return TRUE;
73  }
74 
75  //
76  // Setup the MENU_INFO structure
77  //
78  MenuInformation.MenuHeader = MenuHeader;
79  MenuInformation.MenuFooter = MenuFooter;
80  MenuInformation.ShowBootOptions = ShowBootOptions;
81  MenuInformation.MenuItemList = MenuItemList;
82  MenuInformation.MenuItemCount = MenuItemCount;
83  MenuInformation.MenuTimeRemaining = MenuTimeOut;
84  MenuInformation.SelectedMenuItem = DefaultMenuItem;
85  MenuInformation.Context = Context;
86 
87  //
88  // Calculate the size of the menu box
89  //
90  TuiCalcMenuBoxSize(&MenuInformation);
91 
92  //
93  // Draw the menu
94  //
95  UiVtbl.DrawMenu(&MenuInformation);
96 
97  //
98  // Get the current second of time
99  //
100  LastClockSecond = ArcGetTime()->Second;
101 
102  //
103  // Process keys
104  //
105  while (TRUE)
106  {
107  //
108  // Process key presses
109  //
110  KeyPress = TuiProcessMenuKeyboardEvent(&MenuInformation, KeyPressFilter);
111 
112  //
113  // Check for ENTER or ESC
114  //
115  if (KeyPress == KEY_ENTER) break;
116  if (CanEscape && KeyPress == KEY_ESC) return FALSE;
117 
118  //
119  // Update the date & time
120  //
123 
124  //
125  // Check if there is a countdown
126  //
127  if (MenuInformation.MenuTimeRemaining > 0)
128  {
129  //
130  // Get the updated time, seconds only
131  //
132  CurrentClockSecond = ArcGetTime()->Second;
133 
134  //
135  // Check if more then a second has now elapsed
136  //
137  if (CurrentClockSecond != LastClockSecond)
138  {
139  //
140  // Update the time information
141  //
142  LastClockSecond = CurrentClockSecond;
143  MenuInformation.MenuTimeRemaining--;
144 
145  //
146  // Update the menu
147  //
148  TuiDrawMenuBox(&MenuInformation);
150  }
151  }
152  else if (MenuInformation.MenuTimeRemaining == 0)
153  {
154  //
155  // A time out occurred, exit this loop and return default OS
156  //
157  break;
158  }
159 
160  MachHwIdle();
161  }
162 
163  //
164  // Return the selected item
165  //
166  if (SelectedMenuItem) *SelectedMenuItem = MenuInformation.SelectedMenuItem;
167  return TRUE;
168 }
169 
170 VOID
172 {
173  ULONG i;
174  ULONG Width = 0;
175  ULONG Height;
176  ULONG Length;
177 
178  //
179  // Height is the menu item count plus 2 (top border & bottom border)
180  //
181  Height = MenuInfo->MenuItemCount + 2;
182  Height -= 1; // Height is zero-based
183 
184  //
185  // Loop every item
186  //
187  for(i = 0; i < MenuInfo->MenuItemCount; i++)
188  {
189  //
190  // Get the string length and make it become the new width if necessary
191  //
192  if (MenuInfo->MenuItemList[i])
193  {
194  Length = (ULONG)strlen(MenuInfo->MenuItemList[i]);
195  if (Length > Width) Width = Length;
196  }
197  }
198 
199  //
200  // Allow room for left & right borders, plus 8 spaces on each side
201  //
202  Width += 18;
203 
204  //
205  // Check if we're drawing a centered menu
206  //
207  if (UiCenterMenu)
208  {
209  //
210  // Calculate the menu box area for a centered menu
211  //
212  MenuInfo->Left = (UiScreenWidth - Width) / 2;
214  Height) / 2) + TUI_TITLE_BOX_CHAR_HEIGHT;
215  }
216  else
217  {
218  //
219  // Put the menu in the default left-corner position
220  //
221  MenuInfo->Left = -1;
222  MenuInfo->Top = 4;
223  }
224 
225  //
226  // The other margins are the same
227  //
228  MenuInfo->Right = (MenuInfo->Left) + Width;
229  MenuInfo->Bottom = (MenuInfo->Top) + Height;
230 }
231 
232 VOID
234 {
235  ULONG i;
236 
237  //
238  // Draw the backdrop
239  //
240  UiDrawBackdrop();
241 
242  //
243  // Update the status bar
244  //
245  UiVtbl.DrawStatusText("Use \x18 and \x19 to select, then press ENTER.");
246 
247  //
248  // Draw the menu box
249  //
251 
252  //
253  // Draw each line of the menu
254  //
255  for (i = 0; i < MenuInfo->MenuItemCount; i++)
256  {
258  }
259 
260  /* Display the boot options if needed */
261  if (MenuInfo->ShowBootOptions)
262  {
264  }
265 
267 }
268 
269 VOID
271 {
272  CHAR MenuLineText[80], TempString[80];
273  ULONG i;
274 
275  //
276  // Draw the menu box if requested
277  //
278  if (UiMenuBox)
279  {
280  UiDrawBox(MenuInfo->Left,
281  MenuInfo->Top,
282  MenuInfo->Right,
283  MenuInfo->Bottom,
284  D_VERT,
285  D_HORZ,
286  FALSE, // Filled
287  TRUE, // Shadow
289  }
290 
291  //
292  // If there is a timeout draw the time remaining
293  //
294  if (MenuInfo->MenuTimeRemaining >= 0)
295  {
296  //
297  // Copy the integral time text string, and remove the last 2 chars
298  //
299  strcpy(TempString, UiTimeText);
300  i = (ULONG)strlen(TempString);
301  TempString[i - 2] = 0;
302 
303  //
304  // Display the first part of the string and the remaining time
305  //
306  strcpy(MenuLineText, TempString);
307  _itoa(MenuInfo->MenuTimeRemaining, TempString, 10);
308  strcat(MenuLineText, TempString);
309 
310  //
311  // Add the last 2 chars
312  //
313  strcat(MenuLineText, &UiTimeText[i - 2]);
314 
315  //
316  // Check if this is a centered menu
317  //
318  if (UiCenterMenu)
319  {
320  //
321  // Display it in the center of the menu
322  //
323  UiDrawText(MenuInfo->Right - (ULONG)strlen(MenuLineText) - 1,
324  MenuInfo->Bottom,
325  MenuLineText,
327  }
328  else
329  {
330  //
331  // Display under the menu directly
332  //
333  UiDrawText(0,
334  MenuInfo->Bottom + 4,
335  MenuLineText,
337  }
338  }
339  else
340  {
341  //
342  // Erase the timeout string with spaces, and 0-terminate for sure
343  //
344  for (i=0; i<sizeof(MenuLineText)-1; i++)
345  {
346  MenuLineText[i] = ' ';
347  }
348  MenuLineText[sizeof(MenuLineText)-1] = 0;
349 
350  //
351  // Draw this "empty" string to erase
352  //
353  if (UiCenterMenu)
354  {
355  UiDrawText(MenuInfo->Right - (ULONG)strlen(MenuLineText) - 1,
356  MenuInfo->Bottom,
357  MenuLineText,
359  }
360  else
361  {
362  UiDrawText(0,
363  MenuInfo->Bottom + 4,
364  MenuLineText,
366  }
367  }
368 
369  //
370  // Loop each item
371  //
372  for (i = 0; i < MenuInfo->MenuItemCount; i++)
373  {
374  //
375  // Check if it's a separator
376  //
377  if (MenuInfo->MenuItemList[i] == NULL)
378  {
379  //
380  // Draw the separator line
381  //
382  UiDrawText(MenuInfo->Left,
383  MenuInfo->Top + i + 1,
384  "\xC7",
386  UiDrawText(MenuInfo->Right,
387  MenuInfo->Top + i + 1,
388  "\xB6",
390  }
391  }
392 }
393 
394 VOID
396  ULONG MenuItemNumber)
397 {
398  ULONG i;
399  CHAR MenuLineText[80];
400  ULONG SpaceTotal;
401  ULONG SpaceLeft;
402  ULONG SpaceRight = 0;
403  UCHAR Attribute = ATTR(UiTextColor, UiMenuBgColor);
404 
405  //
406  // Check if using centered menu
407  //
408  if (UiCenterMenu)
409  {
410  //
411  // We will want the string centered so calculate
412  // how many spaces will be to the left and right
413  //
414  SpaceTotal = (MenuInfo->Right - MenuInfo->Left - 2) -
415  (ULONG)(MenuInfo->MenuItemList[MenuItemNumber] ?
416  strlen(MenuInfo->MenuItemList[MenuItemNumber]) : 0);
417  SpaceLeft = (SpaceTotal / 2) + 1;
418  SpaceRight = (SpaceTotal - SpaceLeft) + 1;
419 
420  //
421  // Insert the spaces on the left
422  //
423  for (i = 0; i < SpaceLeft; i++) MenuLineText[i] = ' ';
424  MenuLineText[i] = '\0';
425  }
426  else
427  {
428  //
429  // Simply left-align it
430  //
431  MenuLineText[0] = '\0';
432  strcat(MenuLineText, " ");
433  }
434 
435  //
436  // Now append the text string
437  //
438  if (MenuInfo->MenuItemList[MenuItemNumber])
439  strcat(MenuLineText, MenuInfo->MenuItemList[MenuItemNumber]);
440 
441  //
442  // Check if using centered menu, and add spaces on the right if so
443  //
444  if (UiCenterMenu) for (i=0; i < SpaceRight; i++) strcat(MenuLineText, " ");
445 
446  //
447  // If it is a separator
448  //
449  if (MenuInfo->MenuItemList[MenuItemNumber] == NULL)
450  {
451  //
452  // Make it a separator line and use menu colors
453  //
454  memset(MenuLineText, 0, 80);
455  memset(MenuLineText, 0xC4, (MenuInfo->Right - MenuInfo->Left - 1));
456  Attribute = ATTR(UiMenuFgColor, UiMenuBgColor);
457  }
458  else if (MenuItemNumber == MenuInfo->SelectedMenuItem)
459  {
460  //
461  // If this is the selected item, use the selected colors
462  //
464  }
465 
466  //
467  // Draw the item
468  //
469  UiDrawText(MenuInfo->Left + 1,
470  MenuInfo->Top + 1 + MenuItemNumber,
471  MenuLineText,
472  Attribute);
473 }
474 
475 ULONG
477  UiMenuKeyPressFilterCallback KeyPressFilter)
478 {
479  ULONG KeyEvent = 0;
480  ULONG Selected, Count;
481 
482  //
483  // Check for a keypress
484  //
485  if (!MachConsKbHit())
486  return 0; // None, bail out
487 
488  //
489  // Check if the timeout is not already complete
490  //
491  if (MenuInfo->MenuTimeRemaining != -1)
492  {
493  //
494  // Cancel it and remove it
495  //
496  MenuInfo->MenuTimeRemaining = -1;
497  TuiDrawMenuBox(MenuInfo); // FIXME: Remove for minimal UI too
498  }
499 
500  //
501  // Get the key (get the extended key if needed)
502  //
503  KeyEvent = MachConsGetCh();
504  if (KeyEvent == KEY_EXTENDED)
505  KeyEvent = MachConsGetCh();
506 
507  //
508  // Call the supplied key filter callback function to see
509  // if it is going to handle this keypress.
510  //
511  if (KeyPressFilter &&
512  KeyPressFilter(KeyEvent, MenuInfo->SelectedMenuItem, MenuInfo->Context))
513  {
514  //
515  // It processed the key character, so redraw and exit
516  //
518  return 0;
519  }
520 
521  //
522  // Process the key
523  //
524  if ((KeyEvent == KEY_UP ) || (KeyEvent == KEY_DOWN) ||
525  (KeyEvent == KEY_HOME) || (KeyEvent == KEY_END ))
526  {
527  //
528  // Get the current selected item and count
529  //
530  Selected = MenuInfo->SelectedMenuItem;
531  Count = MenuInfo->MenuItemCount - 1;
532 
533  //
534  // Check the key and change the selected menu item
535  //
536  if ((KeyEvent == KEY_UP) && (Selected > 0))
537  {
538  //
539  // Deselect previous item and go up
540  //
541  MenuInfo->SelectedMenuItem--;
542  TuiDrawMenuItem(MenuInfo, Selected);
543  Selected--;
544 
545  // Skip past any separators
546  if ((Selected > 0) &&
547  (MenuInfo->MenuItemList[Selected] == NULL))
548  {
549  MenuInfo->SelectedMenuItem--;
550  }
551  }
552  else if ( ((KeyEvent == KEY_UP) && (Selected == 0)) ||
553  (KeyEvent == KEY_END) )
554  {
555  //
556  // Go to the end
557  //
558  MenuInfo->SelectedMenuItem = Count;
559  TuiDrawMenuItem(MenuInfo, Selected);
560  }
561  else if ((KeyEvent == KEY_DOWN) && (Selected < Count))
562  {
563  //
564  // Deselect previous item and go down
565  //
566  MenuInfo->SelectedMenuItem++;
567  TuiDrawMenuItem(MenuInfo, Selected);
568  Selected++;
569 
570  // Skip past any separators
571  if ((Selected < Count) &&
572  (MenuInfo->MenuItemList[Selected] == NULL))
573  {
574  MenuInfo->SelectedMenuItem++;
575  }
576  }
577  else if ( ((KeyEvent == KEY_DOWN) && (Selected == Count)) ||
578  (KeyEvent == KEY_HOME) )
579  {
580  //
581  // Go to the beginning
582  //
583  MenuInfo->SelectedMenuItem = 0;
584  TuiDrawMenuItem(MenuInfo, Selected);
585  }
586 
587  //
588  // Select new item and update video buffer
589  //
590  TuiDrawMenuItem(MenuInfo, MenuInfo->SelectedMenuItem);
592  }
593 
594  //
595  // Return the pressed key
596  //
597  return KeyEvent;
598 }
599 #endif
PCSTR MenuHeader
Definition: ui.h:103
ULONG MenuItemCount
Definition: ui.h:108
#define IN
Definition: typedefs.h:38
LONG MenuTimeRemaining
Definition: ui.h:109
#define TRUE
Definition: types.h:120
UCHAR UiTextColor
Definition: ui.c:42
#define MachConsGetCh()
Definition: machine.h:90
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
#define MachHwIdle()
Definition: machine.h:137
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
CHAR UiTimeText[]
Definition: ui.c:54
#define KEY_DOWN
Definition: keycodes.h:31
VOID TuiUpdateDateTime(VOID)
Definition: tui.c:428
char CHAR
Definition: xmlstorage.h:175
VOID TuiDrawMenu(PUI_MENU_INFO MenuInfo)
Definition: tuimenu.c:233
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
USHORT Second
Definition: fw.h:16
ULONG UiScreenHeight
Definition: ui.c:29
VOID TuiCalcMenuBoxSize(PUI_MENU_INFO MenuInfo)
Definition: tuimenu.c:171
#define TUI_TITLE_BOX_CHAR_HEIGHT
Definition: tui.h:23
#define KEY_EXTENDED
Definition: keycodes.h:23
VOID VideoCopyOffScreenBufferToVRAM(VOID)
Definition: video.c:34
BOOLEAN UiCenterMenu
Definition: ui.c:52
PVOID Context
Definition: ui.h:111
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
UIVTBL UiVtbl
Definition: ui.c:58
long LONG
Definition: pedump.c:60
BOOLEAN ShowBootOptions
Definition: ui.h:105
#define ATTR(cFore, cBack)
Definition: ui.h:192
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
TIMEINFO * ArcGetTime(VOID)
Definition: arcemul.c:27
VOID UiDrawText(ULONG X, ULONG Y, PCSTR Text, UCHAR Attr)
Definition: ui.c:234
#define MachConsKbHit()
Definition: machine.h:88
_CRTIMP char *__cdecl _itoa(_In_ int _Value, _Pre_notnull_ _Post_z_ char *_Dest, _In_ int _Radix)
#define D_HORZ
Definition: ui.h:229
#define KEY_ESC
Definition: keycodes.h:34
BOOLEAN UiMenuBox
Definition: ui.c:53
ULONG SelectedMenuItem
Definition: ui.h:110
ULONG TuiProcessMenuKeyboardEvent(PUI_MENU_INFO MenuInfo, UiMenuKeyPressFilterCallback KeyPressFilter)
Definition: tuimenu.c:476
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
VOID UiDrawBox(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, UCHAR VertStyle, UCHAR HorzStyle, BOOLEAN Fill, BOOLEAN Shadow, UCHAR Attr)
Definition: ui.c:229
BOOLEAN TuiDisplayMenu(IN PCSTR MenuHeader, IN PCSTR MenuFooter OPTIONAL, IN BOOLEAN ShowBootOptions, IN PCSTR MenuItemList[], IN ULONG MenuItemCount, IN ULONG DefaultMenuItem, IN LONG MenuTimeOut, OUT PULONG SelectedMenuItem, IN BOOLEAN CanEscape, IN UiMenuKeyPressFilterCallback KeyPressFilter OPTIONAL, IN PVOID Context OPTIONAL)
Definition: tuimenu.c:17
#define KEY_HOME
Definition: keycodes.h:29
unsigned char UCHAR
Definition: xmlstorage.h:181
BOOLEAN(* UiMenuKeyPressFilterCallback)(IN ULONG KeyPress, IN ULONG SelectedMenuItem, IN PVOID Context OPTIONAL)
Definition: ui.h:121
UCHAR UiMenuBgColor
Definition: ui.c:41
VOID UiDrawBackdrop(VOID)
Definition: ui.c:214
menu info structure
Definition: window.h:275
VOID(* DrawMenu)(PUI_MENU_INFO MenuInfo)
Definition: ui.h:182
VOID(* DrawStatusText)(PCSTR StatusText)
Definition: ui.h:157
UCHAR UiSelectedTextBgColor
Definition: ui.c:44
#define KEY_UP
Definition: keycodes.h:30
VOID TuiDrawMenuBox(PUI_MENU_INFO MenuInfo)
Definition: tuimenu.c:270
unsigned int * PULONG
Definition: retypes.h:1
#define OUT
Definition: typedefs.h:39
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
VOID DisplayBootTimeOptions(VOID)
Definition: options.c:181
struct tagContext Context
Definition: acpixf.h:1030
unsigned int ULONG
Definition: retypes.h:1
UCHAR UiMenuFgColor
Definition: ui.c:40
const char * PCSTR
Definition: typedefs.h:51
PCSTR MenuFooter
Definition: ui.h:104
ULONG UiScreenWidth
Definition: ui.c:28
#define KEY_END
Definition: keycodes.h:49
#define memset(x, y, z)
Definition: compat.h:39
#define D_VERT
Definition: ui.h:231
PCSTR * MenuItemList
Definition: ui.h:107
#define KEY_ENTER
Definition: keycodes.h:24
VOID TuiDrawMenuItem(PUI_MENU_INFO MenuInfo, ULONG MenuItemNumber)
Definition: tuimenu.c:395
UCHAR UiSelectedTextColor
Definition: ui.c:43
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68