2 * COPYRIGHT: See COPYING in the top level directory
4 * FILE: freeldr/ui/tuimenu.c
5 * PURPOSE: UI Menu Functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Brian Palmer (brianp@sginet.com)
10 /* INCLUDES ******************************************************************/
14 /* FUNCTIONS *****************************************************************/
17 TuiDisplayMenu(PCSTR MenuHeader
,
19 BOOLEAN ShowBootOptions
,
22 ULONG DefaultMenuItem
,
24 ULONG
* SelectedMenuItem
,
26 UiMenuKeyPressFilterCallback KeyPressFilter
)
28 UI_MENU_INFO MenuInformation
;
29 ULONG LastClockSecond
;
30 ULONG CurrentClockSecond
;
34 // Check if there's no timeout
38 // Return the default selected item
40 if (SelectedMenuItem
) *SelectedMenuItem
= DefaultMenuItem
;
45 // Setup the MENU_INFO structure
47 MenuInformation
.MenuHeader
= MenuHeader
;
48 MenuInformation
.MenuFooter
= MenuFooter
;
49 MenuInformation
.ShowBootOptions
= ShowBootOptions
;
50 MenuInformation
.MenuItemList
= MenuItemList
;
51 MenuInformation
.MenuItemCount
= MenuItemCount
;
52 MenuInformation
.MenuTimeRemaining
= MenuTimeOut
;
53 MenuInformation
.SelectedMenuItem
= DefaultMenuItem
;
56 // Calculate the size of the menu box
58 TuiCalcMenuBoxSize(&MenuInformation
);
63 UiVtbl
.DrawMenu(&MenuInformation
);
66 // Get the current second of time
68 LastClockSecond
= ArcGetTime()->Second
;
76 // Process key presses
78 KeyPress
= TuiProcessMenuKeyboardEvent(&MenuInformation
,
82 // Check for ENTER or ESC
84 if (KeyPress
== KEY_ENTER
) break;
85 if (CanEscape
&& KeyPress
== KEY_ESC
) return FALSE
;
88 // Update the date & time
91 VideoCopyOffScreenBufferToVRAM();
94 // Check if there is a countdown
96 if (MenuInformation
.MenuTimeRemaining
> 0)
99 // Get the updated time, seconds only
101 CurrentClockSecond
= ArcGetTime()->Second
;
104 // Check if more then a second has now elapsed
106 if (CurrentClockSecond
!= LastClockSecond
)
109 // Update the time information
111 LastClockSecond
= CurrentClockSecond
;
112 MenuInformation
.MenuTimeRemaining
--;
117 TuiDrawMenuBox(&MenuInformation
);
118 VideoCopyOffScreenBufferToVRAM();
121 else if (MenuInformation
.MenuTimeRemaining
== 0)
124 // A time out occurred, exit this loop and return default OS
133 // Return the selected item
135 if (SelectedMenuItem
) *SelectedMenuItem
= MenuInformation
.SelectedMenuItem
;
141 TuiCalcMenuBoxSize(PUI_MENU_INFO MenuInfo
)
149 // Height is the menu item count plus 2 (top border & bottom border)
151 Height
= MenuInfo
->MenuItemCount
+ 2;
152 Height
-= 1; // Height is zero-based
157 for(i
= 0; i
< MenuInfo
->MenuItemCount
; i
++)
160 // Get the string length and make it become the new width if necessary
162 if (MenuInfo
->MenuItemList
[i
])
164 Length
= (ULONG
)strlen(MenuInfo
->MenuItemList
[i
]);
165 if (Length
> Width
) Width
= Length
;
170 // Allow room for left & right borders, plus 8 spaces on each side
175 // Check if we're drawing a centered menu
180 // Calculate the menu box area for a centered menu
182 MenuInfo
->Left
= (UiScreenWidth
- Width
) / 2;
183 MenuInfo
->Top
= (((UiScreenHeight
- TUI_TITLE_BOX_CHAR_HEIGHT
) -
184 Height
) / 2) + TUI_TITLE_BOX_CHAR_HEIGHT
;
189 // Put the menu in the default left-corner position
196 // The other margins are the same
198 MenuInfo
->Right
= (MenuInfo
->Left
) + Width
;
199 MenuInfo
->Bottom
= (MenuInfo
->Top
) + Height
;
203 TuiDrawMenu(PUI_MENU_INFO MenuInfo
)
213 // Update the status bar
215 UiVtbl
.DrawStatusText("Use \x18 and \x19 to select, then press ENTER.");
220 TuiDrawMenuBox(MenuInfo
);
223 // Draw each line of the menu
225 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++)
227 TuiDrawMenuItem(MenuInfo
, i
);
230 /* Display the boot options if needed */
231 if (MenuInfo
->ShowBootOptions
)
233 DisplayBootTimeOptions();
236 VideoCopyOffScreenBufferToVRAM();
241 TuiDrawMenuBox(PUI_MENU_INFO MenuInfo
)
243 CHAR MenuLineText
[80], TempString
[80];
247 // Draw the menu box if requested
251 UiDrawBox(MenuInfo
->Left
,
259 ATTR(UiMenuFgColor
, UiMenuBgColor
));
263 // If there is a timeout draw the time remaining
265 if (MenuInfo
->MenuTimeRemaining
>= 0)
268 // Copy the integral time text string, and remove the last 2 chars
270 strcpy(TempString
, UiTimeText
);
271 i
= (ULONG
)strlen(TempString
);
272 TempString
[i
- 2] = 0;
275 // Display the first part of the string and the remaining time
277 strcpy(MenuLineText
, TempString
);
278 _itoa(MenuInfo
->MenuTimeRemaining
, TempString
, 10);
279 strcat(MenuLineText
, TempString
);
282 // Add the last 2 chars
284 strcat(MenuLineText
, &UiTimeText
[i
- 2]);
287 // Check if this is a centered menu
292 // Display it in the center of the menu
294 UiDrawText(MenuInfo
->Right
- (ULONG
)strlen(MenuLineText
) - 1,
297 ATTR(UiMenuFgColor
, UiMenuBgColor
));
302 // Display under the menu directly
305 MenuInfo
->Bottom
+ 4,
307 ATTR(UiMenuFgColor
, UiMenuBgColor
));
313 // Erase the timeout string with spaces, and 0-terminate for sure
315 for (i
=0; i
<sizeof(MenuLineText
)-1; i
++)
317 MenuLineText
[i
] = ' ';
319 MenuLineText
[sizeof(MenuLineText
)-1] = 0;
322 // Draw this "empty" string to erase
326 UiDrawText(MenuInfo
->Right
- (ULONG
)strlen(MenuLineText
) - 1,
329 ATTR(UiMenuFgColor
, UiMenuBgColor
));
334 MenuInfo
->Bottom
+ 4,
336 ATTR(UiMenuFgColor
, UiMenuBgColor
));
343 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++)
346 // Check if it's a separator
348 if (MenuInfo
->MenuItemList
[i
] == NULL
)
351 // Draw the separator line
353 UiDrawText(MenuInfo
->Left
,
354 MenuInfo
->Top
+ i
+ 1,
356 ATTR(UiMenuFgColor
, UiMenuBgColor
));
357 UiDrawText(MenuInfo
->Right
,
358 MenuInfo
->Top
+ i
+ 1,
360 ATTR(UiMenuFgColor
, UiMenuBgColor
));
367 TuiDrawMenuItem(PUI_MENU_INFO MenuInfo
,
368 ULONG MenuItemNumber
)
371 CHAR MenuLineText
[80];
374 ULONG SpaceRight
= 0;
375 UCHAR Attribute
= ATTR(UiTextColor
, UiMenuBgColor
);
378 // Check if using centered menu
383 // We will want the string centered so calculate
384 // how many spaces will be to the left and right
386 SpaceTotal
= (MenuInfo
->Right
- MenuInfo
->Left
- 2) -
387 (ULONG
)(MenuInfo
->MenuItemList
[MenuItemNumber
] ?
388 strlen(MenuInfo
->MenuItemList
[MenuItemNumber
]) : 0);
389 SpaceLeft
= (SpaceTotal
/ 2) + 1;
390 SpaceRight
= (SpaceTotal
- SpaceLeft
) + 1;
393 // Insert the spaces on the left
395 for (i
= 0; i
< SpaceLeft
; i
++) MenuLineText
[i
] = ' ';
396 MenuLineText
[i
] = '\0';
401 // Simply left-align it
403 MenuLineText
[0] = '\0';
404 strcat(MenuLineText
, " ");
408 // Now append the text string
410 if (MenuInfo
->MenuItemList
[MenuItemNumber
])
411 strcat(MenuLineText
, MenuInfo
->MenuItemList
[MenuItemNumber
]);
414 // Check if using centered menu, and add spaces on the right if so
416 if (UiCenterMenu
) for (i
=0; i
< SpaceRight
; i
++) strcat(MenuLineText
, " ");
419 // If it is a separator
421 if (MenuInfo
->MenuItemList
[MenuItemNumber
] == NULL
)
424 // Make it a separator line and use menu colors
426 memset(MenuLineText
, 0, 80);
427 memset(MenuLineText
, 0xC4, (MenuInfo
->Right
- MenuInfo
->Left
- 1));
428 Attribute
= ATTR(UiMenuFgColor
, UiMenuBgColor
);
430 else if (MenuItemNumber
== MenuInfo
->SelectedMenuItem
)
433 // If this is the selected item, use the selected colors
435 Attribute
= ATTR(UiSelectedTextColor
, UiSelectedTextBgColor
);
441 UiDrawText(MenuInfo
->Left
+ 1,
442 MenuInfo
->Top
+ 1 + MenuItemNumber
,
449 TuiProcessMenuKeyboardEvent(PUI_MENU_INFO MenuInfo
,
450 UiMenuKeyPressFilterCallback KeyPressFilter
)
453 ULONG Selected
, Count
;
456 // Check for a keypress
461 // Check if the timeout is not already complete
463 if (MenuInfo
->MenuTimeRemaining
!= -1)
466 // Cancel it and remove it
468 MenuInfo
->MenuTimeRemaining
= -1;
469 TuiDrawMenuBox(MenuInfo
); // FIXME: Remove for minimal UI too
475 KeyEvent
= MachConsGetCh();
478 // Is it extended? Then get the extended key
480 if (!KeyEvent
) KeyEvent
= MachConsGetCh();
483 // Call the supplied key filter callback function to see
484 // if it is going to handle this keypress.
486 if ((KeyPressFilter
) && (KeyPressFilter(KeyEvent
)))
489 // It processed the key character, so redraw and exit
491 UiVtbl
.DrawMenu(MenuInfo
);
498 if ((KeyEvent
== KEY_UP
) || (KeyEvent
== KEY_DOWN
))
501 // Get the current selected item and count
503 Selected
= MenuInfo
->SelectedMenuItem
;
504 Count
= MenuInfo
->MenuItemCount
- 1;
507 // Check if this was a key up and there's a selected menu item
509 if ((KeyEvent
== KEY_UP
) && (Selected
))
512 // Update the menu (Deselect previous item)
514 MenuInfo
->SelectedMenuItem
--;
515 TuiDrawMenuItem(MenuInfo
, Selected
);
518 // Skip past any separators
520 (MenuInfo
->MenuItemList
[Selected
] == NULL
))
522 MenuInfo
->SelectedMenuItem
--;
525 else if ((KeyEvent
== KEY_DOWN
) && (Selected
< Count
))
528 // Update the menu (deselect previous item)
530 MenuInfo
->SelectedMenuItem
++;
531 TuiDrawMenuItem(MenuInfo
, Selected
);
534 // Skip past any separators
535 if ((Selected
< Count
) &&
536 (MenuInfo
->MenuItemList
[Selected
] == NULL
))
538 MenuInfo
->SelectedMenuItem
++;
543 // Select new item and update video buffer
545 TuiDrawMenuItem(MenuInfo
, MenuInfo
->SelectedMenuItem
);
546 VideoCopyOffScreenBufferToVRAM();
551 // Return the pressed key