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
,
21 ULONG DefaultMenuItem
,
23 ULONG
* SelectedMenuItem
,
25 UiMenuKeyPressFilterCallback KeyPressFilter
)
27 UI_MENU_INFO MenuInformation
;
28 ULONG LastClockSecond
;
29 ULONG CurrentClockSecond
;
33 // Check if there's no timeout
37 // Return the default selected item
39 if (SelectedMenuItem
) *SelectedMenuItem
= DefaultMenuItem
;
44 // Setup the MENU_INFO structure
46 MenuInformation
.MenuHeader
= MenuHeader
;
47 MenuInformation
.MenuFooter
= MenuFooter
;
48 MenuInformation
.MenuItemList
= MenuItemList
;
49 MenuInformation
.MenuItemCount
= MenuItemCount
;
50 MenuInformation
.MenuTimeRemaining
= MenuTimeOut
;
51 MenuInformation
.SelectedMenuItem
= DefaultMenuItem
;
54 // Calculate the size of the menu box
56 TuiCalcMenuBoxSize(&MenuInformation
);
61 UiVtbl
.DrawMenu(&MenuInformation
);
64 // Get the current second of time
66 LastClockSecond
= ArcGetTime()->Second
;
74 // Process key presses
76 KeyPress
= TuiProcessMenuKeyboardEvent(&MenuInformation
,
80 // Check for ENTER or ESC
82 if (KeyPress
== KEY_ENTER
) break;
83 if (CanEscape
&& KeyPress
== KEY_ESC
) return FALSE
;
86 // Update the date & time
89 VideoCopyOffScreenBufferToVRAM();
92 // Check if there is a countdown
94 if (MenuInformation
.MenuTimeRemaining
)
97 // Get the updated time, seconds only
99 CurrentClockSecond
= ArcGetTime()->Second
;
102 // Check if more then a second has now elapsed
104 if (CurrentClockSecond
!= LastClockSecond
)
107 // Update the time information
109 LastClockSecond
= CurrentClockSecond
;
110 MenuInformation
.MenuTimeRemaining
--;
115 TuiDrawMenuBox(&MenuInformation
);
116 VideoCopyOffScreenBufferToVRAM();
122 // A time out occurred, exit this loop and return default OS
131 // Return the selected item
133 if (SelectedMenuItem
) *SelectedMenuItem
= MenuInformation
.SelectedMenuItem
;
139 TuiCalcMenuBoxSize(PUI_MENU_INFO MenuInfo
)
147 // Height is the menu item count plus 2 (top border & bottom border)
149 Height
= MenuInfo
->MenuItemCount
+ 2;
150 Height
-= 1; // Height is zero-based
155 for(i
= 0; i
< MenuInfo
->MenuItemCount
; i
++)
158 // Get the string length and make it become the new width if necessary
160 Length
= (ULONG
)strlen(MenuInfo
->MenuItemList
[i
]);
161 if (Length
> Width
) Width
= Length
;
165 // Allow room for left & right borders, plus 8 spaces on each side
170 // Check if we're drawing a centered menu
175 // Calculate the menu box area for a centered menu
177 MenuInfo
->Left
= (UiScreenWidth
- Width
) / 2;
178 MenuInfo
->Top
= (((UiScreenHeight
- TUI_TITLE_BOX_CHAR_HEIGHT
) -
179 Height
) / 2) + TUI_TITLE_BOX_CHAR_HEIGHT
;
184 // Put the menu in the default left-corner position
191 // The other margins are the same
193 MenuInfo
->Right
= (MenuInfo
->Left
) + Width
;
194 MenuInfo
->Bottom
= (MenuInfo
->Top
) + Height
;
198 TuiDrawMenu(PUI_MENU_INFO MenuInfo
)
208 // Update the status bar
210 UiVtbl
.DrawStatusText("Use \x18 and \x19 to select, then press ENTER.");
215 TuiDrawMenuBox(MenuInfo
);
218 // Draw each line of the menu
220 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++)
222 TuiDrawMenuItem(MenuInfo
, i
);
225 VideoCopyOffScreenBufferToVRAM();
230 TuiDrawMenuBox(PUI_MENU_INFO MenuInfo
)
232 CHAR MenuLineText
[80], TempString
[80];
236 // Draw the menu box if requested
240 UiDrawBox(MenuInfo
->Left
,
248 ATTR(UiMenuFgColor
, UiMenuBgColor
));
252 // If there is a timeout draw the time remaining
254 if (MenuInfo
->MenuTimeRemaining
>= 0)
257 // Copy the integral time text string, and remove the last 2 chars
259 strcpy(TempString
, UiTimeText
);
260 i
= (ULONG
)strlen(TempString
);
261 TempString
[i
- 2] = 0;
264 // Display the first part of the string and the remaining time
266 strcpy(MenuLineText
, TempString
);
267 _itoa(MenuInfo
->MenuTimeRemaining
, TempString
, 10);
268 strcat(MenuLineText
, TempString
);
271 // Add the last 2 chars
273 strcat(MenuLineText
, &UiTimeText
[i
- 2]);
276 // Check if this is a centered menu
281 // Display it in the center of the menu
283 UiDrawText(MenuInfo
->Right
- (ULONG
)strlen(MenuLineText
) - 1,
286 ATTR(UiMenuFgColor
, UiMenuBgColor
));
291 // Display under the menu directly
294 MenuInfo
->Bottom
+ 4,
296 ATTR(UiMenuFgColor
, UiMenuBgColor
));
302 // Erase the timeout string with spaces, and 0-terminate for sure
304 for (i
=0; i
<sizeof(MenuLineText
)-1; i
++)
306 MenuLineText
[i
] = ' ';
308 MenuLineText
[sizeof(MenuLineText
)-1] = 0;
311 // Draw this "empty" string to erase
315 UiDrawText(MenuInfo
->Right
- (ULONG
)strlen(MenuLineText
) - 1,
318 ATTR(UiMenuFgColor
, UiMenuBgColor
));
323 MenuInfo
->Bottom
+ 4,
325 ATTR(UiMenuFgColor
, UiMenuBgColor
));
332 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++)
335 // Check if it's a separator
337 if (!(_stricmp(MenuInfo
->MenuItemList
[i
], "SEPARATOR")))
340 // Draw the separator line
342 UiDrawText(MenuInfo
->Left
,
343 MenuInfo
->Top
+ i
+ 1,
345 ATTR(UiMenuFgColor
, UiMenuBgColor
));
346 UiDrawText(MenuInfo
->Right
,
347 MenuInfo
->Top
+ i
+ 1,
349 ATTR(UiMenuFgColor
, UiMenuBgColor
));
356 TuiDrawMenuItem(PUI_MENU_INFO MenuInfo
,
357 ULONG MenuItemNumber
)
360 CHAR MenuLineText
[80];
363 ULONG SpaceRight
= 0;
364 UCHAR Attribute
= ATTR(UiTextColor
, UiMenuBgColor
);
367 // Check if using centered menu
372 // We will want the string centered so calculate
373 // how many spaces will be to the left and right
375 SpaceTotal
= (MenuInfo
->Right
- MenuInfo
->Left
- 2) -
376 (ULONG
)strlen(MenuInfo
->MenuItemList
[MenuItemNumber
]);
377 SpaceLeft
= (SpaceTotal
/ 2) + 1;
378 SpaceRight
= (SpaceTotal
- SpaceLeft
) + 1;
381 // Insert the spaces on the left
383 for (i
= 0; i
< SpaceLeft
; i
++) MenuLineText
[i
] = ' ';
384 MenuLineText
[i
] = '\0';
389 // Simply left-align it
391 MenuLineText
[0] = '\0';
392 strcat(MenuLineText
, " ");
396 // Now append the text string
398 strcat(MenuLineText
, MenuInfo
->MenuItemList
[MenuItemNumber
]);
401 // Check if using centered menu, and add spaces on the right if so
403 if (UiCenterMenu
) for (i
=0; i
< SpaceRight
; i
++) strcat(MenuLineText
, " ");
406 // If it is a separator
408 if (!(_stricmp(MenuInfo
->MenuItemList
[MenuItemNumber
], "SEPARATOR")))
411 // Make it a separator line and use menu colors
413 memset(MenuLineText
, 0, 80);
414 memset(MenuLineText
, 0xC4, (MenuInfo
->Right
- MenuInfo
->Left
- 1));
415 Attribute
= ATTR(UiMenuFgColor
, UiMenuBgColor
);
417 else if (MenuItemNumber
== MenuInfo
->SelectedMenuItem
)
420 // If this is the selected item, use the selected colors
422 Attribute
= ATTR(UiSelectedTextColor
, UiSelectedTextBgColor
);
428 UiDrawText(MenuInfo
->Left
+ 1,
429 MenuInfo
->Top
+ 1 + MenuItemNumber
,
436 TuiProcessMenuKeyboardEvent(PUI_MENU_INFO MenuInfo
,
437 UiMenuKeyPressFilterCallback KeyPressFilter
)
440 ULONG Selected
, Count
;
443 // Check for a keypress
448 // Check if the timeout is not already complete
450 if (MenuInfo
->MenuTimeRemaining
!= -1)
453 // Cancel it and remove it
455 MenuInfo
->MenuTimeRemaining
= -1;
456 TuiDrawMenuBox(MenuInfo
); // FIXME: Remove for minimal UI too
462 KeyEvent
= MachConsGetCh();
465 // Is it extended? Then get the extended key
467 if (!KeyEvent
) KeyEvent
= MachConsGetCh();
470 // Call the supplied key filter callback function to see
471 // if it is going to handle this keypress.
473 if ((KeyPressFilter
) && (KeyPressFilter(KeyEvent
)))
476 // It processed the key character, so redraw and exit
478 UiVtbl
.DrawMenu(MenuInfo
);
485 if ((KeyEvent
== KEY_UP
) || (KeyEvent
== KEY_DOWN
))
488 // Get the current selected item and count
490 Selected
= MenuInfo
->SelectedMenuItem
;
491 Count
= MenuInfo
->MenuItemCount
- 1;
494 // Check if this was a key up and there's a selected menu item
496 if ((KeyEvent
== KEY_UP
) && (Selected
))
499 // Update the menu (Deselect previous item)
501 MenuInfo
->SelectedMenuItem
--;
502 TuiDrawMenuItem(MenuInfo
, Selected
);
505 // Skip past any separators
507 !(_stricmp(MenuInfo
->MenuItemList
[Selected
], "SEPARATOR")))
509 MenuInfo
->SelectedMenuItem
--;
512 else if ((KeyEvent
== KEY_DOWN
) && (Selected
< Count
))
515 // Update the menu (deselect previous item)
517 MenuInfo
->SelectedMenuItem
++;
518 TuiDrawMenuItem(MenuInfo
, Selected
);
521 // Skip past any separators
522 if ((Selected
< Count
) &&
523 !(_stricmp(MenuInfo
->MenuItemList
[Selected
], "SEPARATOR")))
525 MenuInfo
->SelectedMenuItem
++;
530 // Select new item and update video buffer
532 TuiDrawMenuItem(MenuInfo
, MenuInfo
->SelectedMenuItem
);
533 VideoCopyOffScreenBufferToVRAM();
538 // Return the pressed key