mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-29 12:35:53 +01:00
42cece9885
Move global variable textfaces in XTheme. Move global variable fontsDB in XTheme. Remove XTheme member SVGParser. SVGParser is deleted just after use. Remove XTheme members ImageSVG and ImageSVGnight. All images are rasterized at load, so no need to keep that. Remove XIcon setFilled because XIcon knows if it's filled or not by checking Image & ImageNight
879 lines
34 KiB
C++
879 lines
34 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 "./REFIT_MAINMENU_SCREEN.h"
|
|
#include <Platform.h>
|
|
#include "../Platform/BasicIO.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 "../Platform/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"
|
|
#include "../Platform/Events.h"
|
|
#include "../Settings/Self.h"
|
|
#include "../Platform/Volumes.h"
|
|
#include "../include/OSFlags.h"
|
|
#include "../Platform/CloverVersion.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
|
|
|
|
INTN row0PosXRunning;
|
|
INTN row1PosXRunning;
|
|
INTN *itemPosX = NULL;
|
|
INTN *itemPosY = NULL;
|
|
INTN row1PosY, textPosY, FunctextPosY;
|
|
INTN OldTimeoutTextWidth = 0;
|
|
INTN EntriesWidth, EntriesHeight, EntriesGap;
|
|
INTN MaxItemOnScreen = -1;
|
|
|
|
|
|
REFIT_MAINMENU_SCREEN::REFIT_MAINMENU_SCREEN(UINTN ID, XStringW TTitle, XStringW TTimeoutText) : REFIT_MENU_SCREEN(ID, TTitle, TTimeoutText)
|
|
{
|
|
};
|
|
|
|
/**
|
|
* Draw entries for GUI.
|
|
*/
|
|
|
|
void REFIT_MAINMENU_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);
|
|
const XImage& CurrSel = Entries[ScrollState.CurrentSelection].Image.GetBest(!Daylight);
|
|
Back.Compose(0, 0, CurrSel, false, BadgeDim/128.f);
|
|
Back.DrawOnBack(X, Y, Back);
|
|
}
|
|
|
|
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) && (gSettings.GUI.ShowOptimus == false))
|
|
) {
|
|
return;
|
|
}
|
|
|
|
switch (TextC) {
|
|
case TEXT_CORNER_REVISION:
|
|
// Display Clover boot volume
|
|
if (SelfVolume->VolLabel.notEmpty() && SelfVolume->VolLabel[0] != L'#') {
|
|
Text = SWPrintf("%ls, booted from %ls %ls", gFirmwareRevision, SelfVolume->VolLabel.wc_str(), self.getCloverDirFullPath().wc_str());
|
|
}
|
|
if (Text.isEmpty()) {
|
|
Text = SWPrintf("%ls %ls", gFirmwareRevision, /*SelfVolume->VolName.wc_str(),*/ self.getCloverDirFullPath().wc_str());
|
|
}
|
|
break;
|
|
case TEXT_CORNER_HELP:
|
|
Text = L"F1:Help"_XSW;
|
|
break;
|
|
case TEXT_CORNER_OPTIMUS:
|
|
if (gConf.GfxPropertiesArray.size() > 0 && gConf.GfxPropertiesArray[0].Vendor != Intel) {
|
|
Text = L"Discrete"_XSW;
|
|
} else {
|
|
Text = L"Intel"_XSW;
|
|
}
|
|
// Text = (gConf.GfxPropertiesArray.size() == 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_MAINMENU_SCREEN::DrawMainMenuEntry(REFIT_ABSTRACT_MENU_ENTRY *Entry, XBool 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 (!ThemeX->IsEmbeddedTheme()) {
|
|
MainIcon = ThemeX->GetIcon("os_mac"_XS8);
|
|
}
|
|
if (MainIcon.Image.isEmpty()) {
|
|
MainIcon.Image.DummyImage(MainSize);
|
|
}
|
|
}
|
|
|
|
// const XImage& MainImage = (!ThemeX->Daylight && !MainIcon.ImageNight.isEmpty())? MainIcon.ImageNight : MainIcon.Image;
|
|
const XImage& MainImage = MainIcon.GetBest(!Daylight);
|
|
|
|
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();
|
|
|
|
// 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;
|
|
const XImage& BadgeImage = BadgeIcon->GetBest(!Daylight);
|
|
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(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);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Main screen text.
|
|
*/
|
|
void REFIT_MAINMENU_SCREEN::MainMenuStyle(IN UINTN Function, IN CONST CHAR16 *ParamText)
|
|
{
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
// INTN i = 0;
|
|
INTN MessageHeight = 0;
|
|
// clovy
|
|
if (ThemeX->TypeSVG && ThemeX->getTextFace(1).valid) {
|
|
MessageHeight = (INTN)(ThemeX->getTextFace(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)?true:false,
|
|
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.wc_str(), textPosX, textPosY, X_IS_CENTER);
|
|
}
|
|
}
|
|
} else {
|
|
DrawMainMenuEntry(&Entries[i], (i == ScrollState.CurrentSelection)?true:false,
|
|
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", efiStrError(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", efiStrError(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", efiStrError(Status));
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
void REFIT_MAINMENU_SCREEN::MainMenuVerticalStyle(IN UINTN Function, IN CONST CHAR16 *ParamText)
|
|
{
|
|
// INTN i;
|
|
// INTN row0PosYRunning;
|
|
// INTN VisibleHeight = 0; //assume vertical layout
|
|
|
|
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);
|
|
//
|
|
INTN VisibleHeight = (UGAHeight - EntriesPosY - (int)(LAYOUT_Y_EDGE * ThemeX->Scale) + EntriesGap) / (EntriesHeight + EntriesGap);
|
|
EntriesPosX = UGAWidth - EntriesWidth - (int)((BAR_WIDTH + LAYOUT_X_EDGE) * ThemeX->Scale);
|
|
INTN MessageHeight = 20;
|
|
if (ThemeX->TypeSVG && ThemeX->getTextFace(1).valid) {
|
|
MessageHeight = (INTN)(ThemeX->getTextFace(1).size * RowHeightFromTextHeight * ThemeX->Scale);
|
|
} else {
|
|
MessageHeight = (INTN)(ThemeX->TextHeight * RowHeightFromTextHeight * 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());
|
|
}
|
|
INTN 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)?true:false,
|
|
itemPosX[i - ScrollState.FirstVisible], itemPosY[i - ScrollState.FirstVisible]);
|
|
}
|
|
} else { //row1
|
|
DrawMainMenuEntry(&Entries[i], (i == ScrollState.CurrentSelection)?true:false,
|
|
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 MessageHeight = 20;
|
|
if (ThemeX->TypeSVG && ThemeX->getTextFace(1).valid) {
|
|
MessageHeight = (INTN)(ThemeX->getTextFace(1).size * RowHeightFromTextHeight * ThemeX->Scale);
|
|
} else {
|
|
MessageHeight = (INTN)(ThemeX->TextHeight * RowHeightFromTextHeight * ThemeX->Scale);
|
|
}
|
|
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;
|
|
|
|
}
|
|
}
|
|
|
|
UINTN REFIT_MAINMENU_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) {
|
|
// m_MainStyle = &REFIT_MAINMENU_SCREEN::MainMenuVerticalStyle;
|
|
// } else {
|
|
// m_MainStyle = &REFIT_MAINMENU_SCREEN::MainMenuStyle;
|
|
// }
|
|
// }else{
|
|
// m_MainStyle = &REFIT_MAINMENU_SCREEN::TextMenuStyle;
|
|
// }
|
|
|
|
while (!MenuExit) {
|
|
GetAnime();
|
|
// DBG("AnimeRun=%d\n", (FilmC && FilmC->AnimeRun)?1:0);
|
|
MenuExit = RunGenericMenu(&DefaultEntryIndex, &MainChosenEntry);
|
|
TimeoutSeconds = 0;
|
|
|
|
if (MenuExit == MENU_EXIT_DETAILS && MainChosenEntry->SubScreen != NULL) {
|
|
if ( MainChosenEntry->SubScreen->Entries.size() > 0 ) { // if MainChosenEntry->SubScreen->Entries.size() == 0, we got a crash in GraphicsMenuStyle
|
|
XString8Array TmpArgs;
|
|
if ( gSettings.Boot.BootArgs.length() > 0) {
|
|
TmpArgs = Split<XString8Array>(gSettings.Boot.BootArgs, " ");
|
|
}
|
|
SubMenuIndex = -1;
|
|
|
|
GlobalConfig.OptionsBits = EncodeOptions(TmpArgs);
|
|
// DBG("main OptionsBits = 0x%X\n", GlobalConfig.OptionsBits);
|
|
|
|
if (MainChosenEntry->getLOADER_ENTRY()) {
|
|
GlobalConfig.OptionsBits |= EncodeOptions(MainChosenEntry->getLOADER_ENTRY()->LoadOptions);
|
|
// DBG("add OptionsBits = 0x%X\n", GlobalConfig.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
|
|
GlobalConfig.FlagsBits = MainChosenEntry->getLOADER_ENTRY()->Flags;
|
|
}
|
|
// DBG(" MainChosenEntry with FlagsBits = 0x%X\n", GlobalConfig.FlagsBits);
|
|
|
|
SubMenuExit = 0;
|
|
while (!SubMenuExit) {
|
|
//
|
|
//running details menu
|
|
//
|
|
SubMenuExit = MainChosenEntry->SubScreen->RunGenericMenu(&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()) {
|
|
DBG("menu entry Clover\n");
|
|
MainChosenEntry->getREFIT_MENU_ENTRY_CLOVER()->LoadOptions = (((REFIT_MENU_ENTRY_CLOVER*)TempChosenEntry)->LoadOptions);
|
|
break;
|
|
}
|
|
|
|
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", GlobalConfig.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()) {
|
|
gSettings.Boot.BootArgs = TempChosenEntry->getLOADER_ENTRY()->LoadOptions.ConcatAll(" "_XS8);
|
|
} else {
|
|
gSettings.Boot.BootArgs.setEmpty();
|
|
}
|
|
// DBG(" boot with args: %s\n", gSettings.Boot.BootArgs.c_str());
|
|
}
|
|
|
|
//---- 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(&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(&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)
|
|
}
|
|
}
|
|
//---------
|
|
}
|
|
}else{
|
|
// Here, it means MainChosenEntry->SubScreen != null, but MainChosenEntry->SubScreen->Entries.size() == 0.
|
|
// This is a technical bug. GraphicsMenuStyle would crash.
|
|
#ifdef JIEF_DEBUG
|
|
panic("A sub menu doesn't have any entries");
|
|
#else
|
|
MenuExit = 0; // loop on main menu
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ChosenEntry) {
|
|
*ChosenEntry = MainChosenEntry;
|
|
}
|
|
return MenuExit;
|
|
}
|
|
|