mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-25 16:37:42 +01:00
f8a010245f
to avoid side effects Signed-off-by: SergeySlice <sergey.slice@gmail.com>
2830 lines
104 KiB
C++
2830 lines
104 KiB
C++
/*
|
|
* refit/menu.c
|
|
* Menu functions
|
|
*
|
|
* Copyright (c) 2006 Christoph Pfisterer
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* * Neither the name of Christoph Pfisterer nor the names of the
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
//#include "Platform.h"
|
|
#include "../libeg/libegint.h" //this includes platform.h
|
|
//#include "../include/scroll_images.h"
|
|
|
|
//#include "colors.h"
|
|
|
|
#include "../libeg/nanosvg.h"
|
|
#include "../libeg/FloatLib.h"
|
|
#include "HdaCodecDump.h"
|
|
#include "REFIT_MENU_SCREEN.h"
|
|
//#include "screen.h"
|
|
#include "../cpp_foundation/XString.h"
|
|
#include "../libeg/XTheme.h"
|
|
#include "../libeg/VectorGraphics.h" // for testSVG
|
|
#include "shared_with_menu.h"
|
|
#include "../refit/menu.h" // for DrawTextXY. Must disappear soon.
|
|
#include "../Platform/AcpiPatcher.h"
|
|
#include "../Platform/Nvram.h"
|
|
#include "../refit/screen.h"
|
|
|
|
#ifndef DEBUG_ALL
|
|
#define DEBUG_MENU 1
|
|
#else
|
|
#define DEBUG_MENU DEBUG_ALL
|
|
#endif
|
|
|
|
#if DEBUG_MENU == 0
|
|
#define DBG(...)
|
|
#else
|
|
#define DBG(...) DebugLog(DEBUG_MENU, __VA_ARGS__)
|
|
#endif
|
|
|
|
XPointer REFIT_MENU_SCREEN::mPointer;
|
|
|
|
// scrolling definitions
|
|
static INTN MaxItemOnScreen = -1;
|
|
|
|
|
|
#include "../Platform/Settings.h"
|
|
#include "../Platform/StartupSound.h" // for audioIo
|
|
|
|
|
|
#define SCROLL_LINE_UP (0)
|
|
#define SCROLL_LINE_DOWN (1)
|
|
#define SCROLL_PAGE_UP (2)
|
|
#define SCROLL_PAGE_DOWN (3)
|
|
#define SCROLL_FIRST (4)
|
|
#define SCROLL_LAST (5)
|
|
#define SCROLL_NONE (6)
|
|
#define SCROLL_SCROLL_DOWN (7)
|
|
#define SCROLL_SCROLL_UP (8)
|
|
#define SCROLL_SCROLLBAR_MOVE (9)
|
|
|
|
//
|
|
#define TEXT_CORNER_REVISION (1)
|
|
#define TEXT_CORNER_HELP (2)
|
|
#define TEXT_CORNER_OPTIMUS (3)
|
|
//
|
|
#define TITLE_MAX_LEN (SVALUE_MAX_SIZE / sizeof(CHAR16) + 128)
|
|
//
|
|
// other menu definitions
|
|
|
|
#define MENU_FUNCTION_INIT (0)
|
|
#define MENU_FUNCTION_CLEANUP (1)
|
|
#define MENU_FUNCTION_PAINT_ALL (2)
|
|
#define MENU_FUNCTION_PAINT_SELECTION (3)
|
|
#define MENU_FUNCTION_PAINT_TIMEOUT (4)
|
|
|
|
|
|
//
|
|
const CHAR16 ArrowUp[2] = { ARROW_UP, 0 }; //defined in Simple Text Out protocol
|
|
const CHAR16 ArrowDown[2] = { ARROW_DOWN, 0 };
|
|
//
|
|
//BOOLEAN MainAnime = FALSE;
|
|
//
|
|
////TODO Scroll variables must be a part of REFIT_SCREEN
|
|
////BOOLEAN ScrollEnabled = FALSE;
|
|
//
|
|
INTN ScrollbarYMovement;
|
|
//
|
|
//
|
|
////#define TextHeight (FONT_CELL_HEIGHT + TEXT_YMARGIN * 2)
|
|
//
|
|
|
|
//
|
|
////TODO spacing must be a part of layout in XTheme
|
|
#define TITLEICON_SPACING (16)
|
|
////#define ROW0__TILESIZE (144)
|
|
////#define ROW1_TILESIZE (64)
|
|
#define TILE1_XSPACING (8)
|
|
////#define TILE_YSPACING (24)
|
|
#define ROW0_SCROLLSIZE (100)
|
|
//
|
|
//
|
|
static INTN row0Count, row0PosX, row0PosXRunning;
|
|
static INTN row1Count, row1PosX, row1PosXRunning;
|
|
static INTN *itemPosX = NULL;
|
|
static INTN *itemPosY = NULL;
|
|
static INTN row0PosY, row1PosY, textPosY, FunctextPosY;
|
|
|
|
static INTN OldX = 0, OldY = 0;
|
|
static INTN OldTextWidth = 0, OldTextHeight = 0;
|
|
static UINTN OldRow = 0;
|
|
static INTN OldTimeoutTextWidth = 0;
|
|
static INTN MenuWidth , TimeoutPosY;
|
|
static UINTN MenuMaxTextLen = 0;
|
|
static INTN EntriesPosX, EntriesPosY;
|
|
static INTN EntriesWidth, EntriesHeight, EntriesGap;
|
|
|
|
BOOLEAN mGuiReady = FALSE;
|
|
|
|
|
|
|
|
VOID REFIT_MENU_SCREEN::AddMenuInfo_f(CONST char *format, ...)
|
|
{
|
|
|
|
//DBG("%s, %s : Line=%s\n", __FILE__, __LINE__, XString(Line).c);
|
|
REFIT_INFO_DIALOG *InputBootArgs;
|
|
|
|
InputBootArgs = new REFIT_INFO_DIALOG;
|
|
VA_LIST va;
|
|
VA_START(va, format);
|
|
InputBootArgs->Title.vSWPrintf(format, va);
|
|
VA_END(va);
|
|
InputBootArgs->AtClick = ActionLight;
|
|
AddMenuEntry(InputBootArgs, true);
|
|
}
|
|
|
|
//
|
|
// Graphics helper functions
|
|
//
|
|
|
|
/*
|
|
SelectionImages:
|
|
[0] SelectionBig
|
|
[2] SelectionSmall
|
|
[4] SelectionIndicator
|
|
Buttons:
|
|
[0] radio_button
|
|
[1] radio_button_selected
|
|
[2] checkbox
|
|
[3] checkbox_checked
|
|
*/
|
|
|
|
|
|
//
|
|
// Scrolling functions
|
|
//
|
|
#define CONSTRAIN_MIN(Variable, MinValue) if (Variable < MinValue) Variable = MinValue
|
|
#define CONSTRAIN_MAX(Variable, MaxValue) if (Variable > MaxValue) Variable = MaxValue
|
|
|
|
VOID REFIT_MENU_SCREEN::InitScroll(IN INTN ItemCount, IN UINTN MaxCount,
|
|
IN UINTN VisibleSpace, IN INTN Selected)
|
|
{
|
|
//ItemCount - a number to scroll (Row0)
|
|
//MaxCount - total number (Row0 + Row1)
|
|
//VisibleSpace - a number to fit
|
|
|
|
ScrollState.LastSelection = ScrollState.CurrentSelection = Selected;
|
|
//MaxIndex, MaxScroll, MaxVisible are indexes, 0..N-1
|
|
ScrollState.MaxIndex = (INTN)MaxCount - 1;
|
|
ScrollState.MaxScroll = ItemCount - 1;
|
|
|
|
if (VisibleSpace == 0) {
|
|
ScrollState.MaxVisible = ScrollState.MaxScroll;
|
|
} else {
|
|
ScrollState.MaxVisible = (INTN)VisibleSpace - 1;
|
|
}
|
|
|
|
if (ScrollState.MaxVisible >= ItemCount) {
|
|
ScrollState.MaxVisible = ItemCount - 1;
|
|
}
|
|
|
|
ScrollState.MaxFirstVisible = ScrollState.MaxScroll - ScrollState.MaxVisible;
|
|
CONSTRAIN_MIN(ScrollState.MaxFirstVisible, 0);
|
|
ScrollState.FirstVisible = MIN(Selected, ScrollState.MaxFirstVisible);
|
|
|
|
|
|
ScrollState.IsScrolling = (ScrollState.MaxFirstVisible > 0);
|
|
ScrollState.PaintAll = TRUE;
|
|
ScrollState.PaintSelection = FALSE;
|
|
|
|
ScrollState.LastVisible = ScrollState.FirstVisible + ScrollState.MaxVisible;
|
|
|
|
//scroll bar geometry
|
|
if (!ThemeX.TypeSVG) {
|
|
UpButton.Width = ThemeX.ScrollWidth; // 16
|
|
UpButton.Height = ThemeX.ScrollButtonsHeight; // 20
|
|
DownButton.Width = UpButton.Width;
|
|
DownButton.Height = ThemeX.ScrollButtonsHeight;
|
|
BarStart.Height = ThemeX.ScrollBarDecorationsHeight; // 5
|
|
BarEnd.Height = ThemeX.ScrollBarDecorationsHeight;
|
|
ScrollStart.Height = ThemeX.ScrollScrollDecorationsHeight; // 7
|
|
ScrollEnd.Height = ThemeX.ScrollScrollDecorationsHeight;
|
|
|
|
} else {
|
|
UpButton.Width = ThemeX.ScrollWidth; // 16
|
|
UpButton.Height = 0; // 20
|
|
DownButton.Width = UpButton.Width;
|
|
DownButton.Height = 0;
|
|
BarStart.Height = ThemeX.ScrollBarDecorationsHeight; // 5
|
|
BarEnd.Height = ThemeX.ScrollBarDecorationsHeight;
|
|
ScrollStart.Height = 0; // 7
|
|
ScrollEnd.Height = 0;
|
|
}
|
|
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::UpdateScroll(IN UINTN Movement)
|
|
{
|
|
INTN Lines;
|
|
UINTN ScrollMovement = SCROLL_SCROLL_DOWN;
|
|
ScrollState.LastSelection = ScrollState.CurrentSelection;
|
|
|
|
switch (Movement) {
|
|
case SCROLL_SCROLLBAR_MOVE:
|
|
ScrollbarYMovement += ScrollbarNewPointerPlace.YPos - ScrollbarOldPointerPlace.YPos;
|
|
ScrollbarOldPointerPlace.XPos = ScrollbarNewPointerPlace.XPos;
|
|
ScrollbarOldPointerPlace.YPos = ScrollbarNewPointerPlace.YPos;
|
|
Lines = ScrollbarYMovement * ScrollState.MaxIndex / ScrollbarBackground.Height;
|
|
ScrollbarYMovement = ScrollbarYMovement - Lines * (ScrollState.MaxVisible * ThemeX.TextHeight - 16 - 1) / ScrollState.MaxIndex;
|
|
if (Lines < 0) {
|
|
Lines = -Lines;
|
|
ScrollMovement = SCROLL_SCROLL_UP;
|
|
}
|
|
for (INTN i = 0; i < Lines; i++)
|
|
UpdateScroll(ScrollMovement);
|
|
break;
|
|
|
|
case SCROLL_LINE_UP: //of left = decrement
|
|
if (ScrollState.CurrentSelection > 0) {
|
|
ScrollState.CurrentSelection --;
|
|
if (ScrollState.CurrentSelection < ScrollState.FirstVisible) {
|
|
ScrollState.PaintAll = TRUE;
|
|
ScrollState.FirstVisible = ScrollState.CurrentSelection;
|
|
}
|
|
if (ScrollState.CurrentSelection == ScrollState.MaxScroll) {
|
|
ScrollState.PaintAll = TRUE;
|
|
}
|
|
if ((ScrollState.CurrentSelection < ScrollState.MaxScroll) &&
|
|
(ScrollState.CurrentSelection > ScrollState.LastVisible)) {
|
|
ScrollState.PaintAll = TRUE;
|
|
ScrollState.LastVisible = ScrollState.CurrentSelection;
|
|
ScrollState.FirstVisible = ScrollState.LastVisible - ScrollState.MaxVisible;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SCROLL_LINE_DOWN: //or right -- increment
|
|
if (ScrollState.CurrentSelection < ScrollState.MaxIndex) {
|
|
ScrollState.CurrentSelection++;
|
|
if ((ScrollState.CurrentSelection > ScrollState.LastVisible) &&
|
|
(ScrollState.CurrentSelection <= ScrollState.MaxScroll)){
|
|
ScrollState.PaintAll = TRUE;
|
|
ScrollState.FirstVisible++;
|
|
CONSTRAIN_MAX(ScrollState.FirstVisible, ScrollState.MaxFirstVisible);
|
|
}
|
|
if (ScrollState.CurrentSelection == ScrollState.MaxScroll + 1) {
|
|
ScrollState.PaintAll = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SCROLL_SCROLL_DOWN:
|
|
if (ScrollState.FirstVisible < ScrollState.MaxFirstVisible) {
|
|
if (ScrollState.CurrentSelection == ScrollState.FirstVisible)
|
|
ScrollState.CurrentSelection++;
|
|
ScrollState.FirstVisible++;
|
|
ScrollState.LastVisible++;
|
|
ScrollState.PaintAll = TRUE;
|
|
}
|
|
break;
|
|
|
|
case SCROLL_SCROLL_UP:
|
|
if (ScrollState.FirstVisible > 0) {
|
|
if (ScrollState.CurrentSelection == ScrollState.LastVisible)
|
|
ScrollState.CurrentSelection--;
|
|
ScrollState.FirstVisible--;
|
|
ScrollState.LastVisible--;
|
|
ScrollState.PaintAll = TRUE;
|
|
}
|
|
break;
|
|
|
|
case SCROLL_PAGE_UP:
|
|
if (ScrollState.CurrentSelection > 0) {
|
|
if (ScrollState.CurrentSelection == ScrollState.MaxIndex) { // currently at last entry, special treatment
|
|
if (ScrollState.IsScrolling)
|
|
ScrollState.CurrentSelection -= ScrollState.MaxVisible - 1; // move to second line without scrolling
|
|
else
|
|
ScrollState.CurrentSelection = 0; // move to first entry
|
|
} else {
|
|
if (ScrollState.FirstVisible > 0)
|
|
ScrollState.PaintAll = TRUE;
|
|
ScrollState.CurrentSelection -= ScrollState.MaxVisible; // move one page and scroll synchronously
|
|
ScrollState.FirstVisible -= ScrollState.MaxVisible;
|
|
}
|
|
CONSTRAIN_MIN(ScrollState.CurrentSelection, 0);
|
|
CONSTRAIN_MIN(ScrollState.FirstVisible, 0);
|
|
if (ScrollState.CurrentSelection < ScrollState.FirstVisible) {
|
|
ScrollState.PaintAll = TRUE;
|
|
ScrollState.FirstVisible = ScrollState.CurrentSelection;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SCROLL_PAGE_DOWN:
|
|
// DBG("cur=%lld, maxInd=%lld, maxVis=%lld, First=%lld, maxFirst=%lld, lastVis=%lld, maxscr=%lld\n",
|
|
// ScrollState.CurrentSelection, ScrollState.MaxIndex, ScrollState.MaxVisible, ScrollState.FirstVisible,
|
|
// ScrollState.MaxFirstVisible, ScrollState.CurrentSelection, ScrollState.LastVisible);
|
|
|
|
if (ScrollState.CurrentSelection < ScrollState.MaxIndex) {
|
|
if (ScrollState.CurrentSelection == 0) { // currently at first entry, special treatment
|
|
if (ScrollState.IsScrolling)
|
|
ScrollState.CurrentSelection = ScrollState.MaxVisible - 1; // move to second-to-last line without scrolling
|
|
else
|
|
ScrollState.CurrentSelection = ScrollState.MaxIndex; // move to last entry
|
|
} else {
|
|
// if (ScrollState.FirstVisible < ScrollState.MaxFirstVisible)
|
|
// ScrollState.PaintAll = TRUE;
|
|
ScrollState.CurrentSelection += ScrollState.MaxVisible; // move one page and scroll synchronously
|
|
ScrollState.FirstVisible += ScrollState.MaxVisible;
|
|
}
|
|
CONSTRAIN_MAX(ScrollState.CurrentSelection, ScrollState.MaxIndex); // if (v>m) v=m;
|
|
CONSTRAIN_MAX(ScrollState.FirstVisible, ScrollState.MaxFirstVisible);
|
|
if ((ScrollState.CurrentSelection > ScrollState.LastVisible) &&
|
|
(ScrollState.CurrentSelection <= ScrollState.MaxScroll)){
|
|
// ScrollState.PaintAll = TRUE;
|
|
ScrollState.FirstVisible+= ScrollState.MaxVisible;
|
|
CONSTRAIN_MAX(ScrollState.FirstVisible, ScrollState.MaxFirstVisible);
|
|
}
|
|
ScrollState.PaintAll = TRUE;
|
|
}
|
|
// DBG("after cur=%lld, maxInd=%lld, maxVis=%lld, First=%lld, maxFirst=%lld, lastVis=%lld, maxscr=%lld\n",
|
|
// ScrollState.CurrentSelection, ScrollState.MaxIndex, ScrollState.MaxVisible, ScrollState.FirstVisible,
|
|
// ScrollState.MaxFirstVisible, ScrollState.CurrentSelection, ScrollState.LastVisible);
|
|
|
|
break;
|
|
|
|
case SCROLL_FIRST:
|
|
if (ScrollState.CurrentSelection > 0) {
|
|
ScrollState.CurrentSelection = 0;
|
|
if (ScrollState.FirstVisible > 0) {
|
|
ScrollState.PaintAll = TRUE;
|
|
ScrollState.FirstVisible = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SCROLL_LAST:
|
|
if (ScrollState.CurrentSelection < ScrollState.MaxIndex) {
|
|
ScrollState.CurrentSelection = ScrollState.MaxIndex;
|
|
if (ScrollState.FirstVisible < ScrollState.MaxFirstVisible) {
|
|
ScrollState.PaintAll = TRUE;
|
|
ScrollState.FirstVisible = ScrollState.MaxFirstVisible;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SCROLL_NONE:
|
|
// The caller has already updated CurrentSelection, but we may
|
|
// have to scroll to make it visible.
|
|
if (ScrollState.CurrentSelection < ScrollState.FirstVisible) {
|
|
ScrollState.PaintAll = TRUE;
|
|
ScrollState.FirstVisible = ScrollState.CurrentSelection; // - (ScrollState.MaxVisible >> 1);
|
|
CONSTRAIN_MIN(ScrollState.FirstVisible, 0);
|
|
} else if ((ScrollState.CurrentSelection > ScrollState.LastVisible) &&
|
|
(ScrollState.CurrentSelection <= ScrollState.MaxScroll)) {
|
|
ScrollState.PaintAll = TRUE;
|
|
ScrollState.FirstVisible = ScrollState.CurrentSelection - ScrollState.MaxVisible;
|
|
CONSTRAIN_MAX(ScrollState.FirstVisible, ScrollState.MaxFirstVisible);
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
if (!ScrollState.PaintAll && ScrollState.CurrentSelection != ScrollState.LastSelection)
|
|
ScrollState.PaintSelection = TRUE;
|
|
ScrollState.LastVisible = ScrollState.FirstVisible + ScrollState.MaxVisible;
|
|
|
|
//ycr.ru
|
|
if ((ScrollState.PaintAll) && (Movement != SCROLL_NONE))
|
|
HidePointer();
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::HidePointer()
|
|
{
|
|
if ( mPointer.isAlive() ) mPointer.Hide();
|
|
}
|
|
|
|
EFI_STATUS REFIT_MENU_SCREEN::MouseBirth()
|
|
{
|
|
|
|
//if ( !mPointer ) mPointer = new XPointer();
|
|
return mPointer.MouseBirth();
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::KillMouse()
|
|
{
|
|
/*if ( mPointer ) */mPointer.KillMouse();
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::AddMenuInfoLine_f(CONST char *format, ...)
|
|
{
|
|
XStringW* s = new XStringW();
|
|
VA_LIST va;
|
|
VA_START(va, format);
|
|
s->vSWPrintf(format, va);
|
|
VA_END(va);
|
|
InfoLines.AddReference(s, true);
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::AddMenuEntry(IN REFIT_ABSTRACT_MENU_ENTRY *Entry, bool freeIt)
|
|
{
|
|
if ( !Entry ) return;
|
|
Entries.AddReference(Entry, freeIt);
|
|
}
|
|
|
|
// This is supposed to be a destructor ?
|
|
VOID REFIT_MENU_SCREEN::FreeMenu()
|
|
{
|
|
REFIT_ABSTRACT_MENU_ENTRY *Tentry = NULL;
|
|
//TODO - here we must Free for a list of Entries, Screens, InputBootArgs
|
|
if (Entries.size() > 0) {
|
|
for (UINTN i = 0; i < Entries.size(); i++) {
|
|
Tentry = &Entries[i];
|
|
if (Tentry->SubScreen) {
|
|
// don't free image because of reusing them
|
|
Tentry->SubScreen->FreeMenu();
|
|
Tentry->SubScreen = NULL;
|
|
}
|
|
}
|
|
Entries.Empty();
|
|
}
|
|
InfoLines.setEmpty();
|
|
}
|
|
|
|
INTN REFIT_MENU_SCREEN::FindMenuShortcutEntry(IN CHAR16 Shortcut)
|
|
{
|
|
if (Shortcut >= 'a' && Shortcut <= 'z')
|
|
Shortcut -= ('a' - 'A');
|
|
if (Shortcut) {
|
|
for (UINTN i = 0; i < Entries.size(); i++) {
|
|
if (Entries[i].ShortcutDigit == Shortcut ||
|
|
Entries[i].ShortcutLetter == Shortcut) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// generic input menu function
|
|
// usr-sse2
|
|
//
|
|
UINTN REFIT_MENU_SCREEN::InputDialog(IN MENU_STYLE_FUNC StyleFunc)
|
|
{
|
|
if ( !Entries[ScrollState.CurrentSelection].getREFIT_MENU_ITEM_IEM_ABSTRACT() ) {
|
|
DebugLog(2, "BUG : InputDialog called with !Entries[ScrollState.CurrentSelection].REFIT_MENU_ENTRY_ITEM_ABSTRACT()\n");
|
|
return 0; // is it the best thing to do ? CpuDeadLog ?
|
|
}
|
|
|
|
EFI_STATUS Status;
|
|
EFI_INPUT_KEY key;
|
|
UINTN ind = 0;
|
|
UINTN i = 0;
|
|
UINTN MenuExit = 0;
|
|
//UINTN LogSize;
|
|
UINTN Pos = (Entries[ScrollState.CurrentSelection]).Row;
|
|
REFIT_MENU_ENTRY_ITEM_ABSTRACT& selectedEntry = *Entries[ScrollState.CurrentSelection].getREFIT_MENU_ITEM_IEM_ABSTRACT();
|
|
INPUT_ITEM *Item = selectedEntry.Item;
|
|
CHAR16 *Backup = EfiStrDuplicate(Item->SValue);
|
|
UINTN BackupPos, BackupShift;
|
|
CHAR16 *Buffer;
|
|
//SCROLL_STATE StateLine;
|
|
|
|
/*
|
|
I would like to see a LineSize that depends on the Title width and the menu width so
|
|
the edit dialog does not extend beyond the menu width.
|
|
There are 3 cases:
|
|
1) Text menu where MenuWidth is min of ConWidth - 6 and max of 50 and all StrLen(Title)
|
|
2) Graphics menu where MenuWidth is measured in pixels and font is fixed width.
|
|
The following works well in my case but depends on font width and minimum screen size.
|
|
LineSize = 76 - StrLen(Screen->Entries[State->CurrentSelection].Title);
|
|
3) Graphics menu where font is proportional. In this case LineSize would depend on the
|
|
current width of the displayed string which would need to be recalculated after
|
|
every change.
|
|
Anyway, the above will not be implemented for now, and LineSize will remain at 38
|
|
because it works.
|
|
*/
|
|
UINTN LineSize = 38;
|
|
// make sure that LineSize is not too big
|
|
UINTN MaxPossibleLineSize = (MenuWidth - selectedEntry.Place.Width) / (INTN)(ThemeX.CharWidth * ThemeX.Scale) - 1;
|
|
if (!ThemeX.TypeSVG && !ThemeX.Proportional && LineSize > MaxPossibleLineSize) {
|
|
LineSize = MaxPossibleLineSize;
|
|
}
|
|
|
|
#define DBG_INPUTDIALOG 0
|
|
#if DBG_INPUTDIALOG
|
|
UINTN Iteration = 0;
|
|
#endif
|
|
|
|
|
|
if ((Item->ItemType != BoolValue) &&
|
|
(Item->ItemType != RadioSwitch) &&
|
|
(Item->ItemType != CheckBit)) {
|
|
// Grow Item->SValue to SVALUE_MAX_SIZE if we want to edit a text field
|
|
Item->SValue = (__typeof__(Item->SValue))ReallocatePool(StrSize(Item->SValue), SVALUE_MAX_SIZE, Item->SValue);
|
|
}
|
|
|
|
Buffer = Item->SValue;
|
|
BackupShift = Item->LineShift;
|
|
BackupPos = Pos;
|
|
|
|
do {
|
|
|
|
if (Item->ItemType == BoolValue) {
|
|
Item->BValue = !Item->BValue;
|
|
MenuExit = MENU_EXIT_ENTER;
|
|
} else if (Item->ItemType == RadioSwitch) {
|
|
if (Item->IValue == 3) {
|
|
OldChosenTheme = Pos? Pos - 1: 0xFFFF;
|
|
} else if (Item->IValue == 90) {
|
|
OldChosenConfig = Pos;
|
|
} else if (Item->IValue == 116) {
|
|
OldChosenDsdt = Pos? Pos - 1: 0xFFFF;
|
|
} else if (Item->IValue == 119) {
|
|
OldChosenAudio = Pos;
|
|
}
|
|
MenuExit = MENU_EXIT_ENTER;
|
|
} else if (Item->ItemType == CheckBit) {
|
|
Item->IValue ^= Pos;
|
|
MenuExit = MENU_EXIT_ENTER;
|
|
} else {
|
|
|
|
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &key);
|
|
|
|
if (Status == EFI_NOT_READY) {
|
|
gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &ind);
|
|
continue;
|
|
}
|
|
|
|
switch (key.ScanCode) {
|
|
case SCAN_RIGHT:
|
|
if (Pos + Item->LineShift < StrLen(Buffer)) {
|
|
if (Pos < LineSize)
|
|
Pos++;
|
|
else
|
|
Item->LineShift++;
|
|
}
|
|
break;
|
|
case SCAN_LEFT:
|
|
if (Pos > 0)
|
|
Pos--;
|
|
else if (Item->LineShift > 0)
|
|
Item->LineShift--;
|
|
break;
|
|
case SCAN_HOME:
|
|
Pos = 0;
|
|
Item->LineShift=0;
|
|
break;
|
|
case SCAN_END:
|
|
if (StrLen(Buffer) < LineSize)
|
|
Pos = StrLen(Buffer);
|
|
else {
|
|
Pos = LineSize;
|
|
Item->LineShift = StrLen(Buffer) - LineSize;
|
|
}
|
|
break;
|
|
case SCAN_ESC:
|
|
MenuExit = MENU_EXIT_ESCAPE;
|
|
continue;
|
|
break;
|
|
case SCAN_F2:
|
|
SavePreBootLog = TRUE;
|
|
break;
|
|
//not used here
|
|
/* case SCAN_F6:
|
|
Status = egSaveFile(SelfRootDir, VBIOS_BIN, (UINT8*)(UINTN)0xc0000, 0x20000);
|
|
if (EFI_ERROR(Status)) {
|
|
Status = egSaveFile(NULL, VBIOS_BIN, (UINT8*)(UINTN)0xc0000, 0x20000);
|
|
}
|
|
break; */
|
|
case SCAN_F10:
|
|
egScreenShot();
|
|
break;
|
|
|
|
case SCAN_DELETE:
|
|
// forward delete
|
|
if (Pos + Item->LineShift < StrLen(Buffer)) {
|
|
for (i = Pos + Item->LineShift; i < StrLen(Buffer); i++) {
|
|
Buffer[i] = Buffer[i+1];
|
|
}
|
|
/*
|
|
// Commented this out because it looks weird - Forward Delete should not
|
|
// affect anything left of the cursor even if it's just to shift more of the
|
|
// string into view.
|
|
if (Item->LineShift > 0 && Item->LineShift + LineSize > StrLen(Buffer)) {
|
|
Item->LineShift--;
|
|
Pos++;
|
|
}
|
|
*/
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (key.UnicodeChar) {
|
|
case CHAR_BACKSPACE:
|
|
if (Buffer[0] != CHAR_NULL && Pos != 0) {
|
|
for (i = Pos + Item->LineShift; i <= StrLen(Buffer); i++) {
|
|
Buffer[i-1] = Buffer[i];
|
|
}
|
|
Item->LineShift > 0 ? Item->LineShift-- : Pos--;
|
|
}
|
|
|
|
break;
|
|
|
|
case CHAR_LINEFEED:
|
|
case CHAR_CARRIAGE_RETURN:
|
|
MenuExit = MENU_EXIT_ENTER;
|
|
Pos = 0;
|
|
Item->LineShift = 0;
|
|
break;
|
|
default:
|
|
if ((key.UnicodeChar >= 0x20) &&
|
|
(key.UnicodeChar < 0x80)){
|
|
if (StrSize(Buffer) < SVALUE_MAX_SIZE) {
|
|
for (i = StrLen(Buffer)+1; i > Pos + Item->LineShift; i--) {
|
|
Buffer[i] = Buffer[i-1];
|
|
}
|
|
Buffer[i] = key.UnicodeChar;
|
|
Pos < LineSize ? Pos++ : Item->LineShift++;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
// Redraw the field
|
|
(Entries[ScrollState.CurrentSelection]).Row = Pos;
|
|
((*this).*(StyleFunc))(MENU_FUNCTION_PAINT_SELECTION, NULL);
|
|
} while (!MenuExit);
|
|
|
|
switch (MenuExit) {
|
|
case MENU_EXIT_ENTER:
|
|
Item->Valid = TRUE;
|
|
ApplyInputs();
|
|
break;
|
|
|
|
case MENU_EXIT_ESCAPE:
|
|
if (StrCmp(Item->SValue, Backup) != 0) {
|
|
snwprintf(Item->SValue, SVALUE_MAX_SIZE, "%ls", Backup);
|
|
if (Item->ItemType != BoolValue) {
|
|
Item->LineShift = BackupShift;
|
|
(Entries[ScrollState.CurrentSelection]).Row = BackupPos;
|
|
}
|
|
((*this).*(StyleFunc))( MENU_FUNCTION_PAINT_SELECTION, NULL);
|
|
}
|
|
break;
|
|
}
|
|
Item->Valid = FALSE;
|
|
FreePool(Backup);
|
|
if (Item->SValue) {
|
|
MsgLog("EDITED: %ls\n", Item->SValue);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// TimeoutDefault for a wait in seconds
|
|
// return EFI_TIMEOUT if no inputs
|
|
//the function must be in menu_screen class
|
|
//so UpdatePointer(); => mPointer.Update(&gItemID, &Screen->mAction);
|
|
EFI_STATUS REFIT_MENU_SCREEN::WaitForInputEventPoll(UINTN TimeoutDefault)
|
|
{
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
UINTN TimeoutRemain = TimeoutDefault * 100;
|
|
|
|
while (TimeoutRemain != 0) {
|
|
Status = WaitFor2EventWithTsc (gST->ConIn->WaitForKey, NULL, 10);
|
|
if (Status != EFI_TIMEOUT) {
|
|
break;
|
|
}
|
|
UpdateFilm();
|
|
if (gSettings.PlayAsync) {
|
|
CheckSyncSound(false);
|
|
}
|
|
TimeoutRemain--;
|
|
if (mPointer.isAlive()) {
|
|
mPointer.UpdatePointer(!Daylight);
|
|
Status = CheckMouseEvent(); //out: mItemID, mAction
|
|
if (Status != EFI_TIMEOUT) { //this check should return timeout if no mouse events occured
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
UINTN REFIT_MENU_SCREEN::RunGenericMenu(IN MENU_STYLE_FUNC StyleFunc, IN OUT INTN *DefaultEntryIndex, OUT REFIT_ABSTRACT_MENU_ENTRY **ChosenEntry)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_INPUT_KEY key;
|
|
// UINTN Index;
|
|
INTN ShortcutEntry;
|
|
BOOLEAN HaveTimeout = FALSE;
|
|
INTN TimeoutCountdown = 0;
|
|
UINTN MenuExit;
|
|
|
|
if (ChosenEntry == NULL) {
|
|
TextStyle = 0;
|
|
} else {
|
|
TextStyle = 2;
|
|
}
|
|
if (ThemeX.TypeSVG) {
|
|
if (!textFace[TextStyle].valid) {
|
|
if (textFace[0].valid) {
|
|
TextStyle = 0;
|
|
} else if (textFace[2].valid) {
|
|
TextStyle = 2;
|
|
} else if (textFace[1].valid) {
|
|
TextStyle = 1;
|
|
} else {
|
|
DBG("no valid text style\n");
|
|
textFace[TextStyle].size = ThemeX.TextHeight - 4;
|
|
}
|
|
}
|
|
if (textFace[TextStyle].valid) {
|
|
// TextHeight = (int)((textFace[TextStyle].size + 4) * GlobalConfig.Scale);
|
|
//clovy - row height / text size factor
|
|
ThemeX.TextHeight = (int)((textFace[TextStyle].size * RowHeightFromTextHeight) * ThemeX.Scale);
|
|
}
|
|
}
|
|
|
|
//no default - no timeout!
|
|
if ((*DefaultEntryIndex != -1) && (TimeoutSeconds > 0)) {
|
|
// DBG("have timeout\n");
|
|
HaveTimeout = TRUE;
|
|
TimeoutCountdown = TimeoutSeconds;
|
|
}
|
|
MenuExit = 0;
|
|
|
|
((*this).*(StyleFunc))(MENU_FUNCTION_INIT, NULL);
|
|
// DBG("scroll inited\n");
|
|
// override the starting selection with the default index, if any
|
|
if (*DefaultEntryIndex >= 0 && *DefaultEntryIndex <= ScrollState.MaxIndex) {
|
|
ScrollState.CurrentSelection = *DefaultEntryIndex;
|
|
UpdateScroll(SCROLL_NONE);
|
|
}
|
|
IsDragging = false;
|
|
// DBG("RunGenericMenu CurrentSelection=%d MenuExit=%d\n",
|
|
// State.CurrentSelection, MenuExit);
|
|
|
|
// exhaust key buffer and be sure no key is pressed to prevent option selection
|
|
// when coming with a key press from timeout=0, for example
|
|
while (ReadAllKeyStrokes()) gBS->Stall(500 * 1000);
|
|
while (!MenuExit) {
|
|
// update the screen
|
|
if (ScrollState.PaintAll) {
|
|
((*this).*(StyleFunc))(MENU_FUNCTION_PAINT_ALL, NULL);
|
|
ScrollState.PaintAll = FALSE;
|
|
} else if (ScrollState.PaintSelection) {
|
|
((*this).*(StyleFunc))(MENU_FUNCTION_PAINT_SELECTION, NULL);
|
|
ScrollState.PaintSelection = FALSE;
|
|
}
|
|
|
|
if (HaveTimeout) {
|
|
//TimeoutMessage = PoolPrint(L"%s in %d seconds", TimeoutText.data(), TimeoutCountdown);
|
|
XStringW TOMessage = SWPrintf("%ls in %lld seconds", TimeoutText.wc_str(), TimeoutCountdown);
|
|
((*this).*(StyleFunc))(MENU_FUNCTION_PAINT_TIMEOUT, TOMessage.data());
|
|
}
|
|
|
|
if (gEvent) { //for now used at CD eject.
|
|
MenuExit = MENU_EXIT_ESCAPE;
|
|
ScrollState.PaintAll = TRUE;
|
|
gEvent = 0; //to prevent looping
|
|
break;
|
|
}
|
|
key.UnicodeChar = 0;
|
|
key.ScanCode = 0;
|
|
if (!mGuiReady) {
|
|
mGuiReady = TRUE;
|
|
DBG("GUI ready\n");
|
|
}
|
|
|
|
EFI_TIME Now;
|
|
gRT->GetTime(&Now, NULL);
|
|
if (GlobalConfig.Timezone != 0xFF) {
|
|
INT32 NowHour = Now.Hour + GlobalConfig.Timezone;
|
|
if (NowHour < 0 ) NowHour += 24;
|
|
if (NowHour >= 24 ) NowHour -= 24;
|
|
Daylight = (NowHour > 8) && (NowHour < 20); //this is the screen member
|
|
} else {
|
|
Daylight = true;
|
|
}
|
|
|
|
Status = WaitForInputEventPoll(1); //wait for 1 seconds.
|
|
if (Status == EFI_TIMEOUT) {
|
|
if (HaveTimeout) {
|
|
if (TimeoutCountdown <= 0) {
|
|
// timeout expired
|
|
MenuExit = MENU_EXIT_TIMEOUT;
|
|
break;
|
|
} else {
|
|
// gBS->Stall(100000);
|
|
TimeoutCountdown--;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
switch (mAction) {
|
|
case ActionSelect:
|
|
ScrollState.LastSelection = ScrollState.CurrentSelection;
|
|
ScrollState.CurrentSelection = mItemID;
|
|
ScrollState.PaintAll = TRUE;
|
|
HidePointer();
|
|
break;
|
|
case ActionEnter:
|
|
ScrollState.LastSelection = ScrollState.CurrentSelection;
|
|
ScrollState.CurrentSelection = mItemID;
|
|
if ( Entries[mItemID].getREFIT_INPUT_DIALOG() || Entries[mItemID].getREFIT_MENU_CHECKBIT() ) {
|
|
MenuExit = InputDialog(StyleFunc);
|
|
} else if (Entries[mItemID].getREFIT_MENU_SWITCH()) {
|
|
MenuExit = InputDialog(StyleFunc);
|
|
ScrollState.PaintAll = TRUE;
|
|
HidePointer();
|
|
} else if (!Entries[mItemID].getREFIT_INFO_DIALOG()) {
|
|
MenuExit = MENU_EXIT_ENTER;
|
|
}
|
|
break;
|
|
case ActionHelp:
|
|
MenuExit = MENU_EXIT_HELP;
|
|
break;
|
|
case ActionOptions:
|
|
ScrollState.LastSelection = ScrollState.CurrentSelection;
|
|
ScrollState.CurrentSelection = mItemID;
|
|
MenuExit = MENU_EXIT_OPTIONS;
|
|
break;
|
|
case ActionDetails:
|
|
ScrollState.LastSelection = ScrollState.CurrentSelection;
|
|
// Index = State.CurrentSelection;
|
|
ScrollState.CurrentSelection = mItemID;
|
|
if ((Entries[mItemID].getREFIT_INPUT_DIALOG()) ||
|
|
(Entries[mItemID].getREFIT_MENU_CHECKBIT())) {
|
|
MenuExit = InputDialog(StyleFunc);
|
|
} else if (Entries[mItemID].getREFIT_MENU_SWITCH()) {
|
|
MenuExit = InputDialog(StyleFunc);
|
|
ScrollState.PaintAll = TRUE;
|
|
HidePointer();
|
|
} else if (!Entries[mItemID].getREFIT_INFO_DIALOG()) {
|
|
MenuExit = MENU_EXIT_DETAILS;
|
|
}
|
|
break;
|
|
case ActionDeselect:
|
|
ScrollState.LastSelection = ScrollState.CurrentSelection;
|
|
ScrollState.PaintAll = TRUE;
|
|
HidePointer();
|
|
break;
|
|
case ActionFinish:
|
|
MenuExit = MENU_EXIT_ESCAPE;
|
|
break;
|
|
case ActionScrollDown:
|
|
UpdateScroll(SCROLL_SCROLL_DOWN);
|
|
break;
|
|
case ActionScrollUp:
|
|
UpdateScroll(SCROLL_SCROLL_UP);
|
|
break;
|
|
case ActionMoveScrollbar:
|
|
UpdateScroll(SCROLL_SCROLLBAR_MOVE);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// read key press (and wait for it if applicable)
|
|
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &key);
|
|
if ((Status == EFI_NOT_READY) && (mAction == ActionNone)) {
|
|
continue;
|
|
}
|
|
if (mAction == ActionNone) {
|
|
ReadAllKeyStrokes(); //clean to avoid doubles
|
|
}
|
|
if (HaveTimeout) {
|
|
// the user pressed a key, cancel the timeout
|
|
((*this).*(StyleFunc))(MENU_FUNCTION_PAINT_TIMEOUT, L"");
|
|
HidePointer(); //ycr.ru
|
|
HaveTimeout = FALSE;
|
|
}
|
|
|
|
mAction = ActionNone; //do action once
|
|
// react to key press
|
|
switch (key.ScanCode) {
|
|
case SCAN_UP:
|
|
case SCAN_LEFT:
|
|
UpdateScroll(SCROLL_LINE_UP);
|
|
break;
|
|
case SCAN_DOWN:
|
|
case SCAN_RIGHT:
|
|
UpdateScroll(SCROLL_LINE_DOWN);
|
|
break;
|
|
case SCAN_HOME:
|
|
UpdateScroll(SCROLL_FIRST);
|
|
break;
|
|
case SCAN_END:
|
|
UpdateScroll(SCROLL_LAST);
|
|
break;
|
|
case SCAN_PAGE_UP:
|
|
UpdateScroll(SCROLL_PAGE_UP);
|
|
// SetNextScreenMode(1);
|
|
// ((*this).*(StyleFunc))(MENU_FUNCTION_INIT, NULL);
|
|
break;
|
|
case SCAN_PAGE_DOWN:
|
|
UpdateScroll(SCROLL_PAGE_DOWN);
|
|
// SetNextScreenMode(-1);
|
|
// ((*this).*(StyleFunc))(MENU_FUNCTION_INIT, NULL);
|
|
break;
|
|
case SCAN_ESC:
|
|
MenuExit = MENU_EXIT_ESCAPE;
|
|
break;
|
|
case SCAN_INSERT:
|
|
MenuExit = MENU_EXIT_OPTIONS;
|
|
break;
|
|
|
|
case SCAN_F1:
|
|
MenuExit = MENU_EXIT_HELP;
|
|
break;
|
|
case SCAN_F2:
|
|
SavePreBootLog = TRUE;
|
|
//let it be twice
|
|
Status = SaveBooterLog(SelfRootDir, PREBOOT_LOG);
|
|
if (EFI_ERROR(Status)) {
|
|
Status = SaveBooterLog(NULL, PREBOOT_LOG);
|
|
}
|
|
break;
|
|
case SCAN_F3:
|
|
MenuExit = MENU_EXIT_HIDE_TOGGLE;
|
|
break;
|
|
case SCAN_F4:
|
|
SaveOemTables();
|
|
break;
|
|
case SCAN_F5:
|
|
SaveOemDsdt(TRUE); //full patch
|
|
break;
|
|
case SCAN_F6:
|
|
Status = egSaveFile(SelfRootDir, VBIOS_BIN, (UINT8*)(UINTN)0xc0000, 0x20000);
|
|
if (EFI_ERROR(Status)) {
|
|
Status = egSaveFile(NULL, VBIOS_BIN, (UINT8*)(UINTN)0xc0000, 0x20000);
|
|
}
|
|
break;
|
|
/* just a sample code
|
|
case SCAN_F7:
|
|
Status = egMkDir(SelfRootDir, L"EFI\\CLOVER\\new_folder");
|
|
DBG("create folder %s\n", strerror(Status));
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = egSaveFile(SelfRootDir, L"EFI\\CLOVER\\new_folder\\new_file.txt", (UINT8*)SomeText, sizeof(*SomeText)+1);
|
|
DBG("create file %s\n", strerror(Status));
|
|
}
|
|
break;
|
|
*/
|
|
case SCAN_F7:
|
|
if (OldChosenAudio > AudioNum) {
|
|
OldChosenAudio = 0; //security correction
|
|
}
|
|
Status = gBS->HandleProtocol(AudioList[OldChosenAudio].Handle, &gEfiAudioIoProtocolGuid, (VOID**)&AudioIo);
|
|
DBG("open %llu audio handle status=%s\n", OldChosenAudio, strerror(Status));
|
|
if (!EFI_ERROR(Status)) {
|
|
StartupSoundPlay(SelfRootDir, NULL); //play embedded sound
|
|
}
|
|
break;
|
|
case SCAN_F8:
|
|
// testSVG();
|
|
SaveHdaDumpBin();
|
|
SaveHdaDumpTxt();
|
|
break;
|
|
|
|
case SCAN_F9:
|
|
SetNextScreenMode(1);
|
|
egGetScreenSize(&UGAWidth, &UGAHeight); //before init theme
|
|
gThemeChanged = TRUE;
|
|
MenuExit = MENU_EXIT_ESCAPE; //to redraw screen
|
|
break;
|
|
case SCAN_F10:
|
|
egScreenShot();
|
|
break;
|
|
case SCAN_F11:
|
|
ResetNvram();
|
|
MenuExit = MENU_EXIT_ESCAPE; //to redraw screen
|
|
break;
|
|
case SCAN_F12:
|
|
MenuExit = MENU_EXIT_EJECT;
|
|
ScrollState.PaintAll = TRUE;
|
|
break;
|
|
|
|
}
|
|
switch (key.UnicodeChar) {
|
|
case CHAR_LINEFEED:
|
|
case CHAR_CARRIAGE_RETURN:
|
|
if ((Entries[ScrollState.CurrentSelection].getREFIT_INPUT_DIALOG()) ||
|
|
(Entries[ScrollState.CurrentSelection].getREFIT_MENU_CHECKBIT())) {
|
|
MenuExit = InputDialog(StyleFunc);
|
|
} else if (Entries[ScrollState.CurrentSelection].getREFIT_MENU_SWITCH()){
|
|
MenuExit = InputDialog(StyleFunc);
|
|
ScrollState.PaintAll = TRUE;
|
|
} else if (Entries[ScrollState.CurrentSelection].getREFIT_MENU_ENTRY_CLOVER()){
|
|
MenuExit = MENU_EXIT_DETAILS;
|
|
} else if (!Entries[ScrollState.CurrentSelection].getREFIT_INFO_DIALOG()) {
|
|
MenuExit = MENU_EXIT_ENTER;
|
|
}
|
|
break;
|
|
case ' ': //CHAR_SPACE
|
|
if ((Entries[ScrollState.CurrentSelection].getREFIT_INPUT_DIALOG()) ||
|
|
(Entries[ScrollState.CurrentSelection].getREFIT_MENU_CHECKBIT())) {
|
|
MenuExit = InputDialog(StyleFunc);
|
|
} else if (Entries[ScrollState.CurrentSelection].getREFIT_MENU_SWITCH()){
|
|
MenuExit = InputDialog(StyleFunc);
|
|
ScrollState.PaintAll = TRUE;
|
|
HidePointer();
|
|
} else if (!Entries[ScrollState.CurrentSelection].getREFIT_INFO_DIALOG()) {
|
|
MenuExit = MENU_EXIT_DETAILS;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ShortcutEntry = FindMenuShortcutEntry(key.UnicodeChar);
|
|
if (ShortcutEntry >= 0) {
|
|
ScrollState.CurrentSelection = ShortcutEntry;
|
|
MenuExit = MENU_EXIT_ENTER;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
((*this).*(StyleFunc))(MENU_FUNCTION_CLEANUP, NULL);
|
|
|
|
if (ChosenEntry) {
|
|
*ChosenEntry = &Entries[ScrollState.CurrentSelection];
|
|
}
|
|
|
|
*DefaultEntryIndex = ScrollState.CurrentSelection;
|
|
|
|
return MenuExit;
|
|
}
|
|
|
|
/**
|
|
* Text Mode menu.
|
|
*/
|
|
VOID REFIT_MENU_SCREEN::TextMenuStyle(IN UINTN Function, IN CONST CHAR16 *ParamText)
|
|
{
|
|
INTN i = 0, j = 0;
|
|
static UINTN TextMenuWidth = 0,ItemWidth = 0, MenuHeight = 0;
|
|
static UINTN MenuPosY = 0;
|
|
//static CHAR16 **DisplayStrings;
|
|
CHAR16 *TimeoutMessage;
|
|
CHAR16 ResultString[TITLE_MAX_LEN]; // assume a title max length of around 128
|
|
UINTN OldChosenItem = ~(UINTN)0;
|
|
|
|
switch (Function) {
|
|
|
|
case MENU_FUNCTION_INIT:
|
|
// vertical layout
|
|
MenuPosY = 4;
|
|
|
|
if (InfoLines.size() > 0) {
|
|
MenuPosY += InfoLines.size() + 1;
|
|
}
|
|
|
|
MenuHeight = ConHeight - MenuPosY;
|
|
|
|
if (TimeoutSeconds > 0) {
|
|
MenuHeight -= 2;
|
|
}
|
|
|
|
InitScroll(Entries.size(), Entries.size(), MenuHeight, 0);
|
|
|
|
// determine width of the menu
|
|
TextMenuWidth = 50; // minimum
|
|
for (i = 0; i <= ScrollState.MaxIndex; i++) {
|
|
ItemWidth = Entries[i].Title.length();
|
|
|
|
if (TextMenuWidth < ItemWidth) {
|
|
TextMenuWidth = ItemWidth;
|
|
}
|
|
}
|
|
|
|
if (TextMenuWidth > ConWidth - 6) {
|
|
TextMenuWidth = ConWidth - 6;
|
|
}
|
|
|
|
if (Entries[0].getREFIT_MENU_SWITCH() && Entries[0].getREFIT_MENU_SWITCH()->Item->IValue == 90) {
|
|
j = OldChosenConfig;
|
|
} else if (Entries[0].getREFIT_MENU_SWITCH() && Entries[0].getREFIT_MENU_SWITCH()->Item->IValue == 116) {
|
|
j = OldChosenDsdt;
|
|
} else if (Entries[0].getREFIT_MENU_SWITCH() && Entries[0].getREFIT_MENU_SWITCH()->Item->IValue == 119) {
|
|
j = OldChosenAudio;
|
|
}
|
|
|
|
break;
|
|
|
|
case MENU_FUNCTION_CLEANUP:
|
|
// release temporary memory
|
|
|
|
// reset default output colours
|
|
gST->ConOut->SetAttribute(gST->ConOut, ATTR_BANNER);
|
|
|
|
break;
|
|
|
|
case MENU_FUNCTION_PAINT_ALL:
|
|
// paint the whole screen (initially and after scrolling)
|
|
gST->ConOut->SetAttribute (gST->ConOut, ATTR_CHOICE_BASIC);
|
|
for (i = 0; i < (INTN)ConHeight - 4; i++) {
|
|
gST->ConOut->SetCursorPosition(gST->ConOut, 0, 4 + i);
|
|
gST->ConOut->OutputString(gST->ConOut, BlankLine);
|
|
}
|
|
|
|
BeginTextScreen(Title.wc_str());
|
|
|
|
if (InfoLines.size() > 0) {
|
|
gST->ConOut->SetAttribute (gST->ConOut, ATTR_BASIC);
|
|
|
|
for (i = 0; i < (INTN)InfoLines.size(); i++) {
|
|
gST->ConOut->SetCursorPosition (gST->ConOut, 3, 4 + i);
|
|
gST->ConOut->OutputString (gST->ConOut, InfoLines[i].data());
|
|
}
|
|
}
|
|
|
|
for (i = ScrollState.FirstVisible; i <= ScrollState.LastVisible && i <= ScrollState.MaxIndex; i++) {
|
|
gST->ConOut->SetCursorPosition (gST->ConOut, 2, MenuPosY + (i - ScrollState.FirstVisible));
|
|
|
|
if (i == ScrollState.CurrentSelection) {
|
|
gST->ConOut->SetAttribute (gST->ConOut, ATTR_CHOICE_CURRENT);
|
|
} else {
|
|
gST->ConOut->SetAttribute (gST->ConOut, ATTR_CHOICE_BASIC);
|
|
}
|
|
|
|
StrCpyS(ResultString, TITLE_MAX_LEN, Entries[i].Title.wc_str());
|
|
|
|
if (Entries[i].getREFIT_INPUT_DIALOG()) {
|
|
REFIT_INPUT_DIALOG& entry = (REFIT_INPUT_DIALOG&) Entries[i];
|
|
if (entry.getREFIT_INPUT_DIALOG()) {
|
|
if ((entry).Item->ItemType == BoolValue) {
|
|
StrCatS(ResultString, TITLE_MAX_LEN, (entry).Item->BValue ? L": [+]" : L": [ ]");
|
|
} else {
|
|
StrCatS(ResultString, TITLE_MAX_LEN, (entry).Item->SValue);
|
|
}
|
|
} else if (entry.getREFIT_MENU_CHECKBIT()) {
|
|
// check boxes
|
|
StrCatS(ResultString, TITLE_MAX_LEN, ((entry).Item->IValue & (entry.Row)) ? L": [+]" : L": [ ]");
|
|
} else if (entry.getREFIT_MENU_SWITCH()) {
|
|
// radio buttons
|
|
|
|
// update chosen config
|
|
if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 90) {
|
|
OldChosenItem = OldChosenConfig;
|
|
} else if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 116) {
|
|
OldChosenItem = OldChosenDsdt;
|
|
} else if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 119) {
|
|
OldChosenItem = OldChosenAudio;
|
|
}
|
|
|
|
StrCatS(ResultString, TITLE_MAX_LEN, (entry.Row == OldChosenItem) ? L": (*)" : L": ( )");
|
|
}
|
|
}
|
|
|
|
for (j = StrLen(ResultString); j < (INTN)TextMenuWidth; j++) {
|
|
ResultString[j] = L' ';
|
|
}
|
|
|
|
ResultString[j] = 0;
|
|
gST->ConOut->OutputString(gST->ConOut, ResultString);
|
|
}
|
|
|
|
// scrolling indicators
|
|
gST->ConOut->SetAttribute (gST->ConOut, ATTR_SCROLLARROW);
|
|
gST->ConOut->SetCursorPosition (gST->ConOut, 0, MenuPosY);
|
|
|
|
if (ScrollState.FirstVisible > 0) {
|
|
gST->ConOut->OutputString (gST->ConOut, ArrowUp);
|
|
} else {
|
|
gST->ConOut->OutputString (gST->ConOut, L" ");
|
|
}
|
|
|
|
gST->ConOut->SetCursorPosition (gST->ConOut, 0, MenuPosY + ScrollState.MaxVisible);
|
|
|
|
if (ScrollState.LastVisible < ScrollState.MaxIndex) {
|
|
gST->ConOut->OutputString (gST->ConOut, ArrowDown);
|
|
} else {
|
|
gST->ConOut->OutputString (gST->ConOut, L" ");
|
|
}
|
|
|
|
break;
|
|
|
|
case MENU_FUNCTION_PAINT_SELECTION:
|
|
// last selection
|
|
// redraw selection cursor
|
|
gST->ConOut->SetCursorPosition (gST->ConOut, 2, MenuPosY + (ScrollState.LastSelection - ScrollState.FirstVisible));
|
|
gST->ConOut->SetAttribute (gST->ConOut, ATTR_CHOICE_BASIC);
|
|
//gST->ConOut->OutputString (gST->ConOut, DisplayStrings[ScrollState.LastSelection]);
|
|
StrCpyS(ResultString, TITLE_MAX_LEN, Entries[ScrollState.LastSelection].Title.wc_str());
|
|
if (Entries[ScrollState.LastSelection].getREFIT_INPUT_DIALOG()) {
|
|
REFIT_INPUT_DIALOG& entry = (REFIT_INPUT_DIALOG&) Entries[ScrollState.LastSelection];
|
|
if (entry.getREFIT_INPUT_DIALOG()) {
|
|
if (entry.Item->ItemType == BoolValue) {
|
|
StrCatS(ResultString, TITLE_MAX_LEN, entry.Item->BValue ? L": [+]" : L": [ ]");
|
|
} else {
|
|
StrCatS(ResultString, TITLE_MAX_LEN, entry.Item->SValue);
|
|
}
|
|
} else if (entry.getREFIT_MENU_CHECKBIT()) {
|
|
// check boxes
|
|
StrCatS(ResultString, TITLE_MAX_LEN, (entry.Item->IValue & (entry.Row)) ? L": [+]" : L": [ ]");
|
|
} else if (entry.getREFIT_MENU_SWITCH()) {
|
|
// radio buttons
|
|
|
|
if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 90) {
|
|
OldChosenItem = OldChosenConfig;
|
|
} else if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 116) {
|
|
OldChosenItem = OldChosenDsdt;
|
|
} else if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 119) {
|
|
OldChosenItem = OldChosenAudio;
|
|
}
|
|
|
|
StrCatS(ResultString, TITLE_MAX_LEN, (entry.Row == OldChosenItem) ? L": (*)" : L": ( )");
|
|
}
|
|
}
|
|
|
|
for (j = StrLen(ResultString); j < (INTN) TextMenuWidth; j++) {
|
|
ResultString[j] = L' ';
|
|
}
|
|
|
|
ResultString[j] = 0;
|
|
gST->ConOut->OutputString (gST->ConOut, ResultString);
|
|
|
|
// current selection
|
|
gST->ConOut->SetCursorPosition (gST->ConOut, 2, MenuPosY + (ScrollState.CurrentSelection - ScrollState.FirstVisible));
|
|
gST->ConOut->SetAttribute (gST->ConOut, ATTR_CHOICE_CURRENT);
|
|
StrCpyS(ResultString, TITLE_MAX_LEN, Entries[ScrollState.CurrentSelection].Title.wc_str());
|
|
if (Entries[ScrollState.CurrentSelection].getREFIT_INPUT_DIALOG()) {
|
|
REFIT_INPUT_DIALOG& entry = (REFIT_INPUT_DIALOG&) Entries[ScrollState.CurrentSelection];
|
|
if (entry.getREFIT_INPUT_DIALOG()) {
|
|
if (entry.Item->ItemType == BoolValue) {
|
|
StrCatS(ResultString, TITLE_MAX_LEN, entry.Item->BValue ? L": [+]" : L": [ ]");
|
|
} else {
|
|
StrCatS(ResultString, TITLE_MAX_LEN, entry.Item->SValue);
|
|
}
|
|
} else if (entry.getREFIT_MENU_CHECKBIT()) {
|
|
// check boxes
|
|
StrCatS(ResultString, TITLE_MAX_LEN, (entry.Item->IValue & (entry.Row)) ? L": [+]" : L": [ ]");
|
|
} else if (entry.getREFIT_MENU_SWITCH()) {
|
|
// radio buttons
|
|
|
|
if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 90) {
|
|
OldChosenItem = OldChosenConfig;
|
|
} else if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 116) {
|
|
OldChosenItem = OldChosenDsdt;
|
|
} else if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 119) {
|
|
OldChosenItem = OldChosenAudio;
|
|
}
|
|
|
|
StrCatS(ResultString, TITLE_MAX_LEN, (entry.Row == OldChosenItem) ? L": (*)" : L": ( )");
|
|
}
|
|
}
|
|
|
|
for (j = StrLen(ResultString); j < (INTN) TextMenuWidth; j++) {
|
|
ResultString[j] = L' ';
|
|
}
|
|
|
|
ResultString[j] = 0;
|
|
gST->ConOut->OutputString (gST->ConOut, ResultString);
|
|
//gST->ConOut->OutputString (gST->ConOut, DisplayStrings[ScrollState.CurrentSelection]);
|
|
|
|
break;
|
|
|
|
case MENU_FUNCTION_PAINT_TIMEOUT:
|
|
if (ParamText[0] == 0) {
|
|
// clear message
|
|
gST->ConOut->SetAttribute (gST->ConOut, ATTR_BASIC);
|
|
gST->ConOut->SetCursorPosition (gST->ConOut, 0, ConHeight - 1);
|
|
gST->ConOut->OutputString (gST->ConOut, BlankLine + 1);
|
|
} else {
|
|
// paint or update message
|
|
gST->ConOut->SetAttribute (gST->ConOut, ATTR_ERROR);
|
|
gST->ConOut->SetCursorPosition (gST->ConOut, 3, ConHeight - 1);
|
|
TimeoutMessage = PoolPrint(L"%s ", ParamText);
|
|
gST->ConOut->OutputString (gST->ConOut, TimeoutMessage);
|
|
FreePool(TimeoutMessage);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Draw text with specific coordinates.
|
|
*/
|
|
|
|
|
|
INTN REFIT_MENU_SCREEN::DrawTextXY(IN const XStringW& Text, IN INTN XPos, IN INTN YPos, IN UINT8 XAlign)
|
|
{
|
|
INTN TextWidth = 0;
|
|
INTN XText = 0;
|
|
INTN Height;
|
|
INTN TextXYStyle = 1;
|
|
XImage TextBufferXY(0,0);
|
|
|
|
if (Text.isEmpty()) {
|
|
return 0;
|
|
}
|
|
//TODO assume using embedded font for BootScreen
|
|
//messages must be TextXYStyle = 1 if it is provided by theme
|
|
if (!textFace[1].valid) {
|
|
if (textFace[2].valid) {
|
|
TextXYStyle = 2;
|
|
} else {
|
|
TextXYStyle = 0;
|
|
}
|
|
}
|
|
/*
|
|
* here we want to know how many place is needed for the graphical text
|
|
* the procedure worked for fixed width font but the problem appears with proportional fonts
|
|
* as well we not know yet the font using but egRenderText calculate later real width
|
|
* so make a place to be large enoungh
|
|
*/
|
|
ThemeX.MeasureText(Text, &TextWidth, NULL); //NULL means we already know Height
|
|
// DBG("drawXY=%ls width=%lld\n", Text.wc_str(), TextWidth);
|
|
if (XAlign == X_IS_LEFT) {
|
|
TextWidth = UGAWidth - XPos - 1;
|
|
XText = XPos;
|
|
}
|
|
|
|
if (!isBootScreen && ThemeX.TypeSVG) {
|
|
TextWidth += ThemeX.TextHeight * 2; //give more place for buffer
|
|
if (!textFace[TextXYStyle].valid) {
|
|
DBG("no vaid text face for message!\n");
|
|
Height = ThemeX.TextHeight;
|
|
} else {
|
|
Height = (int)(textFace[TextXYStyle].size * RowHeightFromTextHeight * ThemeX.Scale);
|
|
}
|
|
} else {
|
|
Height = ThemeX.TextHeight;
|
|
}
|
|
OldTextHeight = Height;
|
|
|
|
// TextBufferXY = egCreateFilledImage(TextWidth, Height, TRUE, &MenuBackgroundPixel);
|
|
TextBufferXY.setSizeInPixels(TextWidth, Height);
|
|
// TextBufferXY.Fill(MenuBackgroundPixel);
|
|
|
|
// render the text
|
|
INTN TextWidth2 = ThemeX.RenderText(Text, &TextBufferXY, 0, 0, 0xFFFF, TextXYStyle);
|
|
// there is real text width but we already have an array with Width = TextWidth
|
|
//
|
|
// TextBufferXY.EnsureImageSize(TextWidth2, Height); //assume color = MenuBackgroundPixel
|
|
|
|
if (XAlign != X_IS_LEFT) {
|
|
// shift 64 is prohibited
|
|
XText = XPos - (TextWidth2 >> XAlign); //X_IS_CENTER = 1
|
|
}
|
|
|
|
OldTextBufferRect.XPos = XText;
|
|
OldTextBufferRect.YPos = YPos;
|
|
OldTextBufferRect.Width = TextWidth2;
|
|
OldTextBufferRect.Height = Height;
|
|
|
|
OldTextBufferImage.GetArea(OldTextBufferRect);
|
|
//GetArea may change sizes
|
|
OldTextBufferRect.Width = OldTextBufferImage.GetWidth();
|
|
OldTextBufferRect.Height = OldTextBufferImage.GetHeight();
|
|
|
|
// DBG("draw text %ls\n", Text);
|
|
// DBG("pos=%d width=%d xtext=%d Height=%d Y=%d\n", XPos, TextWidth, XText, Height, YPos);
|
|
// TextBufferXY.Draw(XText, YPos, 0, false);
|
|
// TextBufferXY.DrawWithoutCompose(XText, YPos);
|
|
TextBufferXY.DrawOnBack(XText, YPos, ThemeX.Background);
|
|
return TextWidth2;
|
|
}
|
|
|
|
void REFIT_MENU_SCREEN::EraseTextXY() //used on boot screen
|
|
{
|
|
OldTextBufferImage.Draw(OldTextBufferRect.XPos, OldTextBufferRect.YPos);
|
|
}
|
|
/**
|
|
* Helper function to draw text for Boot Camp Style.
|
|
* @author: Needy
|
|
*/
|
|
VOID REFIT_MENU_SCREEN::DrawBCSText(IN CONST CHAR16 *Text, IN INTN XPos, IN INTN YPos, IN UINT8 XAlign)
|
|
{
|
|
// check if text was provided. And what else?
|
|
if (!Text) {
|
|
return;
|
|
}
|
|
|
|
// number of chars to be drawn on the screen
|
|
UINTN MaxTextLen = 13;
|
|
|
|
// some optimization
|
|
if (ThemeX.TileXSpace >= 25) {
|
|
MaxTextLen = ThemeX.TileXSpace / 5 + 9;
|
|
}
|
|
|
|
XStringW BCSTextX;
|
|
if (StrLen(Text) <= MaxTextLen) { // if the text exceeds the given limit
|
|
BCSTextX.strncpy(Text, MaxTextLen);
|
|
} else {
|
|
BCSTextX.strncpy(Text, MaxTextLen - 2); // EllipsisLen=2
|
|
BCSTextX += L"..";
|
|
}
|
|
DrawTextXY(BCSTextX, XPos, YPos, XAlign);
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::DrawMenuText(IN const XStringW& Text, IN INTN SelectedWidth, IN INTN XPos, IN INTN YPos, IN UINTN Cursor, IN INTN MaxWidth)
|
|
{
|
|
INTN Width = (MaxWidth > 0 && (XPos + MaxWidth <= UGAWidth)) ? MaxWidth : UGAWidth - XPos;
|
|
XImage TextBufferX(Width, ThemeX.TextHeight);
|
|
XImage SelectionBar(Width, ThemeX.TextHeight);
|
|
|
|
/*
|
|
if (Cursor == 0xFFFF) { //InfoLine = 0xFFFF
|
|
TextBufferX.Fill(MenuBackgroundPixel);
|
|
} else {
|
|
TextBufferX.Fill(InputBackgroundPixel);
|
|
}
|
|
*/
|
|
|
|
if (SelectedWidth > 0) {
|
|
// fill selection bar background
|
|
EG_RECT TextRect;
|
|
TextRect.Width = SelectedWidth;
|
|
TextRect.Height = ThemeX.TextHeight;
|
|
TextBufferX.FillArea(SelectionBackgroundPixel, TextRect);
|
|
// SelectionBar.Fill(SelectionBackgroundPixel);
|
|
}
|
|
SelectionBar.CopyRect(ThemeX.Background, XPos, YPos);
|
|
// SelectionBar.DrawWithoutCompose(XPos, YPos);
|
|
// TextBufferX.Compose(0, 0, ThemeX.Background, true);
|
|
// render the text
|
|
if (ThemeX.TypeSVG) {
|
|
//clovy - text vertically centred on Height
|
|
ThemeX.RenderText(Text, &TextBufferX, 0,
|
|
(INTN)((ThemeX.TextHeight - (textFace[TextStyle].size * ThemeX.Scale)) / 2),
|
|
Cursor, TextStyle);
|
|
} else {
|
|
ThemeX.RenderText(Text, &TextBufferX, TEXT_XMARGIN, TEXT_YMARGIN, Cursor, TextStyle);
|
|
}
|
|
SelectionBar.Compose(0, 0, TextBufferX, false);
|
|
// TextBufferX.DrawWithoutCompose(XPos, YPos);
|
|
SelectionBar.DrawWithoutCompose(XPos, YPos);
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::SetBar(INTN PosX, INTN UpPosY, INTN DownPosY, IN SCROLL_STATE *State)
|
|
{
|
|
// DBG("SetBar <= %d %d %d %d %d\n", UpPosY, DownPosY, State->MaxVisible, State->MaxIndex, State->FirstVisible);
|
|
//SetBar <= 302 722 19 31 0
|
|
UpButton.XPos = PosX;
|
|
UpButton.YPos = UpPosY;
|
|
|
|
DownButton.XPos = UpButton.XPos;
|
|
DownButton.YPos = DownPosY;
|
|
|
|
ScrollbarBackground.XPos = UpButton.XPos;
|
|
ScrollbarBackground.YPos = UpButton.YPos + UpButton.Height;
|
|
ScrollbarBackground.Width = UpButton.Width;
|
|
ScrollbarBackground.Height = DownButton.YPos - (UpButton.YPos + UpButton.Height);
|
|
|
|
BarStart.XPos = ScrollbarBackground.XPos;
|
|
BarStart.YPos = ScrollbarBackground.YPos;
|
|
BarStart.Width = ScrollbarBackground.Width;
|
|
|
|
BarEnd.Width = ScrollbarBackground.Width;
|
|
BarEnd.XPos = ScrollbarBackground.XPos;
|
|
BarEnd.YPos = DownButton.YPos - BarEnd.Height;
|
|
|
|
ScrollStart.XPos = ScrollbarBackground.XPos;
|
|
ScrollStart.YPos = ScrollbarBackground.YPos + ScrollbarBackground.Height * State->FirstVisible / (State->MaxIndex + 1);
|
|
ScrollStart.Width = ScrollbarBackground.Width;
|
|
|
|
Scrollbar.XPos = ScrollbarBackground.XPos;
|
|
Scrollbar.YPos = ScrollStart.YPos + ScrollStart.Height;
|
|
Scrollbar.Width = ScrollbarBackground.Width;
|
|
Scrollbar.Height = ScrollbarBackground.Height * (State->MaxVisible + 1) / (State->MaxIndex + 1) - ScrollStart.Height;
|
|
|
|
ScrollEnd.Width = ScrollbarBackground.Width;
|
|
ScrollEnd.XPos = ScrollbarBackground.XPos;
|
|
ScrollEnd.YPos = Scrollbar.YPos + Scrollbar.Height - ScrollEnd.Height;
|
|
|
|
Scrollbar.Height -= ScrollEnd.Height;
|
|
|
|
ScrollTotal.XPos = UpButton.XPos;
|
|
ScrollTotal.YPos = UpButton.YPos;
|
|
ScrollTotal.Width = UpButton.Width;
|
|
ScrollTotal.Height = DownButton.YPos + DownButton.Height - UpButton.YPos;
|
|
// DBG("ScrollTotal.Height = %d\n", ScrollTotal.Height); //ScrollTotal.Height = 420
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::ScrollingBar()
|
|
{
|
|
ScrollEnabled = (ScrollState.MaxFirstVisible != 0);
|
|
if (!ScrollEnabled) {
|
|
return;
|
|
}
|
|
//use compose instead of Draw
|
|
//this is a copy of old algorithm
|
|
// but we can not use Total and Draw all parts separately assumed they composed on background
|
|
// it is #else
|
|
|
|
XImage Total(ScrollTotal.Width, ScrollTotal.Height);
|
|
// Total.Fill(&MenuBackgroundPixel);
|
|
Total.CopyRect(ThemeX.Background, ScrollTotal.XPos, ScrollTotal.YPos);
|
|
if (!ThemeX.ScrollbarBackgroundImage.isEmpty()) {
|
|
for (INTN i = 0; i < ScrollbarBackground.Height; i+=ThemeX.ScrollbarBackgroundImage.GetHeight()) {
|
|
Total.Compose(ScrollbarBackground.XPos - ScrollTotal.XPos, ScrollbarBackground.YPos + i - ScrollTotal.YPos, ThemeX.ScrollbarBackgroundImage, FALSE);
|
|
}
|
|
}
|
|
Total.Compose(BarStart.XPos - ScrollTotal.XPos, BarStart.YPos - ScrollTotal.YPos, ThemeX.BarStartImage, FALSE);
|
|
Total.Compose(BarEnd.XPos - ScrollTotal.XPos, BarEnd.YPos - ScrollTotal.YPos, ThemeX.BarEndImage, FALSE);
|
|
if (!ThemeX.ScrollbarImage.isEmpty()) {
|
|
for (INTN i = 0; i < Scrollbar.Height; i+=ThemeX.ScrollbarImage.GetHeight()) {
|
|
Total.Compose(Scrollbar.XPos - ScrollTotal.XPos, Scrollbar.YPos + i - ScrollTotal.YPos, ThemeX.ScrollbarImage, FALSE);
|
|
}
|
|
}
|
|
Total.Compose(UpButton.XPos - ScrollTotal.XPos, UpButton.YPos - ScrollTotal.YPos, ThemeX.UpButtonImage, FALSE);
|
|
Total.Compose(DownButton.XPos - ScrollTotal.XPos, DownButton.YPos - ScrollTotal.YPos, ThemeX.DownButtonImage, FALSE);
|
|
Total.Compose(ScrollStart.XPos - ScrollTotal.XPos, ScrollStart.YPos - ScrollTotal.YPos, ThemeX.ScrollStartImage, FALSE);
|
|
Total.Compose(ScrollEnd.XPos - ScrollTotal.XPos, ScrollEnd.YPos - ScrollTotal.YPos, ThemeX.ScrollEndImage, FALSE);
|
|
Total.Draw(ScrollTotal.XPos, ScrollTotal.YPos, ThemeX.ScrollWidth / 16.f); //ScrollWidth can be set in theme.plist but usually=16
|
|
}
|
|
/**
|
|
* Graphical menu.
|
|
*/
|
|
VOID REFIT_MENU_SCREEN::GraphicsMenuStyle(IN UINTN Function, IN CONST CHAR16 *ParamText)
|
|
{
|
|
INTN Chosen = 0;
|
|
INTN ItemWidth = 0;
|
|
INTN t1, t2;
|
|
INTN VisibleHeight = 0; //assume vertical layout
|
|
XStringW ResultString;
|
|
INTN PlaceCentre = 0; //(TextHeight / 2) - 7;
|
|
INTN PlaceCentre1 = 0;
|
|
UINTN OldChosenItem = ~(UINTN)0;
|
|
INTN TitleLen = 0;
|
|
INTN ScaledWidth = (INTN)(ThemeX.CharWidth * ThemeX.Scale);
|
|
|
|
// clovy
|
|
INTN ctrlX, ctrlY, ctrlTextX;
|
|
|
|
HidePointer();
|
|
|
|
switch (Function) {
|
|
|
|
case MENU_FUNCTION_INIT:
|
|
{
|
|
egGetScreenSize(&UGAWidth, &UGAHeight);
|
|
InitAnime();
|
|
SwitchToGraphicsAndClear();
|
|
|
|
EntriesPosY = ((UGAHeight - (int)(LAYOUT_TOTAL_HEIGHT * ThemeX.Scale)) >> 1) + (int)(ThemeX.LayoutBannerOffset * ThemeX.Scale) + (ThemeX.TextHeight << 1);
|
|
|
|
VisibleHeight = ((UGAHeight - EntriesPosY) / ThemeX.TextHeight) - InfoLines.size() - 2;
|
|
//DBG("MENU_FUNCTION_INIT 1 EntriesPosY=%d VisibleHeight=%d\n", EntriesPosY, VisibleHeight);
|
|
if ( Entries[0].getREFIT_INPUT_DIALOG() ) {
|
|
REFIT_INPUT_DIALOG& entry = (REFIT_INPUT_DIALOG&)Entries[0];
|
|
if (entry.getREFIT_MENU_SWITCH()) {
|
|
if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 3) {
|
|
Chosen = (OldChosenTheme == 0xFFFF) ? 0: (OldChosenTheme + 1);
|
|
} else if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 90) {
|
|
Chosen = OldChosenConfig;
|
|
} else if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 116) {
|
|
Chosen = (OldChosenDsdt == 0xFFFF) ? 0: (OldChosenDsdt + 1);
|
|
} else if (entry.getREFIT_MENU_SWITCH()->Item->IValue == 119) {
|
|
Chosen = OldChosenAudio;
|
|
}
|
|
}
|
|
}
|
|
InitScroll(Entries.size(), Entries.size(), VisibleHeight, Chosen);
|
|
// determine width of the menu - not working
|
|
//MenuWidth = 80; // minimum
|
|
MenuWidth = (int)(LAYOUT_TEXT_WIDTH * ThemeX.Scale); //500
|
|
|
|
if (!TitleImage.isEmpty()) {
|
|
if (MenuWidth > (INTN)(UGAWidth - (int)(TITLEICON_SPACING * ThemeX.Scale) - TitleImage.Image.GetWidth())) {
|
|
MenuWidth = UGAWidth - (int)(TITLEICON_SPACING * ThemeX.Scale) - TitleImage.Image.GetWidth() - 2;
|
|
}
|
|
EntriesPosX = (UGAWidth - (TitleImage.Image.GetWidth() + (int)(TITLEICON_SPACING * ThemeX.Scale) + MenuWidth)) >> 1;
|
|
// DBG("UGAWIdth=%lld TitleImage.Image=%lld MenuWidth=%lld\n", UGAWidth,
|
|
// TitleImage.Image.GetWidth(), MenuWidth);
|
|
MenuWidth += TitleImage.Image.GetWidth();
|
|
} else {
|
|
EntriesPosX = (UGAWidth - MenuWidth) >> 1;
|
|
}
|
|
TimeoutPosY = EntriesPosY + (Entries.size() + 1) * ThemeX.TextHeight;
|
|
|
|
// set maximum allowed text length for menu content (this is applicable only for non-svg and non-proportional)
|
|
MenuMaxTextLen = (UINTN)(MenuWidth / ScaledWidth);
|
|
|
|
// initial painting
|
|
ThemeX.MeasureText(Title, &ItemWidth, NULL);
|
|
if (!(ThemeX.HideUIFlags & HIDEUI_FLAG_MENU_TITLE)) {
|
|
DrawTextXY(Title, (UGAWidth >> 1), EntriesPosY - ThemeX.TextHeight * 2, X_IS_CENTER);
|
|
}
|
|
|
|
if (!TitleImage.isEmpty()) {
|
|
INTN FilmXPos = (INTN)(EntriesPosX - (TitleImage.Image.GetWidth() + (int)(TITLEICON_SPACING * ThemeX.Scale)));
|
|
INTN FilmYPos = (INTN)EntriesPosY;
|
|
bool free;
|
|
XImage *tImage = TitleImage.GetBest(!Daylight, &free);
|
|
// TitleImage.Image.Draw(FilmXPos, FilmYPos); //TODO - account night and svg
|
|
|
|
// update FilmPlace only if not set by InitAnime
|
|
if (FilmC->FilmPlace.Width == 0 || FilmC->FilmPlace.Height == 0) {
|
|
FilmC->FilmPlace.XPos = FilmXPos;
|
|
FilmC->FilmPlace.YPos = FilmYPos;
|
|
FilmC->FilmPlace.Width = tImage->GetWidth();
|
|
FilmC->FilmPlace.Height = tImage->GetHeight();
|
|
}
|
|
|
|
tImage->Draw(FilmXPos, FilmYPos);
|
|
if (free) delete tImage;
|
|
}
|
|
|
|
if (InfoLines.size() > 0) {
|
|
for (UINTN i = 0; i < InfoLines.size(); i++) {
|
|
DrawMenuText(InfoLines[i], 0, EntriesPosX, EntriesPosY, 0xFFFF, 0);
|
|
EntriesPosY += ThemeX.TextHeight;
|
|
}
|
|
EntriesPosY += ThemeX.TextHeight; // also add a blank line
|
|
}
|
|
ThemeX.InitBar();
|
|
|
|
break;
|
|
}
|
|
case MENU_FUNCTION_CLEANUP:
|
|
HidePointer();
|
|
break;
|
|
|
|
case MENU_FUNCTION_PAINT_ALL:
|
|
{
|
|
// DBG("PAINT_ALL: EntriesPosY=%lld MaxVisible=%lld\n", EntriesPosY, ScrollState.MaxVisible);
|
|
// DBG("DownButton.Height=%lld TextHeight=%lld MenuWidth=%lld\n", DownButton.Height, TextHeight, MenuWidth);
|
|
t2 = EntriesPosY + (ScrollState.MaxVisible + 1) * ThemeX.TextHeight - DownButton.Height;
|
|
t1 = EntriesPosX + ThemeX.TextHeight + MenuWidth + (INTN)((TEXT_XMARGIN + 16) * ThemeX.Scale);
|
|
// DBG("PAINT_ALL: X=%lld Y=%lld\n", t1, t2);
|
|
SetBar(t1, EntriesPosY, t2, &ScrollState); //823 302 554
|
|
/*
|
|
48:307 39:206 UGAWIdth=800 TitleImage=48 MenuWidth=333
|
|
48:635 0:328 PAINT_ALL: EntriesPosY=259 MaxVisible=13
|
|
48:640 0:004 DownButton.Height=0 TextHeight=21 MenuWidth=381
|
|
48:646 0:006 PAINT_ALL: X=622 Y=553
|
|
*/
|
|
|
|
// blackosx swapped this around so drawing of selection comes before drawing scrollbar.
|
|
|
|
for (INTN i = ScrollState.FirstVisible, j = 0; i <= ScrollState.LastVisible; i++, j++) {
|
|
REFIT_ABSTRACT_MENU_ENTRY *Entry = &Entries[i];
|
|
ResultString = Entry->Title; //create a copy to modify later
|
|
if (!ThemeX.TypeSVG && !ThemeX.Proportional && ResultString.length() > MenuMaxTextLen) {
|
|
ResultString = ResultString.subString(0,MenuMaxTextLen-3) + L".."_XSW;
|
|
}
|
|
TitleLen = ResultString.length();
|
|
Entry->Place.XPos = EntriesPosX;
|
|
Entry->Place.YPos = EntriesPosY + j * ThemeX.TextHeight;
|
|
Entry->Place.Width = TitleLen * ScaledWidth;
|
|
Entry->Place.Height = (UINTN)ThemeX.TextHeight;
|
|
PlaceCentre = (INTN)((ThemeX.TextHeight - (INTN)(ThemeX.Buttons[2].GetHeight())) * ThemeX.Scale / 2);
|
|
PlaceCentre1 = (INTN)((ThemeX.TextHeight - (INTN)(ThemeX.Buttons[0].GetHeight())) * ThemeX.Scale / 2);
|
|
// clovy
|
|
ctrlX = (ThemeX.TypeSVG) ? EntriesPosX : EntriesPosX + (INTN)(TEXT_XMARGIN * ThemeX.Scale);
|
|
ctrlTextX = ctrlX + ThemeX.Buttons[0].GetWidth() + (INTN)(TEXT_XMARGIN * ThemeX.Scale / 2);
|
|
ctrlY = Entry->Place.YPos + PlaceCentre;
|
|
|
|
if ( Entry->getREFIT_INPUT_DIALOG() ) {
|
|
REFIT_INPUT_DIALOG* inputDialogEntry = Entry->getREFIT_INPUT_DIALOG();
|
|
if (inputDialogEntry->Item && inputDialogEntry->Item->ItemType == BoolValue) {
|
|
//possible artefacts
|
|
DrawMenuText(ResultString, (i == ScrollState.CurrentSelection) ? (MenuWidth) : 0,
|
|
ctrlTextX, Entry->Place.YPos, 0xFFFF, MenuWidth);
|
|
ThemeX.FillRectAreaOfScreen((ctrlTextX + ctrlX) >> 1, Entry->Place.YPos, ctrlTextX - ctrlX, ThemeX.TextHeight); //clean head
|
|
ThemeX.Buttons[(inputDialogEntry->Item->BValue)?3:2].DrawOnBack(ctrlX, ctrlY, ThemeX.Background);
|
|
} else {
|
|
// text input
|
|
ResultString += inputDialogEntry->Item->SValue + L" "_XSW;
|
|
// set cursor to beginning if it is outside of screen
|
|
if (!ThemeX.TypeSVG && !ThemeX.Proportional && (TitleLen + (INTN)Entry->Row) * ScaledWidth > MenuWidth) {
|
|
Entry->Row = 0;
|
|
}
|
|
// Slice - suppose to use Row as Cursor in text
|
|
DrawMenuText(ResultString, (i == ScrollState.CurrentSelection) ? MenuWidth : 0,
|
|
EntriesPosX, Entry->Place.YPos, TitleLen + Entry->Row, MenuWidth);
|
|
ThemeX.FillRectAreaOfScreen(MenuWidth + ((ctrlTextX + EntriesPosX) >> 1), Entry->Place.YPos, ctrlTextX - EntriesPosX, ThemeX.TextHeight); //clean tail
|
|
}
|
|
} else if (Entry->getREFIT_MENU_CHECKBIT()) {
|
|
DrawMenuText(ResultString, (i == ScrollState.CurrentSelection) ? (MenuWidth) : 0,
|
|
ctrlTextX, Entry->Place.YPos, 0xFFFF, MenuWidth);
|
|
ThemeX.FillRectAreaOfScreen((ctrlTextX + ctrlX) >> 1, Entry->Place.YPos, ctrlTextX - ctrlX, ThemeX.TextHeight); //clean head
|
|
ThemeX.Buttons[(((REFIT_INPUT_DIALOG*)(Entry))->Item->IValue & Entry->Row)?3:2].DrawOnBack(ctrlX, ctrlY, ThemeX.Background);
|
|
} else if (Entry->getREFIT_MENU_SWITCH()) {
|
|
if (Entry->getREFIT_MENU_SWITCH()->Item->IValue == 3) {
|
|
//OldChosenItem = OldChosenTheme;
|
|
OldChosenItem = (OldChosenTheme == 0xFFFF) ? 0: (OldChosenTheme + 1);
|
|
} else if (Entry->getREFIT_MENU_SWITCH()->Item->IValue == 90) {
|
|
OldChosenItem = OldChosenConfig;
|
|
} else if (Entry->getREFIT_MENU_SWITCH()->Item->IValue == 116) {
|
|
OldChosenItem = (OldChosenDsdt == 0xFFFF) ? 0: (OldChosenDsdt + 1);
|
|
} else if (Entry->getREFIT_MENU_SWITCH()->Item->IValue == 119) {
|
|
OldChosenItem = OldChosenAudio;
|
|
}
|
|
DrawMenuText(ResultString, (i == ScrollState.CurrentSelection) ? MenuWidth : 0,
|
|
// clovy EntriesPosX + (TextHeight + (INTN)(TEXT_XMARGIN * GlobalConfig.Scale)),
|
|
ctrlTextX, Entry->Place.YPos, 0xFFFF, MenuWidth);
|
|
ThemeX.FillRectAreaOfScreen((ctrlTextX + ctrlX) >> 1, Entry->Place.YPos, ctrlTextX - ctrlX, ThemeX.TextHeight); //clean head
|
|
ThemeX.Buttons[(Entry->Row == OldChosenItem)?1:0].DrawOnBack(ctrlX, ctrlY, ThemeX.Background);
|
|
} else {
|
|
//DBG("paint entry %d title=%ls\n", i, Entries[i]->Title);
|
|
DrawMenuText(ResultString, (i == ScrollState.CurrentSelection) ? MenuWidth : 0,
|
|
EntriesPosX, Entry->Place.YPos, 0xFFFF, MenuWidth);
|
|
ThemeX.FillRectAreaOfScreen(MenuWidth + ((ctrlTextX + EntriesPosX) >> 1), Entry->Place.YPos, ctrlTextX - EntriesPosX, ThemeX.TextHeight); //clean tail
|
|
}
|
|
}
|
|
|
|
ScrollingBar(); //&ScrollState - inside the class
|
|
//MouseBirth();
|
|
break;
|
|
}
|
|
case MENU_FUNCTION_PAINT_SELECTION:
|
|
{
|
|
REFIT_ABSTRACT_MENU_ENTRY *EntryL = &Entries[ScrollState.LastSelection];
|
|
REFIT_ABSTRACT_MENU_ENTRY *EntryC = &Entries[ScrollState.CurrentSelection];
|
|
|
|
// last selection
|
|
ResultString = EntryL->Title;
|
|
if (!ThemeX.TypeSVG && !ThemeX.Proportional && ResultString.length() > MenuMaxTextLen) {
|
|
ResultString = ResultString.subString(0,MenuMaxTextLen-3) + L".."_XSW;
|
|
}
|
|
TitleLen = ResultString.length();
|
|
//clovy//PlaceCentre = (TextHeight - (INTN)(Buttons[2]->Height * GlobalConfig.Scale)) / 2;
|
|
//clovy//PlaceCentre = (PlaceCentre>0)?PlaceCentre:0;
|
|
//clovy//PlaceCentre1 = (TextHeight - (INTN)(Buttons[0]->Height * GlobalConfig.Scale)) / 2;
|
|
PlaceCentre = (INTN)((ThemeX.TextHeight - (INTN)(ThemeX.Buttons[2].GetHeight())) * ThemeX.Scale / 2);
|
|
PlaceCentre1 = (INTN)((ThemeX.TextHeight - (INTN)(ThemeX.Buttons[0].GetHeight())) * ThemeX.Scale / 2);
|
|
|
|
// clovy
|
|
ctrlX = (ThemeX.TypeSVG) ? EntriesPosX : EntriesPosX + (INTN)(TEXT_XMARGIN * ThemeX.Scale);
|
|
ctrlTextX = ctrlX + ThemeX.Buttons[0].GetWidth() + (INTN)(TEXT_XMARGIN * ThemeX.Scale / 2);
|
|
|
|
// redraw selection cursor
|
|
// 1. blackosx swapped this around so drawing of selection comes before drawing scrollbar.
|
|
// 2. usr-sse2
|
|
if ( EntryL->getREFIT_INPUT_DIALOG() ) {
|
|
REFIT_INPUT_DIALOG* inputDialogEntry = (REFIT_INPUT_DIALOG*)EntryL;
|
|
if (inputDialogEntry->Item->ItemType == BoolValue) { //this is checkbox
|
|
//clovy
|
|
DrawMenuText(ResultString, 0,
|
|
ctrlTextX, EntryL->Place.YPos, 0xFFFF, MenuWidth);
|
|
ThemeX.Buttons[(inputDialogEntry->Item->BValue)?3:2].DrawOnBack(ctrlX, EntryL->Place.YPos + PlaceCentre, ThemeX.Background);
|
|
} else {
|
|
ResultString += (inputDialogEntry->Item->SValue + inputDialogEntry->Item->LineShift) + L" "_XSW;
|
|
DrawMenuText(ResultString, 0,
|
|
EntriesPosX, EntryL->Place.YPos, TitleLen + EntryL->Row, MenuWidth);
|
|
ThemeX.FillRectAreaOfScreen(MenuWidth + ((ctrlTextX + EntriesPosX) >> 1), EntryL->Place.YPos, ctrlTextX - EntriesPosX, ThemeX.TextHeight); //clean tail
|
|
}
|
|
} else if (EntryL->getREFIT_MENU_SWITCH()) { //radio buttons 0,1
|
|
if (EntryL->getREFIT_MENU_SWITCH()->Item->IValue == 3) {
|
|
OldChosenItem = (OldChosenTheme == 0xFFFF) ? 0: OldChosenTheme + 1;
|
|
} else if (EntryL->getREFIT_MENU_SWITCH()->Item->IValue == 90) {
|
|
OldChosenItem = OldChosenConfig;
|
|
} else if (EntryL->getREFIT_MENU_SWITCH()->Item->IValue == 116) {
|
|
OldChosenItem = (OldChosenDsdt == 0xFFFF) ? 0: OldChosenDsdt + 1;
|
|
} else if (EntryL->getREFIT_MENU_SWITCH()->Item->IValue == 119) {
|
|
OldChosenItem = OldChosenAudio;
|
|
}
|
|
// clovy
|
|
DrawMenuText(ResultString, 0,
|
|
ctrlTextX, EntryL->Place.YPos, 0xFFFF, MenuWidth);
|
|
ThemeX.Buttons[(EntryL->Row == OldChosenItem)?1:0].DrawOnBack(ctrlX, EntryL->Place.YPos + PlaceCentre1, ThemeX.Background);
|
|
} else if (EntryL->getREFIT_MENU_CHECKBIT()) {
|
|
// clovy
|
|
DrawMenuText(ResultString, 0,
|
|
ctrlTextX, EntryL->Place.YPos, 0xFFFF, MenuWidth);
|
|
ThemeX.Buttons[(EntryL->getREFIT_MENU_CHECKBIT()->Item->IValue & EntryL->Row) ?3:2].DrawOnBack(ctrlX, EntryL->Place.YPos + PlaceCentre, ThemeX.Background);
|
|
} else {
|
|
DrawMenuText(ResultString, 0,
|
|
EntriesPosX, EntryL->Place.YPos, 0xFFFF, MenuWidth);
|
|
ThemeX.FillRectAreaOfScreen(MenuWidth + ((ctrlTextX + EntriesPosX) >> 1), EntryL->Place.YPos, ctrlTextX - EntriesPosX, ThemeX.TextHeight); //clean tail
|
|
}
|
|
|
|
// current selection
|
|
ResultString = EntryC->Title;
|
|
if (!ThemeX.TypeSVG && !ThemeX.Proportional && ResultString.length() > MenuMaxTextLen) {
|
|
ResultString = ResultString.subString(0,MenuMaxTextLen-3) + L".."_XSW;
|
|
}
|
|
TitleLen = ResultString.length();
|
|
if ( EntryC->getREFIT_MENU_SWITCH() ) {
|
|
if (EntryC->getREFIT_MENU_SWITCH()->Item->IValue == 3) {
|
|
OldChosenItem = (OldChosenTheme == 0xFFFF) ? 0: OldChosenTheme + 1;;
|
|
} else if (EntryC->getREFIT_MENU_SWITCH()->Item->IValue == 90) {
|
|
OldChosenItem = OldChosenConfig;
|
|
} else if (EntryC->getREFIT_MENU_SWITCH()->Item->IValue == 116) {
|
|
OldChosenItem = (OldChosenDsdt == 0xFFFF) ? 0: OldChosenDsdt + 1;
|
|
} else if (EntryC->getREFIT_MENU_SWITCH()->Item->IValue == 119) {
|
|
OldChosenItem = OldChosenAudio;
|
|
}
|
|
}
|
|
|
|
if ( EntryC->getREFIT_INPUT_DIALOG() ) {
|
|
REFIT_INPUT_DIALOG* inputDialogEntry = (REFIT_INPUT_DIALOG*)EntryC;
|
|
if (inputDialogEntry->Item->ItemType == BoolValue) { //checkbox
|
|
DrawMenuText(ResultString, MenuWidth,
|
|
ctrlTextX, EntryC->Place.YPos, 0xFFFF, MenuWidth);
|
|
ThemeX.Buttons[(inputDialogEntry->Item->BValue)?3:2].DrawOnBack(ctrlX, EntryC->Place.YPos + PlaceCentre, ThemeX.Background);
|
|
} else {
|
|
ResultString += (inputDialogEntry->Item->SValue + inputDialogEntry->Item->LineShift) + L" "_XSW;
|
|
DrawMenuText(ResultString, MenuWidth,
|
|
EntriesPosX, EntryC->Place.YPos, TitleLen + EntryC->Row, MenuWidth);
|
|
}
|
|
} else if (EntryC->getREFIT_MENU_SWITCH()) { //radio
|
|
DrawMenuText(ResultString, MenuWidth,
|
|
ctrlTextX, EntryC->Place.YPos, 0xFFFF, MenuWidth);
|
|
ThemeX.Buttons[(EntryC->Row == OldChosenItem)?1:0].DrawOnBack(ctrlX, EntryC->Place.YPos + PlaceCentre1, ThemeX.Background);
|
|
} else if (EntryC->getREFIT_MENU_CHECKBIT()) {
|
|
DrawMenuText(ResultString, MenuWidth,
|
|
ctrlTextX, EntryC->Place.YPos, 0xFFFF, MenuWidth);
|
|
ThemeX.Buttons[(EntryC->getREFIT_MENU_CHECKBIT()->Item->IValue & EntryC->Row)?3:2].DrawOnBack(ctrlX, EntryC->Place.YPos + PlaceCentre, ThemeX.Background);
|
|
} else {
|
|
DrawMenuText(ResultString, MenuWidth,
|
|
EntriesPosX, EntryC->Place.YPos, 0xFFFF, MenuWidth);
|
|
}
|
|
|
|
ScrollStart.YPos = ScrollbarBackground.YPos + ScrollbarBackground.Height * ScrollState.FirstVisible / (ScrollState.MaxIndex + 1);
|
|
Scrollbar.YPos = ScrollStart.YPos + ScrollStart.Height;
|
|
ScrollEnd.YPos = Scrollbar.YPos + Scrollbar.Height; // ScrollEnd.Height is already subtracted
|
|
ScrollingBar(); //&ScrollState);
|
|
|
|
break;
|
|
}
|
|
|
|
case MENU_FUNCTION_PAINT_TIMEOUT: //ParamText should be XStringW
|
|
ResultString.takeValueFrom(ParamText);
|
|
INTN X = (UGAWidth - StrLen(ParamText) * ScaledWidth) >> 1;
|
|
DrawMenuText(ResultString, 0, X, TimeoutPosY, 0xFFFF, 0);
|
|
break;
|
|
}
|
|
|
|
MouseBirth();
|
|
}
|
|
|
|
/**
|
|
* Draw entries for GUI.
|
|
*/
|
|
|
|
VOID REFIT_MENU_SCREEN::DrawMainMenuLabel(IN CONST XStringW& Text, IN INTN XPos, IN INTN YPos)
|
|
{
|
|
INTN TextWidth = 0;
|
|
INTN BadgeDim = (INTN)(BADGE_DIMENSION * ThemeX.Scale);
|
|
|
|
ThemeX.MeasureText(Text, &TextWidth, NULL);
|
|
|
|
//Clear old text
|
|
ThemeX.FillRectAreaOfScreen(OldX, OldY, OldTextWidth, OldTextHeight);
|
|
|
|
if (!(ThemeX.BootCampStyle)
|
|
&& (ThemeX.HideBadges & HDBADGES_INLINE) && (!OldRow)
|
|
&& (OldTextWidth) && (OldTextWidth != TextWidth)
|
|
) {
|
|
//Clear badge
|
|
ThemeX.FillRectAreaOfScreen((OldX - (OldTextWidth >> 1) - (BadgeDim + 16)),
|
|
(OldY - ((BadgeDim - ThemeX.TextHeight) >> 1)), 128, 128);
|
|
}
|
|
DrawTextXY(Text, XPos, YPos, X_IS_CENTER);
|
|
|
|
//show inline badge
|
|
if (!(ThemeX.BootCampStyle) &&
|
|
(ThemeX.HideBadges & HDBADGES_INLINE) &&
|
|
(Entries[ScrollState.CurrentSelection].Row == 0)) {
|
|
// Display Inline Badge: small icon before the text
|
|
XImage Back(BadgeDim, BadgeDim);
|
|
INTN X = XPos - (TextWidth >> 1) - (BadgeDim + 16);
|
|
INTN Y = YPos - ((BadgeDim - ThemeX.TextHeight) >> 1);
|
|
Back.CopyRect(ThemeX.Background, X, Y);
|
|
bool free = false;
|
|
XImage *CurrSel = Entries[ScrollState.CurrentSelection].Image.GetBest(!Daylight, &free);
|
|
Back.Compose(0, 0, *CurrSel, false, BadgeDim/128.f);
|
|
Back.DrawOnBack(X, Y, Back);
|
|
if (free) {
|
|
delete CurrSel;
|
|
}
|
|
}
|
|
|
|
OldX = XPos;
|
|
OldY = YPos;
|
|
OldTextWidth = TextWidth;
|
|
OldRow = Entries[ScrollState.CurrentSelection].Row;
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::CountItems()
|
|
{
|
|
row0PosX = 0;
|
|
row1PosX = Entries.size();
|
|
// layout
|
|
row0Count = 0; //Nr items in row0
|
|
row1Count = 0;
|
|
for (INTN i = 0; i < (INTN)Entries.size(); i++) {
|
|
if (Entries[i].Row == 0) {
|
|
row0Count++;
|
|
CONSTRAIN_MIN(row0PosX, i);
|
|
} else {
|
|
row1Count++;
|
|
CONSTRAIN_MAX(row1PosX, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::DrawTextCorner(UINTN TextC, UINT8 Align)
|
|
{
|
|
INTN Xpos;
|
|
// CHAR16 *Text = NULL;
|
|
XStringW Text;
|
|
|
|
if (
|
|
// HIDEUI_ALL - included
|
|
((TextC == TEXT_CORNER_REVISION) && ((ThemeX.HideUIFlags & HIDEUI_FLAG_REVISION) != 0)) ||
|
|
((TextC == TEXT_CORNER_HELP) && ((ThemeX.HideUIFlags & HIDEUI_FLAG_HELP) != 0)) ||
|
|
((TextC == TEXT_CORNER_OPTIMUS) && (GlobalConfig.ShowOptimus == FALSE))
|
|
) {
|
|
return;
|
|
}
|
|
|
|
switch (TextC) {
|
|
case TEXT_CORNER_REVISION:
|
|
// Display Clover boot volume
|
|
if (SelfVolume->VolLabel && SelfVolume->VolLabel[0] != L'#') {
|
|
// Text = PoolPrint(L"%s, booted from %s", gFirmwareRevision, SelfVolume->VolLabel);
|
|
Text = XStringW() + gFirmwareRevision + L", booted from "_XSW + SelfVolume->VolLabel;
|
|
}
|
|
if (Text.isEmpty()) {
|
|
Text = XStringW() + gFirmwareRevision + L" "_XSW + SelfVolume->VolName;
|
|
}
|
|
break;
|
|
case TEXT_CORNER_HELP:
|
|
Text = L"F1:Help"_XSW;
|
|
break;
|
|
case TEXT_CORNER_OPTIMUS:
|
|
if (gGraphics[0].Vendor != Intel) {
|
|
Text = L"Discrete"_XSW;
|
|
} else {
|
|
Text = L"Intel"_XSW;
|
|
}
|
|
// Text = (NGFX == 2)?L"Intel":L"Discrete";
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
switch (Align) {
|
|
case X_IS_LEFT:
|
|
Xpos = (INTN)(ThemeX.TextHeight * 0.75f);
|
|
break;
|
|
case X_IS_RIGHT:
|
|
Xpos = UGAWidth - (INTN)(ThemeX.TextHeight * 0.75f);//2
|
|
break;
|
|
case X_IS_CENTER:
|
|
Xpos = UGAWidth >> 1;
|
|
break;
|
|
default:
|
|
Text.setEmpty();
|
|
return;
|
|
}
|
|
// DBG("draw text %ls at (%d, %d)\n", Text, Xpos, UGAHeight - 5 - TextHeight),
|
|
// clovy DrawTextXY(Text, Xpos, UGAHeight - 5 - TextHeight, Align);
|
|
DrawTextXY(Text, Xpos, UGAHeight - (INTN)(ThemeX.TextHeight * 1.5f), Align);
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::DrawMainMenuEntry(REFIT_ABSTRACT_MENU_ENTRY *Entry, BOOLEAN selected, INTN XPos, INTN YPos)
|
|
{
|
|
INTN MainSize = ThemeX.MainEntriesSize;
|
|
// XImage MainImage(MainSize, MainSize);
|
|
// XImage* BadgeImage;
|
|
XIcon MainIcon; //it can be changed here
|
|
XIcon* BadgeIcon = NULL;
|
|
|
|
if (Entry->Row == 0 && Entry->getDriveImage() && !(ThemeX.HideBadges & HDBADGES_SWAP)) {
|
|
MainIcon = *Entry->getDriveImage();
|
|
} else {
|
|
MainIcon = Entry->Image; // XIcon*
|
|
}
|
|
//this should be inited by the Theme
|
|
if (MainIcon.isEmpty()) {
|
|
// DBG(" why MainImage is empty? Report to devs\n");
|
|
if (!IsEmbeddedTheme()) {
|
|
MainIcon = ThemeX.GetIcon("os_mac"_XS8);
|
|
}
|
|
if (MainIcon.Image.isEmpty()) {
|
|
MainIcon.Image.DummyImage(MainSize);
|
|
MainIcon.setFilled();
|
|
}
|
|
}
|
|
|
|
// const XImage& MainImage = (!ThemeX.Daylight && !MainIcon.ImageNight.isEmpty())? MainIcon.ImageNight : MainIcon.Image;
|
|
bool free = false;
|
|
XImage *MainImage = MainIcon.GetBest(!Daylight, &free);
|
|
|
|
INTN CompWidth = (Entry->Row == 0) ? ThemeX.row0TileSize : ThemeX.row1TileSize;
|
|
INTN CompHeight = CompWidth;
|
|
|
|
float fScale;
|
|
if (ThemeX.TypeSVG) {
|
|
fScale = (selected ? 1.f : -1.f);
|
|
} else {
|
|
fScale = ((Entry->Row == 0) ? (ThemeX.MainEntriesSize/128.f * (selected ? 1.f : -1.f)): 1.f) ;
|
|
}
|
|
|
|
if (Entry->Row == 0) {
|
|
BadgeIcon = Entry->getBadgeImage();
|
|
}
|
|
|
|
const XImage& TopImage = ThemeX.SelectionImages[((Entry->Row == 0) ? 0 : 2) + (selected ? 0 : 1)];
|
|
// DBG(" SelectionWidth=%lld\n", TopImage.GetWidth());
|
|
if (TopImage.GetWidth() > CompWidth) {
|
|
CompWidth = TopImage.GetWidth();
|
|
CompHeight = CompWidth;
|
|
}
|
|
XImage Back(CompWidth, CompHeight);
|
|
Back.CopyRect(ThemeX.Background, XPos, YPos);
|
|
|
|
INTN OffsetX = (CompWidth - MainImage->GetWidth()) / 2;
|
|
OffsetX = (OffsetX > 0) ? OffsetX: 0;
|
|
INTN OffsetY = (CompHeight - MainImage->GetHeight()) / 2;
|
|
OffsetY = (OffsetY > 0) ? OffsetY: 0;
|
|
|
|
INTN OffsetTX = (CompWidth - TopImage.GetWidth()) / 2;
|
|
OffsetTX = (OffsetTX > 0) ? OffsetTX: 0;
|
|
INTN OffsetTY = (CompHeight - TopImage.GetHeight()) / 2;
|
|
OffsetTY = (OffsetTY > 0) ? OffsetTY: 0;
|
|
|
|
// DBG(" Comp=[%lld,%lld], offset=[%lld,%lld]\n", CompWidth, CompHeight, OffsetX, OffsetY);
|
|
|
|
float composeScale = (ThemeX.NonSelectedGrey && !selected)? -1.f: 1.f;
|
|
if(ThemeX.SelectionOnTop) {
|
|
//place main image in centre. It may be OS or Drive
|
|
Back.Compose(OffsetX, OffsetY, *MainImage, false, composeScale);
|
|
} else {
|
|
Back.Compose(OffsetTX, OffsetTY, TopImage, false); //selection first
|
|
Back.Compose(OffsetX, OffsetY, *MainImage, false, composeScale);
|
|
}
|
|
|
|
Entry->Place.XPos = XPos;
|
|
Entry->Place.YPos = YPos;
|
|
Entry->Place.Width = MainImage->GetWidth();
|
|
Entry->Place.Height = MainImage->GetHeight();
|
|
|
|
if (free) {
|
|
delete MainImage;
|
|
}
|
|
// place the badge image
|
|
float fBadgeScale = ThemeX.BadgeScale/16.f;
|
|
if ((Entry->Row == 0) && BadgeIcon && !BadgeIcon->isEmpty()) {
|
|
// const XImage& BadgeImage = (!ThemeX.Daylight && !BadgeIcon->ImageNight.isEmpty()) ? &BadgeIcon->ImageNight : BadgeImage = &BadgeIcon->Image;
|
|
free = false;
|
|
XImage* BadgeImage = BadgeIcon->GetBest(!Daylight, &free);
|
|
INTN BadgeWidth = (INTN)(BadgeImage->GetWidth() * fBadgeScale);
|
|
INTN BadgeHeight = (INTN)(BadgeImage->GetHeight() * fBadgeScale);
|
|
|
|
if ((BadgeWidth + 8) < CompWidth && (BadgeHeight + 8) < CompHeight) {
|
|
|
|
// Check for user badge x offset from theme.plist
|
|
if (ThemeX.BadgeOffsetX != 0xFFFF) {
|
|
OffsetX += ThemeX.BadgeOffsetX;
|
|
} else {
|
|
// Set default position
|
|
OffsetX += CompWidth - 8 - BadgeWidth;
|
|
}
|
|
// Check for user badge y offset from theme.plist
|
|
if (ThemeX.BadgeOffsetY != 0xFFFF) {
|
|
OffsetY += ThemeX.BadgeOffsetY;
|
|
} else {
|
|
// Set default position
|
|
OffsetY += CompHeight - 8 - BadgeHeight;
|
|
}
|
|
// DBG(" badge offset=[%lld,%lld]\n", OffsetX, OffsetY);
|
|
Back.Compose(OffsetX, OffsetY, *BadgeImage, false, fBadgeScale);
|
|
if (free) delete BadgeImage;
|
|
}
|
|
}
|
|
|
|
if(ThemeX.SelectionOnTop) {
|
|
Back.Compose(OffsetTX, OffsetTY, TopImage, false); //selection at the top
|
|
}
|
|
Back.DrawWithoutCompose(XPos, YPos);
|
|
|
|
|
|
// draw BCS indicator
|
|
// Needy: if Labels (Titles) are hidden there is no point to draw the indicator
|
|
if (ThemeX.BootCampStyle && !(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL)) {
|
|
// indicator is for row 0, main entries, only
|
|
if (Entry->Row == 0) {
|
|
const XImage& SelImage = ThemeX.SelectionImages[4 + (selected ? 0 : 1)];
|
|
XPos = XPos + (ThemeX.row0TileSize / 2) - (INTN)(INDICATOR_SIZE * 0.5f * ThemeX.Scale);
|
|
YPos = row0PosY + ThemeX.row0TileSize + ThemeX.TextHeight + (INTN)((BCSMargin * 2) * ThemeX.Scale);
|
|
CompWidth = (INTN)(INDICATOR_SIZE * ThemeX.Scale);
|
|
CompHeight = (INTN)(INDICATOR_SIZE * ThemeX.Scale);
|
|
Back = XImage(CompWidth, CompHeight);
|
|
Back.CopyRect(ThemeX.Background, XPos, YPos);
|
|
Back.Compose(0, 0, SelImage, false);
|
|
Back.DrawWithoutCompose(XPos, YPos);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID REFIT_MENU_SCREEN::MainMenuVerticalStyle(IN UINTN Function, IN CONST CHAR16 *ParamText)
|
|
{
|
|
// INTN i;
|
|
INTN row0PosYRunning;
|
|
INTN VisibleHeight = 0; //assume vertical layout
|
|
INTN MessageHeight = 20;
|
|
|
|
if (ThemeX.TypeSVG && textFace[1].valid) {
|
|
MessageHeight = (INTN)(textFace[1].size * RowHeightFromTextHeight * ThemeX.Scale);
|
|
} else {
|
|
MessageHeight = (INTN)(ThemeX.TextHeight * RowHeightFromTextHeight * ThemeX.Scale);
|
|
}
|
|
|
|
switch (Function) {
|
|
|
|
case MENU_FUNCTION_INIT:
|
|
egGetScreenSize(&UGAWidth, &UGAHeight); //do this when needed
|
|
InitAnime();
|
|
SwitchToGraphicsAndClear();
|
|
//BltClearScreen(FALSE);
|
|
//adjustable by theme.plist?
|
|
EntriesPosY = (int)(LAYOUT_Y_EDGE * ThemeX.Scale);
|
|
EntriesGap = (int)(ThemeX.TileYSpace * ThemeX.Scale);
|
|
EntriesWidth = ThemeX.MainEntriesSize + (int)(16 * ThemeX.Scale);
|
|
EntriesHeight = ThemeX.MainEntriesSize + (int)(16 * ThemeX.Scale);
|
|
//
|
|
VisibleHeight = (UGAHeight - EntriesPosY - (int)(LAYOUT_Y_EDGE * ThemeX.Scale) + EntriesGap) / (EntriesHeight + EntriesGap);
|
|
EntriesPosX = UGAWidth - EntriesWidth - (int)((BAR_WIDTH + LAYOUT_X_EDGE) * ThemeX.Scale);
|
|
TimeoutPosY = UGAHeight - (int)(LAYOUT_Y_EDGE * ThemeX.Scale) - MessageHeight * 2; //optimus + timeout texts
|
|
|
|
CountItems();
|
|
InitScroll(row0Count, Entries.size(), VisibleHeight, 0);
|
|
row0PosX = EntriesPosX;
|
|
row0PosY = EntriesPosY;
|
|
row1PosX = (UGAWidth + EntriesGap - (ThemeX.row1TileSize + (int)(TILE1_XSPACING * ThemeX.Scale)) * row1Count) >> 1;
|
|
textPosY = TimeoutPosY - (int)(ThemeX.TileYSpace * ThemeX.Scale) - MessageHeight; //message text
|
|
row1PosY = textPosY - ThemeX.row1TileSize - (int)(ThemeX.TileYSpace * ThemeX.Scale) - ThemeX.LayoutTextOffset;
|
|
if (!itemPosX) {
|
|
itemPosX = (__typeof__(itemPosX))AllocatePool(sizeof(UINT64) * Entries.size());
|
|
itemPosY = (__typeof__(itemPosY))AllocatePool(sizeof(UINT64) * Entries.size());
|
|
}
|
|
row0PosYRunning = row0PosY;
|
|
row1PosXRunning = row1PosX;
|
|
|
|
// DBG("EntryCount =%d\n", Entries.size());
|
|
for (INTN i = 0; i < (INTN)Entries.size(); i++) {
|
|
if (Entries[i].Row == 0) {
|
|
itemPosX[i] = row0PosX;
|
|
itemPosY[i] = row0PosYRunning;
|
|
row0PosYRunning += EntriesHeight + EntriesGap;
|
|
} else {
|
|
itemPosX[i] = row1PosXRunning;
|
|
itemPosY[i] = row1PosY;
|
|
row1PosXRunning += ThemeX.row1TileSize + (int)(ThemeX.TileXSpace * ThemeX.Scale);
|
|
// DBG("next item in row1 at x=%d\n", row1PosXRunning);
|
|
}
|
|
}
|
|
|
|
// Update FilmPlace only if not set by InitAnime
|
|
if (FilmC->FilmPlace.Width == 0 || FilmC->FilmPlace.Height == 0) {
|
|
FilmC->FilmPlace = ThemeX.BannerPlace;
|
|
}
|
|
|
|
ThemeX.InitBar(); //not sure
|
|
break;
|
|
|
|
case MENU_FUNCTION_CLEANUP:
|
|
FreePool(itemPosX);
|
|
itemPosX = NULL;
|
|
FreePool(itemPosY);
|
|
itemPosY = NULL;
|
|
HidePointer();
|
|
break;
|
|
|
|
case MENU_FUNCTION_PAINT_ALL:
|
|
SetBar(EntriesPosX + EntriesWidth + (int)(10 * ThemeX.Scale),
|
|
EntriesPosY, UGAHeight - (int)(LAYOUT_Y_EDGE * ThemeX.Scale), &ScrollState);
|
|
for (INTN i = 0; i <= ScrollState.MaxIndex; i++) {
|
|
if (Entries[i].Row == 0) {
|
|
if ((i >= ScrollState.FirstVisible) && (i <= ScrollState.LastVisible)) {
|
|
DrawMainMenuEntry(&Entries[i], (i == ScrollState.CurrentSelection)?1:0,
|
|
itemPosX[i - ScrollState.FirstVisible], itemPosY[i - ScrollState.FirstVisible]);
|
|
}
|
|
} else { //row1
|
|
DrawMainMenuEntry(&Entries[i], (i == ScrollState.CurrentSelection)?1:0,
|
|
itemPosX[i], itemPosY[i]);
|
|
}
|
|
}
|
|
if (!(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL)){
|
|
DrawMainMenuLabel(Entries[ScrollState.CurrentSelection].Title,
|
|
(UGAWidth >> 1), textPosY);
|
|
}
|
|
|
|
ScrollingBar(); //&ScrollState);
|
|
DrawTextCorner(TEXT_CORNER_REVISION, X_IS_LEFT);
|
|
DrawTextCorner(TEXT_CORNER_OPTIMUS, X_IS_CENTER);
|
|
MouseBirth();
|
|
break;
|
|
|
|
case MENU_FUNCTION_PAINT_SELECTION:
|
|
HidePointer();
|
|
if (Entries[ScrollState.LastSelection].Row == 0) {
|
|
DrawMainMenuEntry(&Entries[ScrollState.LastSelection], FALSE,
|
|
itemPosX[ScrollState.LastSelection - ScrollState.FirstVisible],
|
|
itemPosY[ScrollState.LastSelection - ScrollState.FirstVisible]);
|
|
} else {
|
|
DrawMainMenuEntry(&Entries[ScrollState.LastSelection], FALSE,
|
|
itemPosX[ScrollState.LastSelection],
|
|
itemPosY[ScrollState.LastSelection]);
|
|
}
|
|
|
|
if (Entries[ScrollState.CurrentSelection].Row == 0) {
|
|
DrawMainMenuEntry(&Entries[ScrollState.CurrentSelection], TRUE,
|
|
itemPosX[ScrollState.CurrentSelection - ScrollState.FirstVisible],
|
|
itemPosY[ScrollState.CurrentSelection - ScrollState.FirstVisible]);
|
|
} else {
|
|
DrawMainMenuEntry(&Entries[ScrollState.CurrentSelection], TRUE,
|
|
itemPosX[ScrollState.CurrentSelection],
|
|
itemPosY[ScrollState.CurrentSelection]);
|
|
}
|
|
if (!(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL)) {
|
|
DrawMainMenuLabel(Entries[ScrollState.CurrentSelection].Title,
|
|
(UGAWidth >> 1), textPosY);
|
|
}
|
|
|
|
ScrollingBar(); //&ScrollState);
|
|
DrawTextCorner(TEXT_CORNER_REVISION, X_IS_LEFT);
|
|
DrawTextCorner(TEXT_CORNER_OPTIMUS, X_IS_CENTER);
|
|
MouseBirth();
|
|
break;
|
|
|
|
case MENU_FUNCTION_PAINT_TIMEOUT:
|
|
INTN hi = MessageHeight * ((ThemeX.HideBadges & HDBADGES_INLINE)?3:1);
|
|
HidePointer();
|
|
if (!(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL)) {
|
|
ThemeX.FillRectAreaOfScreen((UGAWidth >> 1), textPosY + hi,
|
|
OldTimeoutTextWidth, ThemeX.TextHeight);
|
|
XStringW TextX;
|
|
TextX.takeValueFrom(ParamText);
|
|
OldTimeoutTextWidth = DrawTextXY(TextX, (UGAWidth >> 1), textPosY + hi, X_IS_CENTER);
|
|
}
|
|
|
|
DrawTextCorner(TEXT_CORNER_REVISION, X_IS_LEFT);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Main screen text.
|
|
*/
|
|
VOID REFIT_MENU_SCREEN::MainMenuStyle(IN UINTN Function, IN CONST CHAR16 *ParamText)
|
|
{
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
// INTN i = 0;
|
|
INTN MessageHeight = 0;
|
|
// clovy
|
|
if (ThemeX.TypeSVG && textFace[1].valid) {
|
|
MessageHeight = (INTN)(textFace[1].size * RowHeightFromTextHeight * ThemeX.Scale);
|
|
} else {
|
|
MessageHeight = (INTN)(ThemeX.TextHeight * RowHeightFromTextHeight * ThemeX.Scale);
|
|
}
|
|
|
|
switch (Function) {
|
|
|
|
case MENU_FUNCTION_INIT:
|
|
egGetScreenSize(&UGAWidth, &UGAHeight);
|
|
InitAnime();
|
|
SwitchToGraphicsAndClear();
|
|
//BltClearScreen(FALSE);
|
|
|
|
EntriesGap = (int)(ThemeX.TileXSpace * ThemeX.Scale);
|
|
EntriesWidth = ThemeX.row0TileSize;
|
|
EntriesHeight = ThemeX.MainEntriesSize + (int)(16.f * ThemeX.Scale);
|
|
|
|
MaxItemOnScreen = (UGAWidth - (int)((ROW0_SCROLLSIZE * 2)* ThemeX.Scale)) / (EntriesWidth + EntriesGap); //8
|
|
CountItems();
|
|
InitScroll(row0Count, Entries.size(), MaxItemOnScreen, 0);
|
|
|
|
row0PosX = EntriesWidth + EntriesGap;
|
|
row0PosX = row0PosX * ((MaxItemOnScreen < row0Count)?MaxItemOnScreen:row0Count);
|
|
row0PosX = row0PosX - EntriesGap;
|
|
row0PosX = UGAWidth - row0PosX;
|
|
row0PosX = row0PosX >> 1;
|
|
|
|
row0PosY = (int)(((float)UGAHeight - ThemeX.LayoutHeight * ThemeX.Scale) * 0.5f +
|
|
ThemeX.LayoutBannerOffset * ThemeX.Scale);
|
|
|
|
row1PosX = (UGAWidth + 8 - (ThemeX.row1TileSize + (INTN)(8.0f * ThemeX.Scale)) * row1Count) >> 1;
|
|
|
|
if (ThemeX.BootCampStyle && !(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL)) {
|
|
row1PosY = row0PosY + ThemeX.row0TileSize + (INTN)((BCSMargin * 2) * ThemeX.Scale) + ThemeX.TextHeight +
|
|
(INTN)(INDICATOR_SIZE * ThemeX.Scale) +
|
|
(INTN)((ThemeX.LayoutButtonOffset + ThemeX.TileYSpace) * ThemeX.Scale);
|
|
} else {
|
|
row1PosY = row0PosY + EntriesHeight +
|
|
(INTN)((ThemeX.TileYSpace + ThemeX.LayoutButtonOffset) * ThemeX.Scale);
|
|
}
|
|
|
|
if (row1Count > 0) {
|
|
textPosY = row1PosY + MAX(ThemeX.row1TileSize, MessageHeight) + (INTN)((ThemeX.TileYSpace + ThemeX.LayoutTextOffset) * ThemeX.Scale);
|
|
} else {
|
|
textPosY = row1PosY;
|
|
}
|
|
|
|
if (ThemeX.BootCampStyle) {
|
|
textPosY = row0PosY + ThemeX.row0TileSize + (INTN)((TEXT_YMARGIN + BCSMargin) * ThemeX.Scale);
|
|
}
|
|
|
|
FunctextPosY = row1PosY + ThemeX.row1TileSize + (INTN)((ThemeX.TileYSpace + ThemeX.LayoutTextOffset) * ThemeX.Scale);
|
|
|
|
if (!itemPosX) {
|
|
itemPosX = (__typeof__(itemPosX))AllocatePool(sizeof(UINT64) * Entries.size());
|
|
}
|
|
|
|
row0PosXRunning = row0PosX;
|
|
row1PosXRunning = row1PosX;
|
|
//DBG("EntryCount =%d\n", Entries.size());
|
|
for (INTN i = 0; i < (INTN)Entries.size(); i++) {
|
|
if (Entries[i].Row == 0) {
|
|
itemPosX[i] = row0PosXRunning;
|
|
row0PosXRunning += EntriesWidth + EntriesGap;
|
|
} else {
|
|
itemPosX[i] = row1PosXRunning;
|
|
row1PosXRunning += ThemeX.row1TileSize + (INTN)(TILE1_XSPACING * ThemeX.Scale);
|
|
//DBG("next item in row1 at x=%d\n", row1PosXRunning);
|
|
}
|
|
}
|
|
// initial painting
|
|
// ThemeX.InitSelection(); //not needed to do here
|
|
|
|
// Update FilmPlace only if not set by InitAnime
|
|
if (FilmC->FilmPlace.Width == 0 || FilmC->FilmPlace.Height == 0) {
|
|
// CopyMem(&FilmPlace, &BannerPlace, sizeof(BannerPlace));
|
|
FilmC->FilmPlace = ThemeX.BannerPlace;
|
|
}
|
|
|
|
//DBG("main menu inited\n");
|
|
break;
|
|
|
|
case MENU_FUNCTION_CLEANUP:
|
|
FreePool(itemPosX);
|
|
itemPosX = NULL;
|
|
HidePointer();
|
|
break;
|
|
|
|
case MENU_FUNCTION_PAINT_ALL:
|
|
|
|
for (INTN i = 0; i <= ScrollState.MaxIndex; i++) {
|
|
if (Entries[i].Row == 0) {
|
|
if ((i >= ScrollState.FirstVisible) && (i <= ScrollState.LastVisible)) {
|
|
DrawMainMenuEntry(&Entries[i], (i == ScrollState.CurrentSelection)?1:0,
|
|
itemPosX[i - ScrollState.FirstVisible], row0PosY);
|
|
// draw static text for the boot options, BootCampStyle
|
|
|
|
if (ThemeX.BootCampStyle && !(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL)) {
|
|
INTN textPosX = itemPosX[i - ScrollState.FirstVisible] + (ThemeX.row0TileSize / 2);
|
|
// clear the screen
|
|
|
|
ThemeX.FillRectAreaOfScreen(textPosX, textPosY, EntriesWidth + ThemeX.TileXSpace,
|
|
MessageHeight);
|
|
DrawBCSText(Entries[i].Title.data(), textPosX, textPosY, X_IS_CENTER);
|
|
}
|
|
}
|
|
} else {
|
|
DrawMainMenuEntry(&Entries[i], (i == ScrollState.CurrentSelection)?1:0,
|
|
itemPosX[i], row1PosY);
|
|
}
|
|
}
|
|
|
|
// clear the text from the second row, required by the BootCampStyle
|
|
if ((ThemeX.BootCampStyle) && (Entries[ScrollState.LastSelection].Row == 1)
|
|
&& (Entries[ScrollState.CurrentSelection].Row == 0) && !(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL)) {
|
|
ThemeX.FillRectAreaOfScreen((UGAWidth >> 1), FunctextPosY,
|
|
OldTextWidth, MessageHeight);
|
|
}
|
|
|
|
if ((Entries[ScrollState.LastSelection].Row == 0) && (Entries[ScrollState.CurrentSelection].Row == 1)
|
|
&& ThemeX.BootCampStyle && !(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL)) {
|
|
DrawMainMenuLabel(Entries[ScrollState.CurrentSelection].Title,
|
|
(UGAWidth >> 1), FunctextPosY);
|
|
}
|
|
if (!(ThemeX.BootCampStyle) && !(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL)) {
|
|
DrawMainMenuLabel(Entries[ScrollState.CurrentSelection].Title,
|
|
(UGAWidth >> 1), textPosY);
|
|
}
|
|
// DBG("draw TEXT_CORNER_HELP\n");
|
|
DrawTextCorner(TEXT_CORNER_HELP, X_IS_LEFT);
|
|
// DBG("draw TEXT_CORNER_OPTIMUS\n");
|
|
DrawTextCorner(TEXT_CORNER_OPTIMUS, X_IS_CENTER);
|
|
// DBG("draw TEXT_CORNER_REVISION\n");
|
|
DrawTextCorner(TEXT_CORNER_REVISION, X_IS_RIGHT);
|
|
// DBG("MouseBirth\n");
|
|
Status = MouseBirth();
|
|
if(EFI_ERROR(Status)) {
|
|
DBG("can't bear mouse at all! Status=%s\n", strerror(Status));
|
|
}
|
|
break;
|
|
|
|
case MENU_FUNCTION_PAINT_SELECTION:
|
|
HidePointer();
|
|
if (Entries[ScrollState.LastSelection].Row == 0) {
|
|
DrawMainMenuEntry(&Entries[ScrollState.LastSelection], FALSE,
|
|
itemPosX[ScrollState.LastSelection - ScrollState.FirstVisible], row0PosY);
|
|
} else {
|
|
DrawMainMenuEntry(&Entries[ScrollState.LastSelection], FALSE,
|
|
itemPosX[ScrollState.LastSelection], row1PosY);
|
|
}
|
|
|
|
if (Entries[ScrollState.CurrentSelection].Row == 0) {
|
|
DrawMainMenuEntry(&Entries[ScrollState.CurrentSelection], TRUE,
|
|
itemPosX[ScrollState.CurrentSelection - ScrollState.FirstVisible], row0PosY);
|
|
} else {
|
|
DrawMainMenuEntry(&Entries[ScrollState.CurrentSelection], TRUE,
|
|
itemPosX[ScrollState.CurrentSelection], row1PosY);
|
|
}
|
|
|
|
if ((ThemeX.BootCampStyle) && (!(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL))
|
|
&& Entries[ScrollState.CurrentSelection].Row == 1) {
|
|
DrawMainMenuLabel(Entries[ScrollState.CurrentSelection].Title,
|
|
(UGAWidth >> 1), FunctextPosY);
|
|
}
|
|
if ((!(ThemeX.BootCampStyle)) && (!(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL))) {
|
|
DrawMainMenuLabel(Entries[ScrollState.CurrentSelection].Title,
|
|
(UGAWidth >> 1), textPosY);
|
|
}
|
|
|
|
DrawTextCorner(TEXT_CORNER_HELP, X_IS_LEFT);
|
|
DrawTextCorner(TEXT_CORNER_OPTIMUS, X_IS_CENTER);
|
|
DrawTextCorner(TEXT_CORNER_REVISION, X_IS_RIGHT);
|
|
Status = MouseBirth();
|
|
if(EFI_ERROR(Status)) {
|
|
DBG("can't bear mouse at sel! Status=%s\n", strerror(Status));
|
|
}
|
|
break;
|
|
|
|
case MENU_FUNCTION_PAINT_TIMEOUT:
|
|
INTN hi = MessageHeight * ((ThemeX.HideBadges & HDBADGES_INLINE)?3:1);
|
|
HidePointer();
|
|
if (!(ThemeX.HideUIFlags & HIDEUI_FLAG_LABEL)){
|
|
ThemeX.FillRectAreaOfScreen((UGAWidth >> 1), FunctextPosY + hi,
|
|
OldTimeoutTextWidth, MessageHeight);
|
|
XStringW TextX;
|
|
TextX.takeValueFrom(ParamText);
|
|
OldTimeoutTextWidth = DrawTextXY(TextX, (UGAWidth >> 1), FunctextPosY + hi, X_IS_CENTER);
|
|
}
|
|
|
|
DrawTextCorner(TEXT_CORNER_HELP, X_IS_LEFT);
|
|
DrawTextCorner(TEXT_CORNER_OPTIMUS, X_IS_CENTER);
|
|
DrawTextCorner(TEXT_CORNER_REVISION, X_IS_RIGHT);
|
|
Status = MouseBirth();
|
|
if(EFI_ERROR(Status)) {
|
|
DBG("can't bear mouse at timeout! Status=%s\n", strerror(Status));
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
//
|
|
// user-callable dispatcher functions
|
|
//
|
|
|
|
UINTN REFIT_MENU_SCREEN::RunMenu(OUT REFIT_ABSTRACT_MENU_ENTRY **ChosenEntry)
|
|
{
|
|
INTN Index = -1;
|
|
|
|
if (AllowGraphicsMode)
|
|
|
|
return RunGenericMenu(&REFIT_MENU_SCREEN::GraphicsMenuStyle, &Index, ChosenEntry);
|
|
else
|
|
return RunGenericMenu(&REFIT_MENU_SCREEN::TextMenuStyle, &Index, ChosenEntry);
|
|
}
|
|
|
|
|
|
VOID REFIT_MENU_SCREEN::AddMenuCheck(CONST CHAR8 *Text, UINTN Bit, INTN ItemNum)
|
|
{
|
|
REFIT_MENU_CHECKBIT *InputBootArgs;
|
|
|
|
InputBootArgs = new REFIT_MENU_CHECKBIT;
|
|
InputBootArgs->Title.takeValueFrom(Text);
|
|
// InputBootArgs->Tag = TAG_CHECKBIT_OLD;
|
|
InputBootArgs->Row = Bit;
|
|
InputBootArgs->Item = &InputItems[ItemNum];
|
|
InputBootArgs->AtClick = ActionEnter;
|
|
InputBootArgs->AtRightClick = ActionDetails;
|
|
AddMenuEntry(InputBootArgs, true);
|
|
}
|
|
|
|
|
|
VOID REFIT_MENU_SCREEN::AddMenuItem_(REFIT_MENU_ENTRY_ITEM_ABSTRACT* InputBootArgs, INTN Inx, CONST CHAR8 *Line, BOOLEAN Cursor)
|
|
{
|
|
InputBootArgs->Title.takeValueFrom(Line);
|
|
if (Inx == 3 || Inx == 116) {
|
|
InputBootArgs->Row = 0;
|
|
} else {
|
|
InputBootArgs->Row = Cursor?StrLen(InputItems[Inx].SValue):0xFFFF;
|
|
}
|
|
InputBootArgs->Item = &InputItems[Inx];
|
|
InputBootArgs->AtClick = Cursor?ActionSelect:ActionEnter;
|
|
InputBootArgs->AtRightClick = Cursor?ActionNone:ActionDetails;
|
|
InputBootArgs->AtDoubleClick = Cursor?ActionEnter:ActionNone;
|
|
|
|
AddMenuEntry(InputBootArgs, true);
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::AddMenuItemInput(INTN Inx, CONST CHAR8 *Line, BOOLEAN Cursor)
|
|
{
|
|
REFIT_INPUT_DIALOG *InputBootArgs = new REFIT_INPUT_DIALOG;
|
|
AddMenuItem_(InputBootArgs, Inx, Line, Cursor);
|
|
}
|
|
|
|
VOID REFIT_MENU_SCREEN::AddMenuItemSwitch(INTN Inx, CONST CHAR8 *Line, BOOLEAN Cursor)
|
|
{
|
|
REFIT_MENU_SWITCH *InputBootArgs = new REFIT_MENU_SWITCH;
|
|
AddMenuItem_(InputBootArgs, Inx, Line, Cursor);
|
|
}
|
|
|
|
|
|
UINTN REFIT_MENU_SCREEN::RunMainMenu(IN INTN DefaultSelection, OUT REFIT_ABSTRACT_MENU_ENTRY **ChosenEntry)
|
|
{
|
|
|
|
MENU_STYLE_FUNC Style = &REFIT_MENU_SCREEN::TextMenuStyle;
|
|
MENU_STYLE_FUNC MainStyle = &REFIT_MENU_SCREEN::TextMenuStyle;
|
|
|
|
REFIT_ABSTRACT_MENU_ENTRY *TempChosenEntry = 0;
|
|
REFIT_ABSTRACT_MENU_ENTRY *MainChosenEntry = 0;
|
|
REFIT_ABSTRACT_MENU_ENTRY *NextChosenEntry = NULL;
|
|
UINTN MenuExit = 0, SubMenuExit = 0;
|
|
INTN DefaultEntryIndex = DefaultSelection;
|
|
INTN SubMenuIndex;
|
|
|
|
// initialize static variables when menu runs so that values from previos sessions won't be used
|
|
OldX = 0;
|
|
OldY = 0;
|
|
OldTextWidth = 0;
|
|
OldTextHeight = 0;
|
|
OldRow = 0;
|
|
OldTimeoutTextWidth = 0;
|
|
|
|
if (AllowGraphicsMode) {
|
|
Style = &REFIT_MENU_SCREEN::GraphicsMenuStyle;
|
|
if (ThemeX.VerticalLayout) {
|
|
MainStyle = &REFIT_MENU_SCREEN::MainMenuVerticalStyle;
|
|
} else {
|
|
MainStyle = &REFIT_MENU_SCREEN::MainMenuStyle;
|
|
}
|
|
}
|
|
|
|
while (!MenuExit) {
|
|
GetAnime();
|
|
DBG("AnimeRun=%d\n", (FilmC && FilmC->AnimeRun)?1:0);
|
|
MenuExit = RunGenericMenu(MainStyle, &DefaultEntryIndex, &MainChosenEntry);
|
|
TimeoutSeconds = 0;
|
|
|
|
if (MenuExit == MENU_EXIT_DETAILS && MainChosenEntry->SubScreen != NULL) {
|
|
XStringArray TmpArgs;
|
|
if (AsciiStrLen(gSettings.BootArgs) > 0) {
|
|
TmpArgs = Split<XStringArray>(gSettings.BootArgs, " ");
|
|
}
|
|
SubMenuIndex = -1;
|
|
|
|
gSettings.OptionsBits = EncodeOptions(TmpArgs);
|
|
// DBG("main OptionsBits = 0x%X\n", gSettings.OptionsBits);
|
|
|
|
if (MainChosenEntry->getLOADER_ENTRY()) {
|
|
gSettings.OptionsBits |= EncodeOptions(MainChosenEntry->getLOADER_ENTRY()->LoadOptions);
|
|
// DBG("add OptionsBits = 0x%X\n", gSettings.OptionsBits);
|
|
}
|
|
|
|
if (MainChosenEntry->getREFIT_MENU_ITEM_BOOTNUM()) {
|
|
DecodeOptions(MainChosenEntry->getREFIT_MENU_ITEM_BOOTNUM());
|
|
}
|
|
// DBG(" enter menu with LoadOptions: %ls\n", ((LOADER_ENTRY*)MainChosenEntry)->LoadOptions);
|
|
|
|
if (MainChosenEntry->getLOADER_ENTRY()) {
|
|
// Only for non-legacy entries, as LEGACY_ENTRY doesn't have Flags
|
|
gSettings.FlagsBits = MainChosenEntry->getLOADER_ENTRY()->Flags;
|
|
}
|
|
// DBG(" MainChosenEntry with FlagsBits = 0x%X\n", gSettings.FlagsBits);
|
|
|
|
SubMenuExit = 0;
|
|
while (!SubMenuExit) {
|
|
//
|
|
//running details menu
|
|
//
|
|
SubMenuExit = MainChosenEntry->SubScreen->RunGenericMenu(Style, &SubMenuIndex, &TempChosenEntry);
|
|
|
|
if (SubMenuExit == MENU_EXIT_ESCAPE || TempChosenEntry->getREFIT_MENU_ITEM_RETURN() ) {
|
|
SubMenuExit = MENU_EXIT_ENTER;
|
|
MenuExit = 0;
|
|
break;
|
|
}
|
|
|
|
if (MainChosenEntry->getREFIT_MENU_ENTRY_CLOVER()) {
|
|
MainChosenEntry->getREFIT_MENU_ENTRY_CLOVER()->LoadOptions = (((REFIT_MENU_ENTRY_CLOVER*)TempChosenEntry)->LoadOptions);
|
|
}
|
|
|
|
if (SubMenuExit == MENU_EXIT_DETAILS) {
|
|
SubMenuExit = 0;
|
|
continue;
|
|
}
|
|
// DBG(" exit menu with LoadOptions: %ls\n", ((LOADER_ENTRY*)MainChosenEntry)->LoadOptions);
|
|
|
|
if (SubMenuExit == MENU_EXIT_ENTER && MainChosenEntry->getLOADER_ENTRY() && TempChosenEntry->getLOADER_ENTRY()) {
|
|
// Only for non-legacy entries, as LEGACY_ENTRY doesn't have Flags/Options
|
|
MainChosenEntry->getLOADER_ENTRY()->Flags = TempChosenEntry->getLOADER_ENTRY()->Flags;
|
|
DBG(" get MainChosenEntry FlagsBits = 0x%X\n", ((LOADER_ENTRY*)MainChosenEntry)->Flags);
|
|
if (OSFLAG_ISUNSET(TempChosenEntry->getLOADER_ENTRY()->Flags, OSFLAG_NODEFAULTARGS)) {
|
|
DecodeOptions(TempChosenEntry->getLOADER_ENTRY());
|
|
// DBG("get OptionsBits = 0x%X\n", gSettings.OptionsBits);
|
|
// DBG(" TempChosenEntry FlagsBits = 0x%X\n", ((LOADER_ENTRY*)TempChosenEntry)->Flags);
|
|
}
|
|
// copy also loadoptions from subentry to mainentry
|
|
MainChosenEntry->getLOADER_ENTRY()->LoadOptions = TempChosenEntry->getLOADER_ENTRY()->LoadOptions;
|
|
}
|
|
|
|
if (/*MenuExit == MENU_EXIT_ENTER &&*/ TempChosenEntry->getLOADER_ENTRY()) {
|
|
if (TempChosenEntry->getLOADER_ENTRY()->LoadOptions.notEmpty()) {
|
|
snprintf(gSettings.BootArgs, 255, "%s", TempChosenEntry->getLOADER_ENTRY()->LoadOptions.ConcatAll(" "_XS8).c_str());
|
|
} else {
|
|
ZeroMem(&gSettings.BootArgs, 255);
|
|
}
|
|
DBG(" boot with args: %s\n", gSettings.BootArgs);
|
|
}
|
|
|
|
//---- Details submenu (kexts disabling etc)
|
|
if (SubMenuExit == MENU_EXIT_ENTER /*|| MenuExit == MENU_EXIT_DETAILS*/) {
|
|
if (TempChosenEntry->SubScreen != NULL) {
|
|
UINTN NextMenuExit = 0;
|
|
INTN NextEntryIndex = -1;
|
|
while (!NextMenuExit) {
|
|
//
|
|
// running submenu
|
|
//
|
|
NextMenuExit = TempChosenEntry->SubScreen->RunGenericMenu(Style, &NextEntryIndex, &NextChosenEntry);
|
|
if (NextMenuExit == MENU_EXIT_ESCAPE || NextChosenEntry->getREFIT_MENU_ITEM_RETURN() ) {
|
|
SubMenuExit = 0;
|
|
NextMenuExit = MENU_EXIT_ENTER;
|
|
break;
|
|
}
|
|
DBG(" get NextChosenEntry FlagsBits = 0x%X\n", ((LOADER_ENTRY*)NextChosenEntry)->Flags);
|
|
//---- Details submenu (kexts disabling etc) second level
|
|
if (NextMenuExit == MENU_EXIT_ENTER /*|| MenuExit == MENU_EXIT_DETAILS*/) {
|
|
if (NextChosenEntry->SubScreen != NULL) {
|
|
UINTN DeepMenuExit = 0;
|
|
INTN DeepEntryIndex = -1;
|
|
REFIT_ABSTRACT_MENU_ENTRY *DeepChosenEntry = NULL;
|
|
while (!DeepMenuExit) {
|
|
//
|
|
// run deep submenu
|
|
//
|
|
DeepMenuExit = NextChosenEntry->SubScreen->RunGenericMenu(Style, &DeepEntryIndex, &DeepChosenEntry);
|
|
if (DeepMenuExit == MENU_EXIT_ESCAPE || DeepChosenEntry->getREFIT_MENU_ITEM_RETURN() ) {
|
|
DeepMenuExit = MENU_EXIT_ENTER;
|
|
NextMenuExit = 0;
|
|
break;
|
|
}
|
|
DBG(" get DeepChosenEntry FlagsBits = 0x%X\n", ((LOADER_ENTRY*)DeepChosenEntry)->Flags);
|
|
} //while(!DeepMenuExit)
|
|
}
|
|
}
|
|
|
|
} //while(!NextMenuExit)
|
|
}
|
|
}
|
|
//---------
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ChosenEntry) {
|
|
*ChosenEntry = MainChosenEntry;
|
|
}
|
|
return MenuExit;
|
|
}
|
|
|
|
|
|
EFI_STATUS REFIT_MENU_SCREEN::CheckMouseEvent()
|
|
{
|
|
EFI_STATUS Status = EFI_TIMEOUT;
|
|
mAction = ActionNone;
|
|
MOUSE_EVENT Event = mPointer.GetEvent();
|
|
bool Move = false;
|
|
|
|
if (!IsDragging && Event == MouseMove)
|
|
Event = NoEvents;
|
|
|
|
if (ScrollEnabled){
|
|
if (mPointer.MouseInRect(&UpButton) && Event == LeftClick)
|
|
mAction = ActionScrollUp;
|
|
else if (mPointer.MouseInRect(&DownButton) && Event == LeftClick)
|
|
mAction = ActionScrollDown;
|
|
else if (mPointer.MouseInRect(&Scrollbar) && Event == LeftMouseDown) {
|
|
IsDragging = TRUE;
|
|
Move = true;
|
|
// mAction = ActionMoveScrollbar;
|
|
ScrollbarYMovement = 0;
|
|
ScrollbarOldPointerPlace.XPos = ScrollbarNewPointerPlace.XPos = mPointer.GetPlace().XPos;
|
|
ScrollbarOldPointerPlace.YPos = ScrollbarNewPointerPlace.YPos = mPointer.GetPlace().YPos;
|
|
}
|
|
else if (IsDragging && Event == LeftClick) {
|
|
IsDragging = FALSE;
|
|
Move = true;
|
|
// mAction = ActionMoveScrollbar;
|
|
}
|
|
else if (IsDragging && Event == MouseMove) {
|
|
mAction = ActionMoveScrollbar;
|
|
ScrollbarNewPointerPlace.XPos = mPointer.GetPlace().XPos;
|
|
ScrollbarNewPointerPlace.YPos = mPointer.GetPlace().YPos;
|
|
}
|
|
else if (mPointer.MouseInRect(&ScrollbarBackground) &&
|
|
Event == LeftClick) {
|
|
if (mPointer.GetPlace().YPos < Scrollbar.YPos) // up
|
|
mAction = ActionPageUp;
|
|
else // down
|
|
mAction = ActionPageDown;
|
|
// page up/down, like in OS X
|
|
}
|
|
else if (Event == ScrollDown) {
|
|
mAction = ActionScrollDown;
|
|
}
|
|
else if (Event == ScrollUp) {
|
|
mAction = ActionScrollUp;
|
|
}
|
|
}
|
|
if (!ScrollEnabled || (mAction == ActionNone && !Move) ) {
|
|
for (UINTN EntryId = 0; EntryId < Entries.size(); EntryId++) {
|
|
if (mPointer.MouseInRect(&(Entries[EntryId].Place))) {
|
|
switch (Event) {
|
|
case LeftClick:
|
|
mAction = Entries[EntryId].AtClick;
|
|
// DBG("Click\n");
|
|
break;
|
|
case RightClick:
|
|
mAction = Entries[EntryId].AtRightClick;
|
|
break;
|
|
case DoubleClick:
|
|
mAction = Entries[EntryId].AtDoubleClick;
|
|
break;
|
|
case ScrollDown:
|
|
mAction = ActionScrollDown;
|
|
break;
|
|
case ScrollUp:
|
|
mAction = ActionScrollUp;
|
|
break;
|
|
case MouseMove:
|
|
mAction = Entries[EntryId].AtMouseOver;
|
|
//how to do the action once?
|
|
break;
|
|
default:
|
|
mAction = ActionNone;
|
|
break;
|
|
}
|
|
mItemID = EntryId;
|
|
break;
|
|
}
|
|
else { //click in milk
|
|
switch (Event) {
|
|
case LeftClick:
|
|
mAction = ActionDeselect;
|
|
break;
|
|
case RightClick:
|
|
mAction = ActionFinish;
|
|
break;
|
|
case ScrollDown:
|
|
mAction = ActionScrollDown;
|
|
break;
|
|
case ScrollUp:
|
|
mAction = ActionScrollUp;
|
|
break;
|
|
default:
|
|
mAction = ActionNone;
|
|
break;
|
|
}
|
|
mItemID = 0xFFFF;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (mAction != ActionNone) {
|
|
Status = EFI_SUCCESS;
|
|
// Event = NoEvents; //clear event as set action
|
|
mPointer.ClearEvent();
|
|
}
|
|
return Status;
|
|
}
|