Mainmenu: Avoid the header being displayed behind the formspec (#13924)

This change keeps the current header placement code, but adds additional code to make sure the header doesn't end up behind the formspec.
This commit is contained in:
grorp 2023-11-25 17:04:33 +01:00 committed by GitHub
parent 6783734612
commit 4255ac3022
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 10 deletions

@ -283,11 +283,16 @@ void GUIEngine::run()
else else
drawBackground(driver); drawBackground(driver);
drawHeader(driver);
drawFooter(driver); drawFooter(driver);
m_rendering_engine->get_gui_env()->drawAll(); m_rendering_engine->get_gui_env()->drawAll();
// The header *must* be drawn after the menu because it uses
// GUIFormspecMenu::getAbsoluteRect().
// The header *can* be drawn after the menu because it never intersects
// the menu.
drawHeader(driver);
driver->endScene(); driver->endScene();
IrrlichtDevice *device = m_rendering_engine->get_raw_device(); IrrlichtDevice *device = m_rendering_engine->get_raw_device();
@ -478,29 +483,56 @@ void GUIEngine::drawHeader(video::IVideoDriver *driver)
video::ITexture* texture = m_textures[TEX_LAYER_HEADER].texture; video::ITexture* texture = m_textures[TEX_LAYER_HEADER].texture;
/* If no texture, draw nothing */ // If no texture, draw nothing
if(!texture) if (!texture)
return; return;
/*
* Calculate the maximum rectangle
*/
core::rect<s32> formspec_rect = m_menu->getAbsoluteRect();
// 4 px of padding on each side
core::rect<s32> max_rect(4, 4, screensize.Width - 8, formspec_rect.UpperLeftCorner.Y - 8);
// If no space (less than 16x16 px), draw nothing
if (max_rect.getWidth() < 16 || max_rect.getHeight() < 16)
return;
/*
* Calculate the preferred rectangle
*/
f32 mult = (((f32)screensize.Width / 2.0)) / f32 mult = (((f32)screensize.Width / 2.0)) /
((f32)texture->getOriginalSize().Width); ((f32)texture->getOriginalSize().Width);
v2s32 splashsize(((f32)texture->getOriginalSize().Width) * mult, v2s32 splashsize(((f32)texture->getOriginalSize().Width) * mult,
((f32)texture->getOriginalSize().Height) * mult); ((f32)texture->getOriginalSize().Height) * mult);
// Don't draw the header if there isn't enough room
s32 free_space = (((s32)screensize.Height)-320)/2; s32 free_space = (((s32)screensize.Height)-320)/2;
if (free_space > splashsize.Y) { core::rect<s32> desired_rect(0, 0, splashsize.X, splashsize.Y);
core::rect<s32> splashrect(0, 0, splashsize.X, splashsize.Y); desired_rect += v2s32((screensize.Width/2)-(splashsize.X/2),
splashrect += v2s32((screensize.Width/2)-(splashsize.X/2),
((free_space/2)-splashsize.Y/2)+10); ((free_space/2)-splashsize.Y/2)+10);
draw2DImageFilterScaled(driver, texture, splashrect, /*
* Make the preferred rectangle fit into the maximum rectangle
*/
// 1. Scale
f32 scale = std::min((f32)max_rect.getWidth() / (f32)desired_rect.getWidth(),
(f32)max_rect.getHeight() / (f32)desired_rect.getHeight());
if (scale < 1.0f) {
v2s32 old_center = desired_rect.getCenter();
desired_rect.LowerRightCorner.X = desired_rect.UpperLeftCorner.X + desired_rect.getWidth() * scale;
desired_rect.LowerRightCorner.Y = desired_rect.UpperLeftCorner.Y + desired_rect.getHeight() * scale;
desired_rect += old_center - desired_rect.getCenter();
}
// 2. Move
desired_rect.constrainTo(max_rect);
draw2DImageFilterScaled(driver, texture, desired_rect,
core::rect<s32>(core::position2d<s32>(0,0), core::rect<s32>(core::position2d<s32>(0,0),
core::dimension2di(texture->getOriginalSize())), core::dimension2di(texture->getOriginalSize())),
NULL, NULL, true); NULL, NULL, true);
}
} }
/******************************************************************************/ /******************************************************************************/

@ -247,6 +247,14 @@ std::vector<std::string>* GUIFormSpecMenu::getDropDownValues(const std::string &
return NULL; return NULL;
} }
// This will only return a meaningful value if called after drawMenu().
core::rect<s32> GUIFormSpecMenu::getAbsoluteRect()
{
core::rect<s32> rect = AbsoluteRect;
rect.UpperLeftCorner.Y += m_tabheader_upper_edge;
return rect;
}
v2s32 GUIFormSpecMenu::getElementBasePos(const std::vector<std::string> *v_pos) v2s32 GUIFormSpecMenu::getElementBasePos(const std::vector<std::string> *v_pos)
{ {
v2f32 pos_f = v2f32(padding.X, padding.Y) + pos_offset * spacing; v2f32 pos_f = v2f32(padding.X, padding.Y) + pos_offset * spacing;
@ -2104,6 +2112,7 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen
e->setActiveTab(tab_index); e->setActiveTab(tab_index);
m_fields.push_back(spec); m_fields.push_back(spec);
m_tabheader_upper_edge = MYMIN(m_tabheader_upper_edge, rect.UpperLeftCorner.Y);
} }
void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &element) void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &element)
@ -3105,6 +3114,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
m_formspec_version = 1; m_formspec_version = 1;
m_bgcolor = video::SColor(140, 0, 0, 0); m_bgcolor = video::SColor(140, 0, 0, 0);
m_tabheader_upper_edge = 0;
{ {
v3f formspec_bgcolor = g_settings->getV3F("formspec_fullscreen_bg_color"); v3f formspec_bgcolor = g_settings->getV3F("formspec_fullscreen_bg_color");

@ -282,6 +282,9 @@ public:
GUITable* getTable(const std::string &tablename); GUITable* getTable(const std::string &tablename);
std::vector<std::string>* getDropDownValues(const std::string &name); std::vector<std::string>* getDropDownValues(const std::string &name);
// This will only return a meaningful value if called after drawMenu().
core::rect<s32> getAbsoluteRect();
#ifdef __ANDROID__ #ifdef __ANDROID__
bool getAndroidUIInput(); bool getAndroidUIInput();
#endif #endif
@ -499,6 +502,9 @@ private:
int m_btn_height; int m_btn_height;
gui::IGUIFont *m_font = nullptr; gui::IGUIFont *m_font = nullptr;
// used by getAbsoluteRect
s32 m_tabheader_upper_edge = 0;
}; };
class FormspecFormSource: public IFormSource class FormspecFormSource: public IFormSource