Add resizing of GUIEngine (only works with some screen)

This commit is contained in:
Benau 2020-06-04 15:49:34 +08:00
parent d7695cb0a7
commit da1d41bf85
12 changed files with 139 additions and 13 deletions

@ -633,6 +633,11 @@ video::IVideoModeList* CIrrDeviceSDL::getVideoModeList()
//! Sets if the window should be resizable in windowed mode. //! Sets if the window should be resizable in windowed mode.
void CIrrDeviceSDL::setResizable(bool resize) void CIrrDeviceSDL::setResizable(bool resize)
{ {
#if SDL_VERSION_ATLEAST(2, 0, 5)
if (CreationParams.Fullscreen)
return;
SDL_SetWindowResizable(Window, resize ? SDL_TRUE : SDL_FALSE);
#endif
} }

@ -82,6 +82,7 @@ FontWithFace::~FontWithFace()
*/ */
void FontWithFace::init() void FontWithFace::init()
{ {
m_glyph_max_height = 0;
setDPI(); setDPI();
#ifndef SERVER_ONLY #ifndef SERVER_ONLY
if (GUIEngine::isNoGraphics()) if (GUIEngine::isNoGraphics())

@ -20,7 +20,10 @@
#include "challenges/story_mode_timer.hpp" #include "challenges/story_mode_timer.hpp"
#include "config/player_manager.hpp" #include "config/player_manager.hpp"
#include "config/user_config.hpp" #include "config/user_config.hpp"
#include "font/bold_face.hpp"
#include "font/digit_face.hpp"
#include "font/font_manager.hpp" #include "font/font_manager.hpp"
#include "font/regular_face.hpp"
#include "graphics/2dutils.hpp" #include "graphics/2dutils.hpp"
#include "graphics/b3d_mesh_loader.hpp" #include "graphics/b3d_mesh_loader.hpp"
#include "graphics/camera.hpp" #include "graphics/camera.hpp"
@ -54,6 +57,8 @@
#include "guiengine/modaldialog.hpp" #include "guiengine/modaldialog.hpp"
#include "guiengine/scalable_font.hpp" #include "guiengine/scalable_font.hpp"
#include "guiengine/screen.hpp" #include "guiengine/screen.hpp"
#include "guiengine/screen_keyboard.hpp"
#include "guiengine/skin.hpp"
#include "io/file_manager.hpp" #include "io/file_manager.hpp"
#include "items/item_manager.hpp" #include "items/item_manager.hpp"
#include "items/powerup_manager.hpp" #include "items/powerup_manager.hpp"
@ -1982,6 +1987,24 @@ void IrrDriver::doScreenShot()
image->drop(); image->drop();
} // doScreenShot } // doScreenShot
// ----------------------------------------------------------------------------
void IrrDriver::handleWindowResize()
{
if (m_actual_screen_size != m_video_driver->getCurrentRenderTargetSize())
{
// Don't update when dialog is opened
if (GUIEngine::ModalDialog::isADialogActive() ||
GUIEngine::ScreenKeyboard::isActive() ||
StateManager::get()->getGameState() != GUIEngine::MENU)
return;
m_actual_screen_size = m_video_driver->getCurrentRenderTargetSize();
UserConfigParams::m_width = m_actual_screen_size.Width;
UserConfigParams::m_height = m_actual_screen_size.Height;
resizeWindow();
}
} // handleWindowResize
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Update, called once per frame. /** Update, called once per frame.
* \param dt Time since last update * \param dt Time since last update
@ -1990,18 +2013,23 @@ void IrrDriver::doScreenShot()
*/ */
void IrrDriver::update(float dt, bool is_loading) void IrrDriver::update(float dt, bool is_loading)
{ {
bool show_dialog_yes = m_resolution_changing == RES_CHANGE_YES;
bool show_dialog_warn = m_resolution_changing == RES_CHANGE_YES_WARN;
// If the resolution should be switched, do it now. This will delete the // If the resolution should be switched, do it now. This will delete the
// old device and create a new one. // old device and create a new one.
if (m_resolution_changing!=RES_CHANGE_NONE) if (m_resolution_changing!=RES_CHANGE_NONE)
{ {
applyResolutionSettings(m_resolution_changing != RES_CHANGE_SAME); applyResolutionSettings(m_resolution_changing != RES_CHANGE_SAME);
if(m_resolution_changing==RES_CHANGE_YES)
new ConfirmResolutionDialog(false);
else if(m_resolution_changing==RES_CHANGE_YES_WARN)
new ConfirmResolutionDialog(true);
m_resolution_changing = RES_CHANGE_NONE; m_resolution_changing = RES_CHANGE_NONE;
} }
handleWindowResize();
if (show_dialog_yes)
new ConfirmResolutionDialog(false);
else if (show_dialog_warn)
new ConfirmResolutionDialog(true);
m_wind->update(); m_wind->update();
PropertyAnimator::get()->update(dt); PropertyAnimator::get()->update(dt);
@ -2301,3 +2329,35 @@ void IrrDriver::resetDebugModes()
SP::sp_debug_view = false; SP::sp_debug_view = false;
#endif #endif
} }
// ----------------------------------------------------------------------------
void IrrDriver::resizeWindow()
{
// Reload fonts
font_manager->getFont<BoldFace>()->init();
font_manager->getFont<DigitFace>()->init();
font_manager->getFont<RegularFace>()->init();
// Reload GUIEngine
GUIEngine::reloadForNewSize();
#ifdef ENABLE_RECORDER
ogrDestroy();
RecorderConfig cfg;
cfg.m_triple_buffering = 1;
cfg.m_record_audio = 1;
cfg.m_width = m_actual_screen_size.Width;
cfg.m_height = m_actual_screen_size.Height;
int vf = UserConfigParams::m_video_format;
cfg.m_video_format = (VideoFormat)vf;
cfg.m_audio_format = OGR_AF_VORBIS;
cfg.m_audio_bitrate = UserConfigParams::m_audio_bitrate;
cfg.m_video_bitrate = UserConfigParams::m_video_bitrate;
cfg.m_record_fps = UserConfigParams::m_record_fps;
cfg.m_record_jpg_quality = UserConfigParams::m_recorder_jpg_quality;
if (ogrInitConfig(&cfg) == 0)
{
Log::error("irr_driver",
"RecorderConfig is invalid, use the default one.");
}
#endif
}

@ -194,7 +194,8 @@ private:
/** Used to visualise skeletons. */ /** Used to visualise skeletons. */
std::vector<irr::scene::IAnimatedMeshSceneNode*> m_debug_meshes; std::vector<irr::scene::IAnimatedMeshSceneNode*> m_debug_meshes;
#endif #endif
// ------------------------------------------------------------------------
void resizeWindow();
public: public:
void doScreenShot(); void doScreenShot();
public: public:
@ -534,6 +535,8 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
u32 getDefaultFramebuffer() const u32 getDefaultFramebuffer() const
{ return m_video_driver->getDefaultFramebuffer(); } { return m_video_driver->getDefaultFramebuffer(); }
// ------------------------------------------------------------------------
void handleWindowResize();
}; // IrrDriver }; // IrrDriver
extern IrrDriver *irr_driver; extern IrrDriver *irr_driver;

@ -295,7 +295,8 @@ void AbstractStateManager::resetAndSetStack(Screen* screens[])
assert(!ModalDialog::isADialogActive()); assert(!ModalDialog::isADialogActive());
assert(!ScreenKeyboard::isActive()); assert(!ScreenKeyboard::isActive());
if (m_game_mode != GAME) getCurrentScreen()->tearDown(); if (m_game_mode != GAME && getCurrentScreen())
getCurrentScreen()->tearDown();
m_menu_stack.clear(); m_menu_stack.clear();
for (int n=0; screens[n] != NULL; n++) for (int n=0; screens[n] != NULL; n++)
@ -311,3 +312,21 @@ void AbstractStateManager::resetAndSetStack(Screen* screens[])
onTopMostScreenChanged(); onTopMostScreenChanged();
} // resetAndSetStack } // resetAndSetStack
// ----------------------------------------------------------------------------
void AbstractStateManager::onResize()
{
// Happens in the first resize in main.cpp
if (m_menu_stack.empty())
return;
std::vector<std::function<Screen*()> > screen_function;
for (auto& p : m_menu_stack)
screen_function.push_back(p.second->getNewScreenPointer());
clearScreenCache();
std::vector<Screen*> new_screen;
for (auto& screen : screen_function)
new_screen.push_back(screen());
new_screen.push_back(NULL);
resetAndSetStack(new_screen.data());
} // onResize

@ -110,6 +110,11 @@ namespace GUIEngine
*/ */
void resetAndSetStack(Screen* screens[]); void resetAndSetStack(Screen* screens[]);
/**
* \brief Called when resizing of stk window
*/
void onResize();
/** /**
* \brief Used in no graphics STK to enter menu screen (when server is * \brief Used in no graphics STK to enter menu screen (when server is
* idle state) * idle state)

@ -1176,6 +1176,18 @@ namespace GUIEngine
assert(g_skin->getReferenceCount() == 1); assert(g_skin->getReferenceCount() == 1);
} // reloadSkin } // reloadSkin
// -----------------------------------------------------------------------
void reloadForNewSize()
{
g_skin->resetBackgroundImage();
Private::font_height = g_font->getDimension( L"X" ).Height;
Private::large_font_height = g_large_font->getDimension( L"X" ).Height;
Private::small_font_height = g_small_font->getDimension( L"X" ).Height;
Private::title_font_height =
g_title_font->getDimension( L"X" ).Height;
StateManager::get()->onResize();
} // reloadForNewSize
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
void addGUIFunctionBeforeRendering(std::function<void()> func) void addGUIFunctionBeforeRendering(std::function<void()> func)
{ {

@ -257,6 +257,11 @@ namespace GUIEngine
*/ */
void reloadSkin(); void reloadSkin();
/**
* \brief call when screen size changed
*/
void reloadForNewSize();
/** /**
* \brief Add gui-related function before rendering GUI (from other thread) * \brief Add gui-related function before rendering GUI (from other thread)
*/ */

@ -102,8 +102,9 @@ protected:
/** A pointer to the Container for the Message */ /** A pointer to the Container for the Message */
SkinWidgetContainer* m_container; SkinWidgetContainer* m_container;
/** Font used to detect if re-initialization is needed */ /** Font and screen size used to detect if re-initialization is needed */
gui::IGUIFont* m_font; gui::IGUIFont* m_font;
core::dimension2du m_screen_size;
public: public:
TextMessage(MessageQueue::MessageType mt, const core::stringw &message) : TextMessage(MessageQueue::MessageType mt, const core::stringw &message) :
Message(5.0f, message) Message(5.0f, message)
@ -135,8 +136,9 @@ public:
{ {
const GUIEngine::BoxRenderParams &brp = const GUIEngine::BoxRenderParams &brp =
GUIEngine::getSkin()->getBoxRenderParams(m_render_type); GUIEngine::getSkin()->getBoxRenderParams(m_render_type);
const unsigned width = irr_driver->getActualScreenSize().Width; m_screen_size = irr_driver->getActualScreenSize();
const unsigned height = irr_driver->getActualScreenSize().Height; const unsigned width = m_screen_size.Width;
const unsigned height = m_screen_size.Height;
m_font = GUIEngine::getFont(); m_font = GUIEngine::getFont();
m_font->initGlyphLayouts(m_message, m_gls); m_font->initGlyphLayouts(m_message, m_gls);
// Reserve space for 3 lines of text, it will occupy the circle // Reserve space for 3 lines of text, it will occupy the circle
@ -204,7 +206,8 @@ public:
Message::draw(dt); Message::draw(dt);
// This happen when GUIEngine is reset (when font size changed for // This happen when GUIEngine is reset (when font size changed for
// example) // example)
if (m_font != GUIEngine::getFont()) if (m_font != GUIEngine::getFont() ||
m_screen_size != irr_driver->getActualScreenSize())
init(); init();
int pos_transform = 0; int pos_transform = 0;
if (m_container == g_container.get()) if (m_container == g_container.get())

@ -39,9 +39,10 @@ using namespace irr;
#include "guiengine/event_handler.hpp" #include "guiengine/event_handler.hpp"
#include "guiengine/widget.hpp" #include "guiengine/widget.hpp"
#include "input/input.hpp" #include "input/input.hpp"
#include "utils/leak_check.hpp"
#include "utils/ptr_vector.hpp" #include "utils/ptr_vector.hpp"
#include "utils/leak_check.hpp" #include <functional>
/** /**
* \ingroup guiengine * \ingroup guiengine
@ -58,7 +59,6 @@ namespace GUIEngine
{ {
protected: protected:
static SCREEN* singleton; static SCREEN* singleton;
public: public:
~ScreenSingleton() ~ScreenSingleton()
@ -71,12 +71,14 @@ namespace GUIEngine
if (singleton == NULL) if (singleton == NULL)
{ {
singleton = new SCREEN(); singleton = new SCREEN();
std::function<SCREEN*()> new_screen_function = []()
{ return ScreenSingleton::getInstance(); };
singleton->setScreenPointerFunction(new_screen_function);
GUIEngine::addScreenToList(singleton); GUIEngine::addScreenToList(singleton);
} }
return singleton; return singleton;
} }
}; };
template <typename SCREEN> SCREEN* template <typename SCREEN> SCREEN*
ScreenSingleton<SCREEN>::singleton = nullptr; ScreenSingleton<SCREEN>::singleton = nullptr;
@ -118,6 +120,8 @@ namespace GUIEngine
*/ */
bool m_update_in_background; bool m_update_in_background;
/** For runtime screen reloading without template */
std::function<Screen*()> m_screen_func;
protected: protected:
bool m_throttle_FPS; bool m_throttle_FPS;
@ -137,6 +141,12 @@ namespace GUIEngine
PtrVector<Widget>& append_to, PtrVector<Widget>& append_to,
irr::gui::IGUIElement* parent = NULL); irr::gui::IGUIElement* parent = NULL);
/** Save the function before GUIEngine::clearScreenCache, call it after
* to get the new screen instance pointer
*/
std::function<Screen*()> getNewScreenPointer() const { return m_screen_func; }
void setScreenPointerFunction(const std::function<Screen*()>& f) { m_screen_func = f; }
Screen(bool pause_race=true); Screen(bool pause_race=true);

@ -334,6 +334,7 @@ namespace GUIEngine
~Skin(); ~Skin();
void resetBackgroundImage() { m_bg_image = NULL; }
static video::SColor getColor(const std::string &name); static video::SColor getColor(const std::string &name);
void renderSections(PtrVector<Widget>* within_vector=NULL); void renderSections(PtrVector<Widget>* within_vector=NULL);
void drawBgImage(); void drawBgImage();

@ -2152,6 +2152,8 @@ int main(int argc, char *argv[])
#ifndef SERVER_ONLY #ifndef SERVER_ONLY
if (!GUIEngine::isNoGraphics()) if (!GUIEngine::isNoGraphics())
{ {
// The screen size may change after loading
irr_driver->handleWindowResize();
// Some Android devices have only 320x240 and height >= 480 is bare // Some Android devices have only 320x240 and height >= 480 is bare
// minimum to make the GUI working as expected. // minimum to make the GUI working as expected.
if (irr_driver->getActualScreenSize().Height < 480) if (irr_driver->getActualScreenSize().Height < 480)