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 MenuItemList
[],
19 ULONG DefaultMenuItem
,
21 ULONG
* SelectedMenuItem
,
23 UiMenuKeyPressFilterCallback KeyPressFilter
)
25 UI_MENU_INFO MenuInformation
;
26 ULONG LastClockSecond
;
27 ULONG CurrentClockSecond
;
31 // Check if there's no timeout
35 // Return the default selected item
37 if (SelectedMenuItem
) *SelectedMenuItem
= DefaultMenuItem
;
42 // Setup the MENU_INFO structure
44 MenuInformation
.MenuItemList
= MenuItemList
;
45 MenuInformation
.MenuItemCount
= MenuItemCount
;
46 MenuInformation
.MenuTimeRemaining
= MenuTimeOut
;
47 MenuInformation
.SelectedMenuItem
= DefaultMenuItem
;
50 // Calculate the size of the menu box
52 TuiCalcMenuBoxSize(&MenuInformation
);
57 UiVtbl
.DrawMenu(&MenuInformation
);
60 // Get the current second of time
62 LastClockSecond
= ArcGetTime()->Second
;
70 // Process key presses
72 KeyPress
= TuiProcessMenuKeyboardEvent(&MenuInformation
,
76 // Check for ENTER or ESC
78 if (KeyPress
== KEY_ENTER
) break;
79 if (CanEscape
&& KeyPress
== KEY_ESC
) return FALSE
;
82 // Update the date & time
85 VideoCopyOffScreenBufferToVRAM();
88 // Check if there is a countdown
90 if (MenuInformation
.MenuTimeRemaining
)
93 // Get the updated time, seconds only
95 CurrentClockSecond
= ArcGetTime()->Second
;
98 // Check if more then a second has now elapsed
100 if (CurrentClockSecond
!= LastClockSecond
)
103 // Update the time information
105 LastClockSecond
= CurrentClockSecond
;
106 MenuInformation
.MenuTimeRemaining
--;
111 TuiDrawMenuBox(&MenuInformation
);
112 VideoCopyOffScreenBufferToVRAM();
118 // A time out occurred, exit this loop and return default OS
127 // Return the selected item
129 if (SelectedMenuItem
) *SelectedMenuItem
= MenuInformation
.SelectedMenuItem
;
135 TuiCalcMenuBoxSize(PUI_MENU_INFO MenuInfo
)
143 // Height is the menu item count plus 2 (top border & bottom border)
145 Height
= MenuInfo
->MenuItemCount
+ 2;
146 Height
-= 1; // Height is zero-based
151 for(i
= 0; i
< MenuInfo
->MenuItemCount
; i
++)
154 // Get the string length and make it become the new width if necessary
156 Length
= (ULONG
)strlen(MenuInfo
->MenuItemList
[i
]);
157 if (Length
> Width
) Width
= Length
;
161 // Allow room for left & right borders, plus 8 spaces on each side
166 // Check if we're drawing a centered menu
171 // Calculate the menu box area for a centered menu
173 MenuInfo
->Left
= (UiScreenWidth
- Width
) / 2;
174 MenuInfo
->Top
= (((UiScreenHeight
- TUI_TITLE_BOX_CHAR_HEIGHT
) -
175 Height
) / 2) + TUI_TITLE_BOX_CHAR_HEIGHT
;
180 // Put the menu in the default left-corner position
187 // The other margins are the same
189 MenuInfo
->Right
= (MenuInfo
->Left
) + Width
;
190 MenuInfo
->Bottom
= (MenuInfo
->Top
) + Height
;
194 TuiDrawMenu(PUI_MENU_INFO MenuInfo
)
204 // Update the status bar
206 UiVtbl
.DrawStatusText("Use \x18\x19 to select, then press ENTER.");
211 TuiDrawMenuBox(MenuInfo
);
214 // Draw each line of the menu
216 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++) TuiDrawMenuItem(MenuInfo
, i
);
217 VideoCopyOffScreenBufferToVRAM();
222 TuiDrawMenuBox(PUI_MENU_INFO MenuInfo
)
224 CHAR MenuLineText
[80];
229 // Draw the menu box if requested
233 UiDrawBox(MenuInfo
->Left
,
241 ATTR(UiMenuFgColor
, UiMenuBgColor
));
245 // If there is a timeout draw the time remaining
247 if (MenuInfo
->MenuTimeRemaining
>= 0)
250 // Copy the integral time text string, and remove the last 2 chars
252 strcpy(TempString
, UiTimeText
);
253 i
= (ULONG
)strlen(TempString
);
254 TempString
[i
- 2] = 0;
257 // Display the first part of the string and the remaining time
259 strcpy(MenuLineText
, TempString
);
260 _itoa(MenuInfo
->MenuTimeRemaining
, TempString
, 10);
261 strcat(MenuLineText
, TempString
);
264 // Add the last 2 chars
266 strcat(MenuLineText
, &UiTimeText
[i
- 2]);
269 // Check if this is a centered menu
274 // Display it in the center of the menu
276 UiDrawText(MenuInfo
->Right
- (ULONG
)strlen(MenuLineText
) - 1,
279 ATTR(UiMenuFgColor
, UiMenuBgColor
));
284 // Display under the menu directly
287 MenuInfo
->Bottom
+ 3,
289 ATTR(UiMenuFgColor
, UiMenuBgColor
));
295 // Erase the timeout string with spaces, and 0-terminate for sure
297 for (i
=0; i
<sizeof(MenuLineText
)-1; i
++)
299 MenuLineText
[i
] = ' ';
301 MenuLineText
[sizeof(MenuLineText
)-1] = 0;
304 // Draw this "empty" string to erase
308 UiDrawText(MenuInfo
->Right
- (ULONG
)strlen(MenuLineText
) - 1,
311 ATTR(UiMenuFgColor
, UiMenuBgColor
));
316 MenuInfo
->Bottom
+ 3,
318 ATTR(UiMenuFgColor
, UiMenuBgColor
));
325 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++)
328 // Check if it's a separator
330 if (!(_stricmp(MenuInfo
->MenuItemList
[i
], "SEPARATOR")))
333 // Draw the separator line
335 UiDrawText(MenuInfo
->Left
,
336 MenuInfo
->Top
+ i
+ 1,
338 ATTR(UiMenuFgColor
, UiMenuBgColor
));
339 UiDrawText(MenuInfo
->Right
,
340 MenuInfo
->Top
+ i
+ 1,
342 ATTR(UiMenuFgColor
, UiMenuBgColor
));
349 TuiDrawMenuItem(PUI_MENU_INFO MenuInfo
,
350 ULONG MenuItemNumber
)
353 CHAR MenuLineText
[80];
356 ULONG SpaceRight
= 0;
357 UCHAR Attribute
= ATTR(UiTextColor
, UiMenuBgColor
);
360 // Check if using centered menu
365 // We will want the string centered so calculate
366 // how many spaces will be to the left and right
368 SpaceTotal
= (MenuInfo
->Right
- MenuInfo
->Left
- 2) -
369 (ULONG
)strlen(MenuInfo
->MenuItemList
[MenuItemNumber
]);
370 SpaceLeft
= (SpaceTotal
/ 2) + 1;
371 SpaceRight
= (SpaceTotal
- SpaceLeft
) + 1;
374 // Insert the spaces on the left
376 for (i
= 0; i
< SpaceLeft
; i
++) MenuLineText
[i
] = ' ';
377 MenuLineText
[i
] = '\0';
382 // Simply left-align it
384 MenuLineText
[0] = '\0';
385 strcat(MenuLineText
, " ");
389 // Now append the text string
391 strcat(MenuLineText
, MenuInfo
->MenuItemList
[MenuItemNumber
]);
394 // Check if using centered menu, and add spaces on the right if so
396 if (UiCenterMenu
) for (i
=0; i
< SpaceRight
; i
++) strcat(MenuLineText
, " ");
399 // If it is a separator
401 if (!(_stricmp(MenuInfo
->MenuItemList
[MenuItemNumber
], "SEPARATOR")))
404 // Make it a separator line and use menu colors
406 memset(MenuLineText
, 0, 80);
407 memset(MenuLineText
, 0xC4, (MenuInfo
->Right
- MenuInfo
->Left
- 1));
408 Attribute
= ATTR(UiMenuFgColor
, UiMenuBgColor
);
410 else if (MenuItemNumber
== MenuInfo
->SelectedMenuItem
)
413 // If this is the selected item, use the selected colors
415 Attribute
= ATTR(UiSelectedTextColor
, UiSelectedTextBgColor
);
421 UiDrawText(MenuInfo
->Left
+ 1,
422 MenuInfo
->Top
+ 1 + MenuItemNumber
,
429 TuiProcessMenuKeyboardEvent(PUI_MENU_INFO MenuInfo
,
430 UiMenuKeyPressFilterCallback KeyPressFilter
)
433 ULONG Selected
, Count
;
436 // Check for a keypress
441 // Check if the timeout is not already complete
443 if (MenuInfo
->MenuTimeRemaining
!= -1)
446 // Cancel it and remove it
448 MenuInfo
->MenuTimeRemaining
= -1;
449 TuiDrawMenuBox(MenuInfo
); // FIXME: Remove for minimal UI too
455 KeyEvent
= MachConsGetCh();
458 // Is it extended? Then get the extended key
460 if (!KeyEvent
) KeyEvent
= MachConsGetCh();
463 // Call the supplied key filter callback function to see
464 // if it is going to handle this keypress.
466 if ((KeyPressFilter
) && (KeyPressFilter(KeyEvent
)))
469 // It processed the key character, so redraw and exit
471 UiVtbl
.DrawMenu(MenuInfo
);
478 if ((KeyEvent
== KEY_UP
) || (KeyEvent
== KEY_DOWN
))
481 // Get the current selected item and count
483 Selected
= MenuInfo
->SelectedMenuItem
;
484 Count
= MenuInfo
->MenuItemCount
- 1;
487 // Check if this was a key up and there's a selected menu item
489 if ((KeyEvent
== KEY_UP
) && (Selected
))
492 // Update the menu (Deselect previous item)
494 MenuInfo
->SelectedMenuItem
--;
495 TuiDrawMenuItem(MenuInfo
, Selected
);
498 // Skip past any separators
500 !(_stricmp(MenuInfo
->MenuItemList
[Selected
], "SEPARATOR")))
502 MenuInfo
->SelectedMenuItem
--;
505 else if ((KeyEvent
== KEY_DOWN
) && (Selected
< Count
))
508 // Update the menu (deselect previous item)
510 MenuInfo
->SelectedMenuItem
++;
511 TuiDrawMenuItem(MenuInfo
, Selected
);
514 // Skip past any separators
515 if ((Selected
< Count
) &&
516 !(_stricmp(MenuInfo
->MenuItemList
[Selected
], "SEPARATOR")))
518 MenuInfo
->SelectedMenuItem
++;
523 // Select new item and update video buffer
525 TuiDrawMenuItem(MenuInfo
, MenuInfo
->SelectedMenuItem
);
526 VideoCopyOffScreenBufferToVRAM();
531 // Return the pressed key