guiEngine.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. /*
  2. Minetest
  3. Copyright (C) 2013 sapier
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "guiEngine.h"
  17. #include <IGUIStaticText.h>
  18. #include <ICameraSceneNode.h>
  19. #include "client/renderingengine.h"
  20. #include "scripting_mainmenu.h"
  21. #include "config.h"
  22. #include "version.h"
  23. #include "porting.h"
  24. #include "filesys.h"
  25. #include "settings.h"
  26. #include "guiMainMenu.h"
  27. #include "sound.h"
  28. #include "httpfetch.h"
  29. #include "log.h"
  30. #include "client/fontengine.h"
  31. #include "client/guiscalingfilter.h"
  32. #include "irrlicht_changes/static_text.h"
  33. #include "client/tile.h"
  34. #include "content/content.h"
  35. #include "content/mods.h"
  36. #if USE_SOUND
  37. #include "client/sound/sound_openal.h"
  38. #endif
  39. /******************************************************************************/
  40. void TextDestGuiEngine::gotText(const StringMap &fields)
  41. {
  42. m_engine->getScriptIface()->handleMainMenuButtons(fields);
  43. }
  44. /******************************************************************************/
  45. void TextDestGuiEngine::gotText(const std::wstring &text)
  46. {
  47. m_engine->getScriptIface()->handleMainMenuEvent(wide_to_utf8(text));
  48. }
  49. /******************************************************************************/
  50. MenuTextureSource::~MenuTextureSource()
  51. {
  52. u32 before = m_driver->getTextureCount();
  53. for (const auto &it: m_to_delete) {
  54. m_driver->removeTexture(it);
  55. }
  56. m_to_delete.clear();
  57. infostream << "~MenuTextureSource() before cleanup: "<< before
  58. << " after: " << m_driver->getTextureCount() << std::endl;
  59. }
  60. /******************************************************************************/
  61. video::ITexture *MenuTextureSource::getTexture(const std::string &name, u32 *id)
  62. {
  63. if (id)
  64. *id = 0;
  65. if (name.empty())
  66. return NULL;
  67. // return if already loaded
  68. video::ITexture *retval = m_driver->findTexture(name.c_str());
  69. if (retval)
  70. return retval;
  71. video::IImage *image = m_driver->createImageFromFile(name.c_str());
  72. if (!image)
  73. return NULL;
  74. image = Align2Npot2(image, m_driver);
  75. retval = m_driver->addTexture(name.c_str(), image);
  76. image->drop();
  77. if (retval)
  78. m_to_delete.push_back(retval);
  79. return retval;
  80. }
  81. /******************************************************************************/
  82. /** MenuMusicFetcher */
  83. /******************************************************************************/
  84. void MenuMusicFetcher::addThePaths(const std::string &name,
  85. std::vector<std::string> &paths)
  86. {
  87. // Allow full paths
  88. if (name.find(DIR_DELIM_CHAR) != std::string::npos) {
  89. addAllAlternatives(name, paths);
  90. } else {
  91. addAllAlternatives(porting::path_share + DIR_DELIM + "sounds" + DIR_DELIM + name, paths);
  92. addAllAlternatives(porting::path_user + DIR_DELIM + "sounds" + DIR_DELIM + name, paths);
  93. }
  94. }
  95. /******************************************************************************/
  96. /** GUIEngine */
  97. /******************************************************************************/
  98. GUIEngine::GUIEngine(JoystickController *joystick,
  99. gui::IGUIElement *parent,
  100. RenderingEngine *rendering_engine,
  101. IMenuManager *menumgr,
  102. MainMenuData *data,
  103. bool &kill) :
  104. m_rendering_engine(rendering_engine),
  105. m_parent(parent),
  106. m_menumanager(menumgr),
  107. m_smgr(rendering_engine->get_scene_manager()),
  108. m_data(data),
  109. m_kill(kill)
  110. {
  111. // initialize texture pointers
  112. for (image_definition &texture : m_textures) {
  113. texture.texture = NULL;
  114. }
  115. // is deleted by guiformspec!
  116. auto buttonhandler = std::make_unique<TextDestGuiEngine>(this);
  117. m_buttonhandler = buttonhandler.get();
  118. // create texture source
  119. m_texture_source = std::make_unique<MenuTextureSource>(rendering_engine->get_video_driver());
  120. // create soundmanager
  121. #if USE_SOUND
  122. if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) {
  123. m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(),
  124. std::make_unique<MenuMusicFetcher>());
  125. }
  126. #endif
  127. if (!m_sound_manager)
  128. m_sound_manager = std::make_unique<DummySoundManager>();
  129. // create topleft header
  130. m_toplefttext = L"";
  131. core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(m_toplefttext.c_str()),
  132. g_fontengine->getTextHeight());
  133. rect += v2s32(4, 0);
  134. m_irr_toplefttext = gui::StaticText::add(rendering_engine->get_gui_env(),
  135. m_toplefttext, rect, false, true, 0, -1);
  136. // create formspecsource
  137. auto formspecgui = std::make_unique<FormspecFormSource>("");
  138. m_formspecgui = formspecgui.get();
  139. /* Create menu */
  140. m_menu = make_irr<GUIFormSpecMenu>(
  141. joystick,
  142. m_parent,
  143. -1,
  144. m_menumanager,
  145. nullptr /* &client */,
  146. m_rendering_engine->get_gui_env(),
  147. m_texture_source.get(),
  148. m_sound_manager.get(),
  149. formspecgui.release(),
  150. buttonhandler.release(),
  151. "",
  152. false);
  153. m_menu->allowClose(false);
  154. m_menu->lockSize(true,v2u32(800,600));
  155. // Initialize scripting
  156. infostream << "GUIEngine: Initializing Lua" << std::endl;
  157. m_script = std::make_unique<MainMenuScripting>(this);
  158. try {
  159. m_script->setMainMenuData(&m_data->script_data);
  160. m_data->script_data.errormessage.clear();
  161. if (!loadMainMenuScript()) {
  162. errorstream << "No future without main menu!" << std::endl;
  163. abort();
  164. }
  165. run();
  166. } catch (LuaError &e) {
  167. errorstream << "Main menu error: " << e.what() << std::endl;
  168. m_data->script_data.errormessage = e.what();
  169. }
  170. m_menu->quitMenu();
  171. m_menu.reset();
  172. }
  173. /******************************************************************************/
  174. std::string findLocaleFileInMods(const std::string &path, const std::string &filename)
  175. {
  176. std::vector<ModSpec> mods = flattenMods(getModsInPath(path, "root", true));
  177. for (const auto &mod : mods) {
  178. std::string ret = mod.path + DIR_DELIM "locale" DIR_DELIM + filename;
  179. if (fs::PathExists(ret)) {
  180. return ret;
  181. }
  182. }
  183. return "";
  184. }
  185. /******************************************************************************/
  186. Translations *GUIEngine::getContentTranslations(const std::string &path,
  187. const std::string &domain, const std::string &lang_code)
  188. {
  189. if (domain.empty() || lang_code.empty())
  190. return nullptr;
  191. std::string filename = domain + "." + lang_code + ".tr";
  192. std::string key = path + DIR_DELIM "locale" DIR_DELIM + filename;
  193. if (key == m_last_translations_key)
  194. return &m_last_translations;
  195. std::string trans_path = key;
  196. ContentType type = getContentType(path);
  197. if (type == ContentType::GAME)
  198. trans_path = findLocaleFileInMods(path + DIR_DELIM "mods" DIR_DELIM, filename);
  199. else if (type == ContentType::MODPACK)
  200. trans_path = findLocaleFileInMods(path, filename);
  201. // We don't need to search for locale files in a mod, as there's only one `locale` folder.
  202. if (trans_path.empty())
  203. return nullptr;
  204. m_last_translations_key = key;
  205. m_last_translations = {};
  206. std::string data;
  207. if (fs::ReadFile(trans_path, data)) {
  208. m_last_translations.loadTranslation(data);
  209. }
  210. return &m_last_translations;
  211. }
  212. /******************************************************************************/
  213. bool GUIEngine::loadMainMenuScript()
  214. {
  215. // Set main menu path (for core.get_mainmenu_path())
  216. m_scriptdir = g_settings->get("main_menu_path");
  217. if (m_scriptdir.empty()) {
  218. m_scriptdir = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM + "mainmenu";
  219. }
  220. // Load builtin (which will load the main menu script)
  221. std::string script = porting::path_share + DIR_DELIM "builtin" + DIR_DELIM "init.lua";
  222. try {
  223. m_script->loadScript(script);
  224. m_script->checkSetByBuiltin();
  225. // Menu script loaded
  226. return true;
  227. } catch (const ModError &e) {
  228. errorstream << "GUIEngine: execution of menu script failed: "
  229. << e.what() << std::endl;
  230. }
  231. return false;
  232. }
  233. /******************************************************************************/
  234. void GUIEngine::run()
  235. {
  236. IrrlichtDevice *device = m_rendering_engine->get_raw_device();
  237. // Always create clouds because they may or may not be
  238. // needed based on the game selected
  239. video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
  240. cloudInit();
  241. unsigned int text_height = g_fontengine->getTextHeight();
  242. // Reset fog color
  243. {
  244. video::SColor fog_color;
  245. video::E_FOG_TYPE fog_type = video::EFT_FOG_LINEAR;
  246. f32 fog_start = 0;
  247. f32 fog_end = 0;
  248. f32 fog_density = 0;
  249. bool fog_pixelfog = false;
  250. bool fog_rangefog = false;
  251. driver->getFog(fog_color, fog_type, fog_start, fog_end, fog_density,
  252. fog_pixelfog, fog_rangefog);
  253. driver->setFog(RenderingEngine::MENU_SKY_COLOR, fog_type, fog_start,
  254. fog_end, fog_density, fog_pixelfog, fog_rangefog);
  255. }
  256. const irr::core::dimension2d<u32> initial_screen_size(
  257. g_settings->getU16("screen_w"),
  258. g_settings->getU16("screen_h")
  259. );
  260. const bool initial_window_maximized = g_settings->getBool("window_maximized");
  261. u64 t_last_frame = porting::getTimeUs();
  262. f32 dtime = 0.0f;
  263. while (m_rendering_engine->run() && (!m_startgame) && (!m_kill)) {
  264. if (device->isWindowVisible()) {
  265. // check if we need to update the "upper left corner"-text
  266. if (text_height != g_fontengine->getTextHeight()) {
  267. updateTopLeftTextSize();
  268. text_height = g_fontengine->getTextHeight();
  269. }
  270. driver->beginScene(true, true, RenderingEngine::MENU_SKY_COLOR);
  271. if (m_clouds_enabled)
  272. {
  273. cloudPreProcess();
  274. drawOverlay(driver);
  275. }
  276. else
  277. drawBackground(driver);
  278. drawFooter(driver);
  279. m_rendering_engine->get_gui_env()->drawAll();
  280. // The header *must* be drawn after the menu because it uses
  281. // GUIFormspecMenu::getAbsoluteRect().
  282. // The header *can* be drawn after the menu because it never intersects
  283. // the menu.
  284. drawHeader(driver);
  285. driver->endScene();
  286. }
  287. u32 frametime_min = 1000 / (device->isWindowFocused()
  288. ? g_settings->getFloat("fps_max")
  289. : g_settings->getFloat("fps_max_unfocused"));
  290. if (m_clouds_enabled)
  291. cloudPostProcess(frametime_min, device);
  292. else
  293. sleep_ms(frametime_min);
  294. u64 t_now = porting::getTimeUs();
  295. dtime = static_cast<f32>(t_now - t_last_frame) * 1.0e-6f;
  296. t_last_frame = t_now;
  297. m_script->step();
  298. sound_volume_control(m_sound_manager.get(), device->isWindowActive());
  299. m_sound_manager->step(dtime);
  300. #ifdef __ANDROID__
  301. m_menu->getAndroidUIInput();
  302. #endif
  303. }
  304. RenderingEngine::autosaveScreensizeAndCo(initial_screen_size, initial_window_maximized);
  305. }
  306. /******************************************************************************/
  307. GUIEngine::~GUIEngine()
  308. {
  309. // deinitialize script first. gc destructors might depend on other stuff
  310. infostream << "GUIEngine: Deinitializing scripting" << std::endl;
  311. m_script.reset();
  312. m_sound_manager.reset();
  313. m_irr_toplefttext->setText(L"");
  314. //clean up texture pointers
  315. for (image_definition &texture : m_textures) {
  316. if (texture.texture)
  317. m_rendering_engine->get_video_driver()->removeTexture(texture.texture);
  318. }
  319. m_texture_source.reset();
  320. m_cloud.clouds.reset();
  321. }
  322. /******************************************************************************/
  323. void GUIEngine::cloudInit()
  324. {
  325. m_cloud.clouds = make_irr<Clouds>(m_smgr, -1, rand());
  326. m_cloud.clouds->setHeight(100.0f);
  327. m_cloud.clouds->update(v3f(0, 0, 0), video::SColor(255,240,240,255));
  328. m_cloud.camera = m_smgr->addCameraSceneNode(0,
  329. v3f(0,0,0), v3f(0, 60, 100));
  330. m_cloud.camera->setFarValue(10000);
  331. m_cloud.lasttime = m_rendering_engine->get_timer_time();
  332. }
  333. /******************************************************************************/
  334. void GUIEngine::cloudPreProcess()
  335. {
  336. u32 time = m_rendering_engine->get_timer_time();
  337. if(time > m_cloud.lasttime)
  338. m_cloud.dtime = (time - m_cloud.lasttime) / 1000.0;
  339. else
  340. m_cloud.dtime = 0;
  341. m_cloud.lasttime = time;
  342. m_cloud.clouds->step(m_cloud.dtime*3);
  343. m_cloud.clouds->render();
  344. m_smgr->drawAll();
  345. }
  346. /******************************************************************************/
  347. void GUIEngine::cloudPostProcess(u32 frametime_min, IrrlichtDevice *device)
  348. {
  349. // Time of frame without fps limit
  350. u32 busytime_u32;
  351. // not using getRealTime is necessary for wine
  352. u32 time = m_rendering_engine->get_timer_time();
  353. if(time > m_cloud.lasttime)
  354. busytime_u32 = time - m_cloud.lasttime;
  355. else
  356. busytime_u32 = 0;
  357. // FPS limit
  358. if (busytime_u32 < frametime_min) {
  359. u32 sleeptime = frametime_min - busytime_u32;
  360. device->sleep(sleeptime);
  361. }
  362. }
  363. /******************************************************************************/
  364. void GUIEngine::setFormspecPrepend(const std::string &fs)
  365. {
  366. if (m_menu) {
  367. m_menu->setFormspecPrepend(fs);
  368. }
  369. }
  370. /******************************************************************************/
  371. void GUIEngine::drawBackground(video::IVideoDriver *driver)
  372. {
  373. v2u32 screensize = driver->getScreenSize();
  374. video::ITexture* texture = m_textures[TEX_LAYER_BACKGROUND].texture;
  375. /* If no texture, draw background of solid color */
  376. if(!texture){
  377. video::SColor color(255,80,58,37);
  378. core::rect<s32> rect(0, 0, screensize.X, screensize.Y);
  379. driver->draw2DRectangle(color, rect, NULL);
  380. return;
  381. }
  382. v2u32 sourcesize = texture->getOriginalSize();
  383. if (m_textures[TEX_LAYER_BACKGROUND].tile)
  384. {
  385. v2u32 tilesize(
  386. MYMAX(sourcesize.X,m_textures[TEX_LAYER_BACKGROUND].minsize),
  387. MYMAX(sourcesize.Y,m_textures[TEX_LAYER_BACKGROUND].minsize));
  388. for (unsigned int x = 0; x < screensize.X; x += tilesize.X )
  389. {
  390. for (unsigned int y = 0; y < screensize.Y; y += tilesize.Y )
  391. {
  392. draw2DImageFilterScaled(driver, texture,
  393. core::rect<s32>(x, y, x+tilesize.X, y+tilesize.Y),
  394. core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
  395. NULL, NULL, true);
  396. }
  397. }
  398. return;
  399. }
  400. // Chop background image to the smaller screen dimension
  401. v2u32 bg_size = screensize;
  402. v2f32 scale(
  403. (f32) bg_size.X / sourcesize.X,
  404. (f32) bg_size.Y / sourcesize.Y);
  405. if (scale.X < scale.Y)
  406. bg_size.X = (int) (scale.Y * sourcesize.X);
  407. else
  408. bg_size.Y = (int) (scale.X * sourcesize.Y);
  409. v2s32 offset = v2s32(
  410. (s32) screensize.X - (s32) bg_size.X,
  411. (s32) screensize.Y - (s32) bg_size.Y
  412. ) / 2;
  413. /* Draw background texture */
  414. draw2DImageFilterScaled(driver, texture,
  415. core::rect<s32>(offset.X, offset.Y, bg_size.X + offset.X, bg_size.Y + offset.Y),
  416. core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
  417. NULL, NULL, true);
  418. }
  419. /******************************************************************************/
  420. void GUIEngine::drawOverlay(video::IVideoDriver *driver)
  421. {
  422. v2u32 screensize = driver->getScreenSize();
  423. video::ITexture* texture = m_textures[TEX_LAYER_OVERLAY].texture;
  424. /* If no texture, draw nothing */
  425. if(!texture)
  426. return;
  427. /* Draw background texture */
  428. v2u32 sourcesize = texture->getOriginalSize();
  429. draw2DImageFilterScaled(driver, texture,
  430. core::rect<s32>(0, 0, screensize.X, screensize.Y),
  431. core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
  432. NULL, NULL, true);
  433. }
  434. /******************************************************************************/
  435. void GUIEngine::drawHeader(video::IVideoDriver *driver)
  436. {
  437. core::dimension2d<u32> screensize = driver->getScreenSize();
  438. video::ITexture* texture = m_textures[TEX_LAYER_HEADER].texture;
  439. // If no texture, draw nothing
  440. if (!texture)
  441. return;
  442. /*
  443. * Calculate the maximum rectangle
  444. */
  445. core::rect<s32> formspec_rect = m_menu->getAbsoluteRect();
  446. // 4 px of padding on each side
  447. core::rect<s32> max_rect(4, 4, screensize.Width - 8, formspec_rect.UpperLeftCorner.Y - 8);
  448. // If no space (less than 16x16 px), draw nothing
  449. if (max_rect.getWidth() < 16 || max_rect.getHeight() < 16)
  450. return;
  451. /*
  452. * Calculate the preferred rectangle
  453. */
  454. f32 mult = (((f32)screensize.Width / 2.0)) /
  455. ((f32)texture->getOriginalSize().Width);
  456. v2s32 splashsize(((f32)texture->getOriginalSize().Width) * mult,
  457. ((f32)texture->getOriginalSize().Height) * mult);
  458. s32 free_space = (((s32)screensize.Height)-320)/2;
  459. core::rect<s32> desired_rect(0, 0, splashsize.X, splashsize.Y);
  460. desired_rect += v2s32((screensize.Width/2)-(splashsize.X/2),
  461. ((free_space/2)-splashsize.Y/2)+10);
  462. /*
  463. * Make the preferred rectangle fit into the maximum rectangle
  464. */
  465. // 1. Scale
  466. f32 scale = std::min((f32)max_rect.getWidth() / (f32)desired_rect.getWidth(),
  467. (f32)max_rect.getHeight() / (f32)desired_rect.getHeight());
  468. if (scale < 1.0f) {
  469. v2s32 old_center = desired_rect.getCenter();
  470. desired_rect.LowerRightCorner.X = desired_rect.UpperLeftCorner.X + desired_rect.getWidth() * scale;
  471. desired_rect.LowerRightCorner.Y = desired_rect.UpperLeftCorner.Y + desired_rect.getHeight() * scale;
  472. desired_rect += old_center - desired_rect.getCenter();
  473. }
  474. // 2. Move
  475. desired_rect.constrainTo(max_rect);
  476. draw2DImageFilterScaled(driver, texture, desired_rect,
  477. core::rect<s32>(core::position2d<s32>(0,0),
  478. core::dimension2di(texture->getOriginalSize())),
  479. NULL, NULL, true);
  480. }
  481. /******************************************************************************/
  482. void GUIEngine::drawFooter(video::IVideoDriver *driver)
  483. {
  484. core::dimension2d<u32> screensize = driver->getScreenSize();
  485. video::ITexture* texture = m_textures[TEX_LAYER_FOOTER].texture;
  486. /* If no texture, draw nothing */
  487. if(!texture)
  488. return;
  489. f32 mult = (((f32)screensize.Width)) /
  490. ((f32)texture->getOriginalSize().Width);
  491. v2s32 footersize(((f32)texture->getOriginalSize().Width) * mult,
  492. ((f32)texture->getOriginalSize().Height) * mult);
  493. // Don't draw the footer if there isn't enough room
  494. s32 free_space = (((s32)screensize.Height)-320)/2;
  495. if (free_space > footersize.Y) {
  496. core::rect<s32> rect(0,0,footersize.X,footersize.Y);
  497. rect += v2s32(screensize.Width/2,screensize.Height-footersize.Y);
  498. rect -= v2s32(footersize.X/2, 0);
  499. draw2DImageFilterScaled(driver, texture, rect,
  500. core::rect<s32>(core::position2d<s32>(0,0),
  501. core::dimension2di(texture->getOriginalSize())),
  502. NULL, NULL, true);
  503. }
  504. }
  505. /******************************************************************************/
  506. bool GUIEngine::setTexture(texture_layer layer, const std::string &texturepath,
  507. bool tile_image, unsigned int minsize)
  508. {
  509. video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
  510. if (m_textures[layer].texture) {
  511. driver->removeTexture(m_textures[layer].texture);
  512. m_textures[layer].texture = NULL;
  513. }
  514. if (texturepath.empty() || !fs::PathExists(texturepath)) {
  515. return false;
  516. }
  517. m_textures[layer].texture = driver->getTexture(texturepath.c_str());
  518. m_textures[layer].tile = tile_image;
  519. m_textures[layer].minsize = minsize;
  520. if (!m_textures[layer].texture) {
  521. return false;
  522. }
  523. return true;
  524. }
  525. /******************************************************************************/
  526. bool GUIEngine::downloadFile(const std::string &url, const std::string &target)
  527. {
  528. #if USE_CURL
  529. std::ofstream target_file(target.c_str(), std::ios::out | std::ios::binary);
  530. if (!target_file.good()) {
  531. return false;
  532. }
  533. HTTPFetchRequest fetch_request;
  534. HTTPFetchResult fetch_result;
  535. fetch_request.url = url;
  536. fetch_request.caller = HTTPFETCH_SYNC;
  537. fetch_request.timeout = std::max(MIN_HTTPFETCH_TIMEOUT,
  538. (long)g_settings->getS32("curl_file_download_timeout"));
  539. httpfetch_sync(fetch_request, fetch_result);
  540. if (!fetch_result.succeeded) {
  541. target_file.close();
  542. fs::DeleteSingleFileOrEmptyDirectory(target);
  543. return false;
  544. }
  545. target_file << fetch_result.data;
  546. return true;
  547. #else
  548. return false;
  549. #endif
  550. }
  551. /******************************************************************************/
  552. void GUIEngine::setTopleftText(const std::string &text)
  553. {
  554. m_toplefttext = translate_string(utf8_to_wide(text));
  555. updateTopLeftTextSize();
  556. }
  557. /******************************************************************************/
  558. void GUIEngine::updateTopLeftTextSize()
  559. {
  560. core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(m_toplefttext.c_str()),
  561. g_fontengine->getTextHeight());
  562. rect += v2s32(4, 0);
  563. m_irr_toplefttext->remove();
  564. m_irr_toplefttext = gui::StaticText::add(m_rendering_engine->get_gui_env(),
  565. m_toplefttext, rect, false, true, 0, -1);
  566. }