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
125 // Return the selected item
127 if (SelectedMenuItem
) *SelectedMenuItem
= MenuInformation
.SelectedMenuItem
;
133 TuiCalcMenuBoxSize(PUI_MENU_INFO MenuInfo
)
141 // Height is the menu item count plus 2 (top border & bottom border)
143 Height
= MenuInfo
->MenuItemCount
+ 2;
144 Height
-= 1; // Height is zero-based
149 for(i
= 0; i
< MenuInfo
->MenuItemCount
; i
++)
152 // Get the string length and make it become the new width if necessary
154 Length
= strlen(MenuInfo
->MenuItemList
[i
]);
155 if (Length
> Width
) Width
= Length
;
159 // Allow room for left & right borders, plus 8 spaces on each side
164 // Check if we're drawing a centered menu
169 // Calculate the menu box area for a centered menu
171 MenuInfo
->Left
= (UiScreenWidth
- Width
) / 2;
172 MenuInfo
->Top
= (((UiScreenHeight
- TUI_TITLE_BOX_CHAR_HEIGHT
) -
173 Height
) / 2) + TUI_TITLE_BOX_CHAR_HEIGHT
;
178 // Put the menu in the default left-corner position
185 // The other margins are the same
187 MenuInfo
->Right
= (MenuInfo
->Left
) + Width
;
188 MenuInfo
->Bottom
= (MenuInfo
->Top
) + Height
;
192 TuiDrawMenu(PUI_MENU_INFO MenuInfo
)
202 // Update the status bar
204 UiVtbl
.DrawStatusText("Use \x18\x19 to select, then press ENTER.");
209 TuiDrawMenuBox(MenuInfo
);
212 // Draw each line of the menu
214 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++) TuiDrawMenuItem(MenuInfo
, i
);
215 VideoCopyOffScreenBufferToVRAM();
220 TuiDrawMenuBox(PUI_MENU_INFO MenuInfo
)
222 CHAR MenuLineText
[80];
227 // Draw the menu box if requested
231 UiDrawBox(MenuInfo
->Left
,
239 ATTR(UiMenuFgColor
, UiMenuBgColor
));
243 // If there is a timeout draw the time remaining
245 if (MenuInfo
->MenuTimeRemaining
>= 0)
248 // Copy the integral time text string, and remove the last 2 chars
250 strcpy(TempString
, UiTimeText
);
251 i
= strlen(TempString
);
252 TempString
[i
- 2] = 0;
255 // Display the first part of the string and the remaining time
257 strcpy(MenuLineText
, TempString
);
258 _itoa(MenuInfo
->MenuTimeRemaining
, TempString
, 10);
259 strcat(MenuLineText
, TempString
);
262 // Add the last 2 chars
264 strcat(MenuLineText
, &UiTimeText
[i
- 2]);
267 // Check if this is a centered menu
272 // Display it in the center of the menu
274 UiDrawText(MenuInfo
->Right
- strlen(MenuLineText
) - 1,
277 ATTR(UiMenuFgColor
, UiMenuBgColor
));
282 // Display under the menu directly
285 MenuInfo
->Bottom
+ 3,
287 ATTR(UiMenuFgColor
, UiMenuBgColor
));
293 // Erase the timeout string with spaces, and 0-terminate for sure
295 for (i
=0; i
<sizeof(MenuLineText
)-1; i
++)
297 MenuLineText
[i
] = ' ';
299 MenuLineText
[sizeof(MenuLineText
)-1] = 0;
302 // Draw this "empty" string to erase
306 UiDrawText(MenuInfo
->Right
- strlen(MenuLineText
) - 1,
309 ATTR(UiMenuFgColor
, UiMenuBgColor
));
314 MenuInfo
->Bottom
+ 3,
316 ATTR(UiMenuFgColor
, UiMenuBgColor
));
323 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++)
326 // Check if it's a separator
328 if (!(_stricmp(MenuInfo
->MenuItemList
[i
], "SEPARATOR")))
331 // Draw the separator line
333 UiDrawText(MenuInfo
->Left
,
334 MenuInfo
->Top
+ i
+ 1,
336 ATTR(UiMenuFgColor
, UiMenuBgColor
));
337 UiDrawText(MenuInfo
->Right
,
338 MenuInfo
->Top
+ i
+ 1,
340 ATTR(UiMenuFgColor
, UiMenuBgColor
));
347 TuiDrawMenuItem(PUI_MENU_INFO MenuInfo
,
348 ULONG MenuItemNumber
)
351 CHAR MenuLineText
[80];
354 ULONG SpaceRight
= 0;
355 UCHAR Attribute
= ATTR(UiTextColor
, UiMenuBgColor
);
358 // Check if using centered menu
363 // We will want the string centered so calculate
364 // how many spaces will be to the left and right
366 SpaceTotal
= (MenuInfo
->Right
- MenuInfo
->Left
- 2) -
367 strlen(MenuInfo
->MenuItemList
[MenuItemNumber
]);
368 SpaceLeft
= (SpaceTotal
/ 2) + 1;
369 SpaceRight
= (SpaceTotal
- SpaceLeft
) + 1;
372 // Insert the spaces on the left
374 for (i
= 0; i
< SpaceLeft
; i
++) MenuLineText
[i
] = ' ';
375 MenuLineText
[i
] = '\0';
380 // Simply left-align it
382 MenuLineText
[0] = '\0';
383 strcat(MenuLineText
, " ");
387 // Now append the text string
389 strcat(MenuLineText
, MenuInfo
->MenuItemList
[MenuItemNumber
]);
392 // Check if using centered menu, and add spaces on the right if so
394 if (UiCenterMenu
) for (i
=0; i
< SpaceRight
; i
++) strcat(MenuLineText
, " ");
397 // If it is a separator
399 if (!(_stricmp(MenuInfo
->MenuItemList
[MenuItemNumber
], "SEPARATOR")))
402 // Make it a separator line and use menu colors
404 memset(MenuLineText
, 0, 80);
405 memset(MenuLineText
, 0xC4, (MenuInfo
->Right
- MenuInfo
->Left
- 1));
406 Attribute
= ATTR(UiMenuFgColor
, UiMenuBgColor
);
408 else if (MenuItemNumber
== MenuInfo
->SelectedMenuItem
)
411 // If this is the selected item, use the selected colors
413 Attribute
= ATTR(UiSelectedTextColor
, UiSelectedTextBgColor
);
419 UiDrawText(MenuInfo
->Left
+ 1,
420 MenuInfo
->Top
+ 1 + MenuItemNumber
,
427 TuiProcessMenuKeyboardEvent(PUI_MENU_INFO MenuInfo
,
428 UiMenuKeyPressFilterCallback KeyPressFilter
)
431 ULONG Selected
, Count
;
434 // Check for a keypress
439 // Check if the timeout is not already complete
441 if (MenuInfo
->MenuTimeRemaining
!= -1)
444 // Cancel it and remove it
446 MenuInfo
->MenuTimeRemaining
= -1;
447 TuiDrawMenuBox(MenuInfo
); // FIXME: Remove for minimal UI too
453 KeyEvent
= MachConsGetCh();
456 // Is it extended? Then get the extended key
458 if (!KeyEvent
) KeyEvent
= MachConsGetCh();
461 // Call the supplied key filter callback function to see
462 // if it is going to handle this keypress.
464 if ((KeyPressFilter
) && (KeyPressFilter(KeyEvent
)))
467 // It processed the key character, so redraw and exit
469 UiVtbl
.DrawMenu(MenuInfo
);
476 if ((KeyEvent
== KEY_UP
) || (KeyEvent
== KEY_DOWN
))
479 // Get the current selected item and count
481 Selected
= MenuInfo
->SelectedMenuItem
;
482 Count
= MenuInfo
->MenuItemCount
- 1;
485 // Check if this was a key up and there's a selected menu item
487 if ((KeyEvent
== KEY_UP
) && (Selected
))
490 // Update the menu (Deselect previous item)
492 MenuInfo
->SelectedMenuItem
--;
493 TuiDrawMenuItem(MenuInfo
, Selected
);
496 // Skip past any separators
498 !(_stricmp(MenuInfo
->MenuItemList
[Selected
], "SEPARATOR")))
500 MenuInfo
->SelectedMenuItem
--;
503 else if ((KeyEvent
== KEY_DOWN
) && (Selected
< Count
))
506 // Update the menu (deselect previous item)
508 MenuInfo
->SelectedMenuItem
++;
509 TuiDrawMenuItem(MenuInfo
, Selected
);
512 // Skip past any separators
513 if ((Selected
< Count
) &&
514 !(_stricmp(MenuInfo
->MenuItemList
[Selected
], "SEPARATOR")))
516 MenuInfo
->SelectedMenuItem
++;
521 // Select new item and update video buffer
523 TuiDrawMenuItem(MenuInfo
, MenuInfo
->SelectedMenuItem
);
524 VideoCopyOffScreenBufferToVRAM();
529 // Return the pressed key